diff options
16 files changed, 15929 insertions, 19580 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/10-mtdpart-redboot-fis-byteswap.patch b/packages/linux/ixp4xx-kernel/2.6.16/10-mtdpart-redboot-fis-byteswap.patch deleted file mode 100644 index 3fa0535abf..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/10-mtdpart-redboot-fis-byteswap.patch +++ /dev/null @@ -1,70 +0,0 @@ -drivers/mtd/redboot.c: recognise a foreign byte sex partition table - -The RedBoot boot loader writes flash partition tables containing native -byte sex 32 bit values. When booting an opposite byte sex kernel (e.g. an -LE kernel from BE RedBoot) the current MTD driver fails to handle the -partition table and therefore is unable to generate the correct partition -map for the flash. - -The patch recognises that the FIS directory (the partition table) is -byte-reversed by examining the partition table size, which is known to be -one erase block (this is an assumption made elsewhere in redboot.c). If -the size matches the erase block after byte swapping the value then -byte-reversal is assumed, if not no further action is taken. The patched -code is fail safe; should redboot.c be changed to support a partition table -with a modified size field the test will fail and the partition table will -be assumed to have the host byte sex. - -If byte-reversal is detected the patch byte swaps the remainder of the 32 -bit fields in the copy of the table; this copy is then used to set up the -MTD partition map. - -Signed-off-by: John Bowler <jbowler@acm.org> -Signed-off-by: Andrew Morton <akpm@osdl.org> -Modified slightly and -Signed-off-by: David Woodhouse <dwmw2@infradead.org> - -Index: drivers/mtd/redboot.c -=================================================================== -RCS file: /home/cvs/mtd/drivers/mtd/redboot.c,v -retrieving revision 1.18 -retrieving revision 1.19 -diff -u -p -r1.18 -r1.19 ---- linux-2.6.15/drivers/mtd/redboot.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.15/drivers/mtd/redboot.c 1970-01-01 00:00:00.000000000 +0000 -@@ -89,8 +89,32 @@ static int parse_redboot_partitions(stru - i = numslots; - break; - } -- if (!memcmp(buf[i].name, "FIS directory", 14)) -+ if (!memcmp(buf[i].name, "FIS directory", 14)) { -+ /* This is apparently the FIS directory entry for the -+ * FIS directory itself. The FIS directory size is -+ * one erase block; if the buf[i].size field is -+ * swab32(erasesize) then we know we are looking at -+ * a byte swapped FIS directory - swap all the entries! -+ * (NOTE: this is 'size' not 'data_length'; size is -+ * the full size of the entry.) -+ */ -+ if (swab32(buf[i].size) == master->erasesize) { -+ int j; -+ for (j = 0; j < numslots && buf[j].name[0] != 0xff; ++j) { -+ /* The unsigned long fields were written with the -+ * wrong byte sex, name and pad have no byte sex. -+ */ -+ swab32s(&buf[j].flash_base); -+ swab32s(&buf[j].mem_base); -+ swab32s(&buf[j].size); -+ swab32s(&buf[j].entry_point); -+ swab32s(&buf[j].data_length); -+ swab32s(&buf[j].desc_cksum); -+ swab32s(&buf[j].file_cksum); -+ } -+ } - break; -+ } - } - if (i == numslots) { - /* Didn't find it */ - - diff --git a/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch b/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch index 3cc84b2a9b..044bd3abc1 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch +++ b/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch @@ -1,6 +1,365 @@ ---- linux-rtc.orig/include/linux/rtc.h 2006-02-19 23:33:10.000000000 +0100 -+++ linux-rtc/include/linux/rtc.h 2006-02-19 23:33:15.000000000 +0100 -@@ -93,8 +93,97 @@ struct rtc_pll_info { +--- + CREDITS | 5 + MAINTAINERS | 6 + arch/arm/Kconfig | 3 + arch/arm/common/rtctime.c | 108 -- + arch/arm/mach-integrator/time.c | 16 + arch/arm/mach-pxa/generic.c | 6 + arch/arm/mach-sa1100/generic.c | 6 + arch/mips/ddb5xxx/common/rtc_ds1386.c | 4 + arch/mips/dec/time.c | 4 + arch/mips/ite-boards/generic/time.c | 4 + arch/mips/jmr3927/common/rtc_ds1742.c | 4 + arch/mips/kernel/time.c | 22 + arch/mips/lasat/setup.c | 4 + arch/mips/mips-boards/atlas/atlas_setup.c | 2 + arch/mips/mips-boards/malta/malta_setup.c | 2 + arch/mips/momentum/jaguar_atx/setup.c | 4 + arch/mips/momentum/ocelot_3/setup.c | 4 + arch/mips/momentum/ocelot_c/setup.c | 4 + arch/mips/pmc-sierra/yosemite/setup.c | 4 + arch/mips/sgi-ip22/ip22-time.c | 4 + arch/mips/sgi-ip32/ip32-setup.c | 4 + arch/mips/sibyte/swarm/setup.c | 8 + arch/mips/sni/setup.c | 4 + arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 4 + arch/mips/tx4938/common/rtc_rx5c348.c | 4 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/char/Kconfig | 2 + drivers/i2c/chips/Kconfig | 18 + drivers/i2c/chips/Makefile | 2 + drivers/i2c/chips/rtc8564.c | 385 ------- + drivers/i2c/chips/rtc8564.h | 78 - + drivers/i2c/chips/x1205.c | 698 ------------- + drivers/rtc/Kconfig | 156 ++ + drivers/rtc/Makefile | 20 + drivers/rtc/class.c | 145 ++ + drivers/rtc/hctosys.c | 69 + + drivers/rtc/interface.c | 277 +++++ + drivers/rtc/rtc-dev.c | 382 +++++++ + drivers/rtc/rtc-ds1672.c | 233 ++++ + drivers/rtc/rtc-ep93xx.c | 163 +++ + drivers/rtc/rtc-lib.c | 99 + + drivers/rtc/rtc-pcf8563.c | 355 ++++++ + drivers/rtc/rtc-proc.c | 162 +++ + drivers/rtc/rtc-rs5c372.c | 295 +++++ + drivers/rtc/rtc-sa1100.c | 392 +++++++ + drivers/rtc/rtc-sysfs.c | 124 ++ + drivers/rtc/rtc-test.c | 205 +++ + drivers/rtc/rtc-x1205.c | 619 +++++++++++ + include/asm-arm/rtc.h | 3 + include/asm-mips/time.h | 12 + include/linux/rtc.h | 92 + + include/linux/x1205.h | 31 + 53 files changed, 3888 insertions(+), 1372 deletions(-) + +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/rtc/rtc-lib.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,99 @@ ++/* ++ * rtc and date/time utility functions ++ * ++ * Copyright (C) 2005-06 Tower Technologies ++ * Author: Alessandro Zummo <a.zummo@towertech.it> ++ * ++ * based on arch/arm/common/rtctime.c and other bits ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++*/ ++ ++#include <linux/module.h> ++#include <linux/rtc.h> ++ ++static const unsigned char rtc_days_in_month[] = { ++ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ++}; ++ ++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) ++#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) ++ ++int rtc_month_days(unsigned int month, unsigned int year) ++{ ++ return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); ++} ++EXPORT_SYMBOL(rtc_month_days); ++ ++/* ++ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. ++ */ ++void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) ++{ ++ register int days, month, year; ++ ++ days = time / 86400; ++ time -= days * 86400; ++ ++ /* day of the week, 1970-01-01 was a Thursday */ ++ tm->tm_wday = (days + 4) % 7; ++ ++ year = 1970 + days / 365; ++ days -= (year - 1970) * 365 ++ + LEAPS_THRU_END_OF(year - 1) ++ - LEAPS_THRU_END_OF(1970 - 1); ++ if (days < 0) { ++ year -= 1; ++ days += 365 + LEAP_YEAR(year); ++ } ++ tm->tm_year = year - 1900; ++ tm->tm_yday = days + 1; ++ ++ for (month = 0; month < 11; month++) { ++ int newdays; ++ ++ newdays = days - rtc_month_days(month, year); ++ if (newdays < 0) ++ break; ++ days = newdays; ++ } ++ tm->tm_mon = month; ++ tm->tm_mday = days + 1; ++ ++ tm->tm_hour = time / 3600; ++ time -= tm->tm_hour * 3600; ++ tm->tm_min = time / 60; ++ tm->tm_sec = time - tm->tm_min * 60; ++} ++EXPORT_SYMBOL(rtc_time_to_tm); ++ ++/* ++ * Does the rtc_time represent a valid date/time? ++ */ ++int rtc_valid_tm(struct rtc_time *tm) ++{ ++ if (tm->tm_year < 70 ++ || tm->tm_mon >= 12 ++ || tm->tm_mday < 1 ++ || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) ++ || tm->tm_hour >= 24 ++ || tm->tm_min >= 60 ++ || tm->tm_sec >= 60) ++ return -EINVAL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(rtc_valid_tm); ++ ++/* ++ * Convert Gregorian date to seconds since 01-01-1970 00:00:00. ++ */ ++int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) ++{ ++ *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_hour, tm->tm_min, tm->tm_sec); ++ return 0; ++} ++EXPORT_SYMBOL(rtc_tm_to_time); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/rtc/Makefile 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,20 @@ ++# ++# Makefile for RTC class/drivers. ++# ++ ++obj-$(CONFIG_RTC_LIB) += rtc-lib.o ++obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o ++obj-$(CONFIG_RTC_CLASS) += rtc-core.o ++rtc-core-y := class.o interface.o ++ ++obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o ++obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o ++obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o ++ ++obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o ++obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o ++obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o ++obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o ++obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o ++obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o ++obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/rtc/Kconfig 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,156 @@ ++\# ++# RTC class/drivers configuration ++# ++ ++menu "Real Time Clock" ++ ++config RTC_LIB ++ bool ++ ++config RTC_CLASS ++ tristate "RTC class" ++ depends on EXPERIMENTAL ++ default n ++ select RTC_LIB ++ help ++ Generic RTC class support. If you say yes here, you will ++ be allowed to plug one or more RTCs to your system. You will ++ probably want to enable one of more of the interfaces below. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-class. ++ ++config RTC_HCTOSYS ++ bool "Set system time from RTC on startup" ++ depends on RTC_CLASS = y ++ default y ++ help ++ If you say yes here, the system time will be set using ++ the value read from the specified RTC device. This is useful ++ in order to avoid unnecessary fschk runs. ++ ++config RTC_HCTOSYS_DEVICE ++ string "The RTC to read the time from" ++ depends on RTC_HCTOSYS = y ++ default "rtc0" ++ help ++ The RTC device that will be used as the source for ++ the system time, usually rtc0. ++ ++comment "RTC interfaces" ++ depends on RTC_CLASS ++ ++config RTC_INTF_SYSFS ++ tristate "sysfs" ++ depends on RTC_CLASS && SYSFS ++ default RTC_CLASS ++ help ++ Say yes here if you want to use your RTC using the sysfs ++ interface, /sys/class/rtc/rtcX . ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-sysfs. ++ ++config RTC_INTF_PROC ++ tristate "proc" ++ depends on RTC_CLASS && PROC_FS ++ default RTC_CLASS ++ help ++ Say yes here if you want to use your RTC using the proc ++ interface, /proc/driver/rtc . ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-proc. ++ ++config RTC_INTF_DEV ++ tristate "dev" ++ depends on RTC_CLASS ++ default RTC_CLASS ++ help ++ Say yes here if you want to use your RTC using the dev ++ interface, /dev/rtc . ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-dev. ++ ++comment "RTC drivers" ++ depends on RTC_CLASS ++ ++config RTC_DRV_X1205 ++ tristate "Xicor/Intersil X1205 RTC chip" ++ depends on RTC_CLASS && I2C ++ help ++ If you say yes here you get support for the ++ Xicor/Intersil X1205 RTC chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-x1205. ++ ++config RTC_DRV_DS1672 ++ tristate "Dallas/Maxim DS1672" ++ depends on RTC_CLASS && I2C ++ help ++ If you say yes here you get support for the ++ Dallas/Maxim DS1672 timekeeping chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-ds1672. ++ ++config RTC_DRV_PCF8563 ++ tristate "Philips PCF8563/Epson RTC8564" ++ depends on RTC_CLASS && I2C ++ help ++ If you say yes here you get support for the ++ Philips PCF8563 RTC chip. The Epson RTC8564 ++ should work as well. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-pcf8563. ++ ++config RTC_DRV_RS5C372 ++ tristate "Ricoh RS5C372A/B" ++ depends on RTC_CLASS && I2C ++ help ++ If you say yes here you get support for the ++ Ricoh RS5C372A and RS5C372B RTC chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-rs5c372. ++ ++config RTC_DRV_EP93XX ++ tristate "Cirrus Logic EP93XX" ++ depends on RTC_CLASS && ARCH_EP93XX ++ help ++ If you say yes here you get support for the ++ RTC embedded in the Cirrus Logic EP93XX processors. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-ep93xx. ++ ++ ++config RTC_DRV_SA1100 ++ bool "SA11x0/PXA2xx RTC support" ++ depends on ARCH_SA1100 || ARCH_PXA ++ help ++ If you say Y here you will get access to the real time clock ++ built into your SA11x0 or PXA2xx CPU. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rtc-sa1100. ++ ++config RTC_DRV_TEST ++ tristate "Test driver/device" ++ depends on RTC_CLASS ++ help ++ If you say yes here you get support for the ++ RTC test driver. It's a software RTC which can be ++ used to test the RTC subsystem APIs. It gets ++ the time from the system clock. ++ You want this driver only if you are doing development ++ on the RTC subsystem. Please read the source code ++ for further details. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-test. ++ ++endmenu +--- linux-ixp4xx.orig/drivers/Kconfig 2006-03-08 01:59:18.000000000 +0100 ++++ linux-ixp4xx/drivers/Kconfig 2006-03-08 01:59:26.000000000 +0100 +@@ -72,4 +72,6 @@ source "drivers/sn/Kconfig" + + source "drivers/edac/Kconfig" + ++source "drivers/rtc/Kconfig" ++ + endmenu +--- linux-ixp4xx.orig/drivers/Makefile 2006-03-08 01:59:18.000000000 +0100 ++++ linux-ixp4xx/drivers/Makefile 2006-03-08 01:59:26.000000000 +0100 +@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/ + obj-$(CONFIG_GAMEPORT) += input/gameport/ + obj-$(CONFIG_INPUT) += input/ + obj-$(CONFIG_I2O) += message/ ++obj-$(CONFIG_RTC_LIB) += rtc/ + obj-$(CONFIG_I2C) += i2c/ + obj-$(CONFIG_W1) += w1/ + obj-$(CONFIG_HWMON) += hwmon/ +--- linux-ixp4xx.orig/include/linux/rtc.h 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/include/linux/rtc.h 2006-03-08 01:59:26.000000000 +0100 +@@ -93,8 +93,100 @@ struct rtc_pll_info { #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ @@ -12,12 +371,19 @@ + #ifdef __KERNEL__ ++extern int rtc_month_days(unsigned int month, unsigned int year); ++extern int rtc_valid_tm(struct rtc_time *tm); ++extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); ++extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); ++ +#include <linux/device.h> +#include <linux/seq_file.h> +#include <linux/cdev.h> +#include <linux/poll.h> +#include <linux/mutex.h> + ++extern struct class *rtc_class; ++ +struct rtc_class_ops { + int (*open)(struct device *); + void (*release)(struct device *); @@ -47,6 +413,7 @@ + struct rtc_class_ops *ops; + struct mutex ops_lock; + ++ struct class_device *rtc_dev; + struct cdev char_dev; + struct mutex char_lock; + @@ -68,11 +435,6 @@ +extern void rtc_device_unregister(struct rtc_device *rdev); +extern int rtc_interface_register(struct class_interface *intf); + -+extern int rtc_month_days(unsigned int month, unsigned int year); -+extern int rtc_valid_tm(struct rtc_time *tm); -+extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); -+extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); -+ +extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm); +extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm); +extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs); @@ -98,28 +460,609 @@ typedef struct rtc_task { void (*func)(void *private_data); void *private_data; ---- linux-rtc.orig/drivers/Kconfig 2006-02-19 23:33:10.000000000 +0100 -+++ linux-rtc/drivers/Kconfig 2006-02-19 23:33:15.000000000 +0100 -@@ -70,4 +70,6 @@ source "drivers/sn/Kconfig" +--- linux-ixp4xx.orig/arch/arm/common/rtctime.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/arm/common/rtctime.c 2006-03-08 01:59:26.000000000 +0100 +@@ -20,6 +20,7 @@ + #include <linux/capability.h> + #include <linux/device.h> + #include <linux/mutex.h> ++#include <linux/rtc.h> - source "drivers/edac/Kconfig" + #include <asm/rtc.h> + #include <asm/semaphore.h> +@@ -42,89 +43,6 @@ static struct rtc_ops *rtc_ops; + + #define rtc_epoch 1900UL + +-static const unsigned char days_in_month[] = { +- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +-}; +- +-#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) +-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) +- +-static int month_days(unsigned int month, unsigned int year) +-{ +- return days_in_month[month] + (LEAP_YEAR(year) && month == 1); +-} +- +-/* +- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. +- */ +-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) +-{ +- int days, month, year; +- +- days = time / 86400; +- time -= days * 86400; +- +- tm->tm_wday = (days + 4) % 7; +- +- year = 1970 + days / 365; +- days -= (year - 1970) * 365 +- + LEAPS_THRU_END_OF(year - 1) +- - LEAPS_THRU_END_OF(1970 - 1); +- if (days < 0) { +- year -= 1; +- days += 365 + LEAP_YEAR(year); +- } +- tm->tm_year = year - 1900; +- tm->tm_yday = days + 1; +- +- for (month = 0; month < 11; month++) { +- int newdays; +- +- newdays = days - month_days(month, year); +- if (newdays < 0) +- break; +- days = newdays; +- } +- tm->tm_mon = month; +- tm->tm_mday = days + 1; +- +- tm->tm_hour = time / 3600; +- time -= tm->tm_hour * 3600; +- tm->tm_min = time / 60; +- tm->tm_sec = time - tm->tm_min * 60; +-} +-EXPORT_SYMBOL(rtc_time_to_tm); +- +-/* +- * Does the rtc_time represent a valid date/time? +- */ +-int rtc_valid_tm(struct rtc_time *tm) +-{ +- if (tm->tm_year < 70 || +- tm->tm_mon >= 12 || +- tm->tm_mday < 1 || +- tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) || +- tm->tm_hour >= 24 || +- tm->tm_min >= 60 || +- tm->tm_sec >= 60) +- return -EINVAL; +- +- return 0; +-} +-EXPORT_SYMBOL(rtc_valid_tm); +- +-/* +- * Convert Gregorian date to seconds since 01-01-1970 00:00:00. +- */ +-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) +-{ +- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, +- tm->tm_hour, tm->tm_min, tm->tm_sec); +- +- return 0; +-} +-EXPORT_SYMBOL(rtc_tm_to_time); +- + /* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. +@@ -151,13 +69,13 @@ void rtc_next_alarm_time(struct rtc_time + } + } + +-static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) ++static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm) + { + memset(tm, 0, sizeof(struct rtc_time)); + return ops->read_time(tm); + } + +-static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) ++static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm) + { + int ret; + +@@ -168,7 +86,7 @@ static inline int rtc_set_time(struct rt + return ret; + } + +-static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) ++static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) + { + int ret = -EINVAL; + if (ops->read_alarm) { +@@ -178,7 +96,7 @@ static inline int rtc_read_alarm(struct + return ret; + } + +-static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) ++static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) + { + int ret = -EINVAL; + if (ops->set_alarm) +@@ -266,7 +184,7 @@ static int rtc_ioctl(struct inode *inode + + switch (cmd) { + case RTC_ALM_READ: +- ret = rtc_read_alarm(ops, &alrm); ++ ret = rtc_arm_read_alarm(ops, &alrm); + if (ret) + break; + ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); +@@ -288,11 +206,11 @@ static int rtc_ioctl(struct inode *inode + alrm.time.tm_wday = -1; + alrm.time.tm_yday = -1; + alrm.time.tm_isdst = -1; +- ret = rtc_set_alarm(ops, &alrm); ++ ret = rtc_arm_set_alarm(ops, &alrm); + break; + + case RTC_RD_TIME: +- ret = rtc_read_time(ops, &tm); ++ ret = rtc_arm_read_time(ops, &tm); + if (ret) + break; + ret = copy_to_user(uarg, &tm, sizeof(tm)); +@@ -310,7 +228,7 @@ static int rtc_ioctl(struct inode *inode + ret = -EFAULT; + break; + } +- ret = rtc_set_time(ops, &tm); ++ ret = rtc_arm_set_time(ops, &tm); + break; + + case RTC_EPOCH_SET: +@@ -341,11 +259,11 @@ static int rtc_ioctl(struct inode *inode + ret = -EFAULT; + break; + } +- ret = rtc_set_alarm(ops, &alrm); ++ ret = rtc_arm_set_alarm(ops, &alrm); + break; + + case RTC_WKALM_RD: +- ret = rtc_read_alarm(ops, &alrm); ++ ret = rtc_arm_read_alarm(ops, &alrm); + if (ret) + break; + ret = copy_to_user(uarg, &alrm, sizeof(alrm)); +@@ -435,7 +353,7 @@ static int rtc_read_proc(char *page, cha + struct rtc_time tm; + char *p = page; + +- if (rtc_read_time(ops, &tm) == 0) { ++ if (rtc_arm_read_time(ops, &tm) == 0) { + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" +@@ -445,7 +363,7 @@ static int rtc_read_proc(char *page, cha + rtc_epoch); + } + +- if (rtc_read_alarm(ops, &alrm) == 0) { ++ if (rtc_arm_read_alarm(ops, &alrm) == 0) { + p += sprintf(p, "alrm_time\t: "); + if ((unsigned int)alrm.time.tm_hour <= 24) + p += sprintf(p, "%02d:", alrm.time.tm_hour); +--- linux-ixp4xx.orig/include/asm-arm/rtc.h 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/include/asm-arm/rtc.h 2006-03-08 01:59:26.000000000 +0100 +@@ -25,9 +25,6 @@ struct rtc_ops { + int (*proc)(char *buf); + }; + +-void rtc_time_to_tm(unsigned long, struct rtc_time *); +-int rtc_tm_to_time(struct rtc_time *, unsigned long *); +-int rtc_valid_tm(struct rtc_time *); + void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); + void rtc_update(unsigned long, unsigned long); + int register_rtc(struct rtc_ops *); +--- linux-ixp4xx.orig/drivers/char/Kconfig 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/drivers/char/Kconfig 2006-03-08 01:59:26.000000000 +0100 +@@ -695,7 +695,7 @@ config NVRAM + + config RTC + tristate "Enhanced Real Time Clock Support" +- depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV ++ depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you +--- linux-ixp4xx.orig/arch/arm/Kconfig 2006-03-08 01:59:18.000000000 +0100 ++++ linux-ixp4xx/arch/arm/Kconfig 2006-03-08 01:59:26.000000000 +0100 +@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" + config ARM + bool + default y ++ select RTC_LIB + help + The ARM series is a line of low-power-consumption RISC chip designs + licensed by ARM Ltd and targeted at embedded applications and +@@ -819,6 +820,8 @@ source "drivers/usb/Kconfig" + + source "drivers/mmc/Kconfig" +source "drivers/rtc/Kconfig" + endmenu ---- linux-rtc.orig/drivers/Makefile 2006-02-19 23:33:10.000000000 +0100 -+++ linux-rtc/drivers/Makefile 2006-02-19 23:33:15.000000000 +0100 -@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/ - obj-$(CONFIG_GAMEPORT) += input/gameport/ - obj-$(CONFIG_INPUT) += input/ - obj-$(CONFIG_I2O) += message/ -+obj-y += rtc/ - obj-$(CONFIG_I2C) += i2c/ - obj-$(CONFIG_W1) += w1/ - obj-$(CONFIG_HWMON) += hwmon/ + + source "fs/Kconfig" +--- linux-ixp4xx.orig/arch/arm/mach-integrator/time.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-integrator/time.c 2006-03-08 01:59:26.000000000 +0100 +@@ -40,13 +40,13 @@ static int integrator_set_rtc(void) + return 1; + } + +-static int rtc_read_alarm(struct rtc_wkalrm *alrm) ++static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm) + { + rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); + return 0; + } + +-static inline int rtc_set_alarm(struct rtc_wkalrm *alrm) ++static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm) + { + unsigned long time; + int ret; +@@ -62,7 +62,7 @@ static inline int rtc_set_alarm(struct r + return ret; + } + +-static int rtc_read_time(struct rtc_time *tm) ++static int integrator_rtc_read_time(struct rtc_time *tm) + { + rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); + return 0; +@@ -76,7 +76,7 @@ static int rtc_read_time(struct rtc_time + * edge of the 1Hz clock, we must write the time one second + * in advance. + */ +-static inline int rtc_set_time(struct rtc_time *tm) ++static inline int integrator_rtc_set_time(struct rtc_time *tm) + { + unsigned long time; + int ret; +@@ -90,10 +90,10 @@ static inline int rtc_set_time(struct rt + + static struct rtc_ops rtc_ops = { + .owner = THIS_MODULE, +- .read_time = rtc_read_time, +- .set_time = rtc_set_time, +- .read_alarm = rtc_read_alarm, +- .set_alarm = rtc_set_alarm, ++ .read_time = integrator_rtc_read_time, ++ .set_time = integrator_rtc_set_time, ++ .read_alarm = integrator_rtc_read_alarm, ++ .set_alarm = integrator_rtc_set_alarm, + }; + + static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, +--- linux-ixp4xx.orig/arch/mips/ddb5xxx/common/rtc_ds1386.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/ddb5xxx/common/rtc_ds1386.c 2006-03-08 01:59:26.000000000 +0100 +@@ -165,6 +165,6 @@ rtc_ds1386_init(unsigned long base) + WRITE_RTC(0xB, byte); + + /* set the function pointers */ +- rtc_get_time = rtc_ds1386_get_time; +- rtc_set_time = rtc_ds1386_set_time; ++ rtc_mips_get_time = rtc_ds1386_get_time; ++ rtc_mips_set_time = rtc_ds1386_set_time; + } +--- linux-ixp4xx.orig/arch/mips/dec/time.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/dec/time.c 2006-03-08 01:59:26.000000000 +0100 +@@ -193,8 +193,8 @@ static void dec_ioasic_hpt_init(unsigned + + void __init dec_time_init(void) + { +- rtc_get_time = dec_rtc_get_time; +- rtc_set_mmss = dec_rtc_set_mmss; ++ rtc_mips_get_time = dec_rtc_get_time; ++ rtc_mips_set_mmss = dec_rtc_set_mmss; + + mips_timer_state = dec_timer_state; + mips_timer_ack = dec_timer_ack; +--- linux-ixp4xx.orig/arch/mips/ite-boards/generic/time.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/ite-boards/generic/time.c 2006-03-08 01:59:26.000000000 +0100 +@@ -227,8 +227,8 @@ void __init it8172_time_init(void) + + local_irq_restore(flags); + +- rtc_get_time = it8172_rtc_get_time; +- rtc_set_time = it8172_rtc_set_time; ++ rtc_mips_get_time = it8172_rtc_get_time; ++ rtc_mips_set_time = it8172_rtc_set_time; + } + + #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +--- linux-ixp4xx.orig/arch/mips/jmr3927/common/rtc_ds1742.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/jmr3927/common/rtc_ds1742.c 2006-03-08 01:59:26.000000000 +0100 +@@ -159,8 +159,8 @@ rtc_ds1742_init(unsigned long base) + db_assert((rtc_base & 0xe0000000) == KSEG1); + + /* set the function pointers */ +- rtc_get_time = rtc_ds1742_get_time; +- rtc_set_time = rtc_ds1742_set_time; ++ rtc_mips_get_time = rtc_ds1742_get_time; ++ rtc_mips_set_time = rtc_ds1742_set_time; + + /* clear oscillator stop bit */ + CMOS_WRITE(RTC_READ, RTC_CONTROL); +--- linux-ixp4xx.orig/arch/mips/kernel/time.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/kernel/time.c 2006-03-08 01:59:26.000000000 +0100 +@@ -65,9 +65,9 @@ static int null_rtc_set_time(unsigned lo + return 0; + } + +-unsigned long (*rtc_get_time)(void) = null_rtc_get_time; +-int (*rtc_set_time)(unsigned long) = null_rtc_set_time; +-int (*rtc_set_mmss)(unsigned long); ++unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time; ++int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; ++int (*rtc_mips_set_mmss)(unsigned long); + + + /* usecs per counter cycle, shifted to left by 32 bits */ +@@ -438,7 +438,7 @@ irqreturn_t timer_interrupt(int irq, voi + + /* + * If we have an externally synchronized Linux clock, then update +- * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be ++ * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be + * called as close as possible to 500 ms before the new second starts. + */ + write_seqlock(&xtime_lock); +@@ -446,7 +446,7 @@ irqreturn_t timer_interrupt(int irq, voi + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { +- if (rtc_set_mmss(xtime.tv_sec) == 0) { ++ if (rtc_mips_set_mmss(xtime.tv_sec) == 0) { + last_rtc_update = xtime.tv_sec; + } else { + /* do it again in 60 s */ +@@ -563,7 +563,7 @@ asmlinkage void ll_local_timer_interrupt + * b) (optional) calibrate and set the mips_hpt_frequency + * (only needed if you intended to use fixed_rate_gettimeoffset + * or use cpu counter as timer interrupt source) +- * 2) setup xtime based on rtc_get_time(). ++ * 2) setup xtime based on rtc_mips_get_time(). + * 3) choose a appropriate gettimeoffset routine. + * 4) calculate a couple of cached variables for later usage + * 5) board_timer_setup() - +@@ -631,10 +631,10 @@ void __init time_init(void) + if (board_time_init) + board_time_init(); + +- if (!rtc_set_mmss) +- rtc_set_mmss = rtc_set_time; ++ if (!rtc_mips_set_mmss) ++ rtc_mips_set_mmss = rtc_mips_set_time; + +- xtime.tv_sec = rtc_get_time(); ++ xtime.tv_sec = rtc_mips_get_time(); + xtime.tv_nsec = 0; + + set_normalized_timespec(&wall_to_monotonic, +@@ -770,8 +770,8 @@ void to_tm(unsigned long tim, struct rtc + + EXPORT_SYMBOL(rtc_lock); + EXPORT_SYMBOL(to_tm); +-EXPORT_SYMBOL(rtc_set_time); +-EXPORT_SYMBOL(rtc_get_time); ++EXPORT_SYMBOL(rtc_mips_set_time); ++EXPORT_SYMBOL(rtc_mips_get_time); + + unsigned long long sched_clock(void) + { +--- linux-ixp4xx.orig/arch/mips/lasat/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/lasat/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -174,8 +174,8 @@ void __init plat_setup(void) + + #ifdef CONFIG_DS1603 + ds1603 = &ds_defs[mips_machtype]; +- rtc_get_time = ds1603_read; +- rtc_set_time = ds1603_set; ++ rtc_mips_get_time = ds1603_read; ++ rtc_mips_set_time = ds1603_set; + #endif + + #ifdef DYNAMIC_SERIAL_INIT +--- linux-ixp4xx.orig/arch/mips/mips-boards/atlas/atlas_setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/mips-boards/atlas/atlas_setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -65,7 +65,7 @@ void __init plat_setup(void) + + board_time_init = mips_time_init; + board_timer_setup = mips_timer_setup; +- rtc_get_time = mips_rtc_get_time; ++ rtc_mips_get_time = mips_rtc_get_time; + } + + static void __init serial_init(void) +--- linux-ixp4xx.orig/arch/mips/mips-boards/malta/malta_setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/mips-boards/malta/malta_setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -225,5 +225,5 @@ void __init plat_setup(void) + + board_time_init = mips_time_init; + board_timer_setup = mips_timer_setup; +- rtc_get_time = mips_rtc_get_time; ++ rtc_mips_get_time = mips_rtc_get_time; + } +--- linux-ixp4xx.orig/arch/mips/momentum/jaguar_atx/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/momentum/jaguar_atx/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -228,8 +228,8 @@ void momenco_time_init(void) + mips_hpt_frequency = cpu_clock / 2; + board_timer_setup = momenco_timer_setup; + +- rtc_get_time = m48t37y_get_time; +- rtc_set_time = m48t37y_set_time; ++ rtc_mips_get_time = m48t37y_get_time; ++ rtc_mips_set_time = m48t37y_set_time; + } + + static struct resource mv_pci_io_mem0_resource = { +--- linux-ixp4xx.orig/arch/mips/momentum/ocelot_3/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/momentum/ocelot_3/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -215,8 +215,8 @@ void momenco_time_init(void) + mips_hpt_frequency = cpu_clock / 2; + board_timer_setup = momenco_timer_setup; + +- rtc_get_time = m48t37y_get_time; +- rtc_set_time = m48t37y_set_time; ++ rtc_mips_get_time = m48t37y_get_time; ++ rtc_mips_set_time = m48t37y_set_time; + } + + /* +--- linux-ixp4xx.orig/arch/mips/momentum/ocelot_c/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/momentum/ocelot_c/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -226,8 +226,8 @@ void momenco_time_init(void) + printk("momenco_time_init cpu_clock=%d\n", cpu_clock); + board_timer_setup = momenco_timer_setup; + +- rtc_get_time = m48t37y_get_time; +- rtc_set_time = m48t37y_set_time; ++ rtc_mips_get_time = m48t37y_get_time; ++ rtc_mips_set_time = m48t37y_set_time; + } + + void __init plat_setup(void) +--- linux-ixp4xx.orig/arch/mips/pmc-sierra/yosemite/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/pmc-sierra/yosemite/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -198,8 +198,8 @@ static void __init py_rtc_setup(void) + if (!m48t37_base) + printk(KERN_ERR "Mapping the RTC failed\n"); + +- rtc_get_time = m48t37y_get_time; +- rtc_set_time = m48t37y_set_time; ++ rtc_mips_get_time = m48t37y_get_time; ++ rtc_mips_set_time = m48t37y_set_time; + + write_seqlock(&xtime_lock); + xtime.tv_sec = m48t37y_get_time(); +--- linux-ixp4xx.orig/arch/mips/sgi-ip22/ip22-time.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/sgi-ip22/ip22-time.c 2006-03-08 01:59:26.000000000 +0100 +@@ -212,8 +212,8 @@ static void indy_timer_setup(struct irqa + void __init ip22_time_init(void) + { + /* setup hookup functions */ +- rtc_get_time = indy_rtc_get_time; +- rtc_set_time = indy_rtc_set_time; ++ rtc_mips_get_time = indy_rtc_get_time; ++ rtc_mips_set_time = indy_rtc_set_time; + + board_time_init = indy_time_init; + board_timer_setup = indy_timer_setup; +--- linux-ixp4xx.orig/arch/mips/sgi-ip32/ip32-setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/sgi-ip32/ip32-setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -91,8 +91,8 @@ void __init plat_setup(void) + { + board_be_init = ip32_be_init; + +- rtc_get_time = mc146818_get_cmos_time; +- rtc_set_mmss = mc146818_set_rtc_mmss; ++ rtc_mips_get_time = mc146818_get_cmos_time; ++ rtc_mips_set_mmss = mc146818_set_rtc_mmss; + + board_time_init = ip32_time_init; + board_timer_setup = ip32_timer_setup; +--- linux-ixp4xx.orig/arch/mips/sibyte/swarm/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/sibyte/swarm/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -114,14 +114,14 @@ void __init plat_setup(void) + + if (xicor_probe()) { + printk("swarm setup: Xicor 1241 RTC detected.\n"); +- rtc_get_time = xicor_get_time; +- rtc_set_time = xicor_set_time; ++ rtc_mips_get_time = xicor_get_time; ++ rtc_mips_set_time = xicor_set_time; + } + + if (m41t81_probe()) { + printk("swarm setup: M41T81 RTC detected.\n"); +- rtc_get_time = m41t81_get_time; +- rtc_set_time = m41t81_set_time; ++ rtc_mips_get_time = m41t81_get_time; ++ rtc_mips_set_time = m41t81_set_time; + } + + printk("This kernel optimized for " +--- linux-ixp4xx.orig/arch/mips/sni/setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/sni/setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -164,8 +164,8 @@ static struct pci_controller sni_control + + static inline void sni_pcimt_time_init(void) + { +- rtc_get_time = mc146818_get_cmos_time; +- rtc_set_time = mc146818_set_rtc_mmss; ++ rtc_mips_get_time = mc146818_get_cmos_time; ++ rtc_mips_set_time = mc146818_set_rtc_mmss; + } + + void __init plat_setup(void) +--- linux-ixp4xx.orig/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c 2006-03-08 01:59:26.000000000 +0100 +@@ -1036,8 +1036,8 @@ toshiba_rbtx4927_time_init(void) + + #ifdef CONFIG_RTC_DS1742 + +- rtc_get_time = rtc_ds1742_get_time; +- rtc_set_time = rtc_ds1742_set_time; ++ rtc_mips_get_time = rtc_ds1742_get_time; ++ rtc_mips_set_time = rtc_ds1742_set_time; + + TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, + ":rtc_ds1742_init()-\n"); +--- linux-ixp4xx.orig/arch/mips/tx4938/common/rtc_rx5c348.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/mips/tx4938/common/rtc_rx5c348.c 2006-03-08 01:59:26.000000000 +0100 +@@ -197,6 +197,6 @@ rtc_rx5c348_init(int chipid) + srtc_24h = 1; + + /* set the function pointers */ +- rtc_get_time = rtc_rx5c348_get_time; +- rtc_set_time = rtc_rx5c348_set_time; ++ rtc_mips_get_time = rtc_rx5c348_get_time; ++ rtc_mips_set_time = rtc_rx5c348_set_time; + } +--- linux-ixp4xx.orig/include/asm-mips/time.h 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/include/asm-mips/time.h 2006-03-08 01:59:26.000000000 +0100 +@@ -26,14 +26,14 @@ extern spinlock_t rtc_lock; + + /* + * RTC ops. By default, they point to no-RTC functions. +- * rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds. +- * rtc_set_time - reverse the above translation and set time to RTC. +- * rtc_set_mmss - similar to rtc_set_time, but only min and sec need ++ * rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds. ++ * rtc_mips_set_time - reverse the above translation and set time to RTC. ++ * rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need + * to be set. Used by RTC sync-up. + */ +-extern unsigned long (*rtc_get_time)(void); +-extern int (*rtc_set_time)(unsigned long); +-extern int (*rtc_set_mmss)(unsigned long); ++extern unsigned long (*rtc_mips_get_time)(void); ++extern int (*rtc_mips_set_time)(unsigned long); ++extern int (*rtc_mips_set_mmss)(unsigned long); + + /* + * Timer interrupt functions. --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/class.c 2006-02-19 23:33:15.000000000 +0100 -@@ -0,0 +1,143 @@ ++++ linux-ixp4xx/drivers/rtc/class.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,145 @@ +/* + * RTC subsystem, base class + * @@ -182,7 +1125,8 @@ + + id = id & MAX_ID_MASK; + -+ if ((rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL)) == NULL) { ++ rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); ++ if (rtc == NULL) { + err = -ENOMEM; + goto exit_idr; + } @@ -201,7 +1145,8 @@ + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); + snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id); + -+ if ((err = class_device_register(&rtc->class_dev))) ++ err = class_device_register(&rtc->class_dev); ++ if (err) + goto exit_kfree; + + dev_info(dev, "rtc core: registered %s as %s\n", @@ -264,163 +1209,8 @@ +MODULE_DESCRIPTION("RTC class support"); +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/Kconfig 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,131 @@ -+# -+# RTC class/drivers configuration -+# -+ -+menu "Real Time Clock" -+ -+config RTC_CLASS -+ tristate "RTC class" -+ depends on EXPERIMENTAL -+ default y -+ help -+ Generic RTC class support. If you say yes here, you will -+ be allowed to plug one or more RTCs to your system. You will -+ probably want to enable one of more of the interfaces below. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-class. -+ -+config RTC_HCTOSYS -+ bool "Set system time from RTC on startup" -+ depends on RTC_CLASS = y -+ default y -+ help -+ If you say yes here, the system time will be set using -+ the value read from the specified RTC device. This is useful -+ in order to avoid unnecessary fschk runs. -+ -+config RTC_HCTOSYS_DEVICE -+ string "The RTC to read the time from" -+ depends on RTC_HCTOSYS = y -+ default "rtc0" -+ help -+ The RTC device that will be used as the source for -+ the system time, usually rtc0. -+ -+comment "RTC interfaces" -+ depends on RTC_CLASS -+ -+config RTC_INTF_SYSFS -+ tristate "sysfs" -+ depends on RTC_CLASS && SYSFS -+ default RTC_CLASS -+ help -+ Say yes here if you want to use your RTC using the sysfs -+ interface, /sys/class/rtc/rtcX . -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-sysfs. -+ -+config RTC_INTF_PROC -+ tristate "proc" -+ depends on RTC_CLASS && PROC_FS -+ default RTC_CLASS -+ help -+ Say yes here if you want to use your RTC using the proc -+ interface, /proc/driver/rtc . -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-proc. -+ -+config RTC_INTF_DEV -+ tristate "dev" -+ depends on RTC_CLASS -+ default RTC_CLASS -+ help -+ Say yes here if you want to use your RTC using the dev -+ interface, /dev/rtc . -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-dev. -+ -+comment "RTC drivers" -+ depends on RTC_CLASS -+ -+config RTC_DRV_X1205 -+ tristate "Xicor/Intersil X1205 RTC chip" -+ depends on RTC_CLASS && I2C -+ help -+ If you say yes here you get support for the -+ Xicor/Intersil X1205 RTC chip. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-x1205. -+ -+config RTC_DRV_DS1672 -+ tristate "Dallas/Maxim DS1672" -+ depends on RTC_CLASS && I2C -+ help -+ If you say yes here you get support for the -+ Dallas/Maxim DS1672 timekeeping chip. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-ds1672. -+ -+config RTC_DRV_PCF8563 -+ tristate "Philips PCF8563/Epson RTC8564" -+ depends on RTC_CLASS && I2C -+ help -+ If you say yes here you get support for the -+ Philips PCF8563 RTC chip. The Epson RTC8564 -+ should work as well. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-pcf8563. -+ -+config RTC_DRV_RS5C372 -+ tristate "Ricoh RS5C372A/B" -+ depends on RTC_CLASS && I2C -+ help -+ If you say yes here you get support for the -+ Ricoh RS5C372A and RS5C372B RTC chips. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-rs5c372. -+ -+config RTC_DRV_TEST -+ tristate "Test driver/device" -+ depends on RTC_CLASS -+ help -+ If you say yes here you get support for the -+ RTC test driver. It's a software RTC which can be -+ used to test the RTC subsystem APIs. It gets -+ the time from the system clock. -+ You want this driver only if you are doing development -+ on the RTC subsystem. Please read the source code -+ for further details. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-test. -+ -+endmenu ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/Makefile 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,18 @@ -+# -+# Makefile for RTC class/drivers. -+# -+ -+obj-y += utils.o -+obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o -+obj-$(CONFIG_RTC_CLASS) += rtc-core.o -+rtc-core-y := class.o interface.o -+obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o -+obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o -+obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o -+ -+obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o -+obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o -+obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o -+obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o -+obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o -+ ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/interface.c 2006-02-19 23:33:15.000000000 +0100 -@@ -0,0 +1,274 @@ ++++ linux-ixp4xx/drivers/rtc/interface.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,277 @@ +/* + * RTC subsystem, interface functions + * @@ -436,15 +1226,14 @@ + +#include <linux/rtc.h> + -+extern struct class *rtc_class; -+ +int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ if ((err = mutex_lock_interruptible(&rtc->ops_lock))) -+ return err; ++ err = mutex_lock_interruptible(&rtc->ops_lock); ++ if (err) ++ return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; @@ -458,18 +1247,20 @@ + mutex_unlock(&rtc->ops_lock); + return err; +} -+EXPORT_SYMBOL(rtc_read_time); ++EXPORT_SYMBOL_GPL(rtc_read_time); + +int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ if ((err = rtc_valid_tm(tm)) != 0) ++ err = rtc_valid_tm(tm); ++ if (err != 0) + return err; + -+ if ((err = mutex_lock_interruptible(&rtc->ops_lock))) -+ return err; ++ err = mutex_lock_interruptible(&rtc->ops_lock); ++ if (err) ++ return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; @@ -481,57 +1272,56 @@ + mutex_unlock(&rtc->ops_lock); + return err; +} -+EXPORT_SYMBOL(rtc_set_time); ++EXPORT_SYMBOL_GPL(rtc_set_time); + +int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ if ((err = mutex_lock_interruptible(&rtc->ops_lock))) -+ return err; ++ err = mutex_lock_interruptible(&rtc->ops_lock); ++ if (err) ++ return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; -+ else if (!rtc->ops->set_mmss) { -+ if (rtc->ops->read_time && rtc->ops->set_time) { -+ struct rtc_time new, old; -+ -+ new.tm_sec = secs % 60; -+ secs /= 60; -+ new.tm_min = secs % 60; -+ secs /= 60; -+ new.tm_hour = secs % 24; -+ -+ /* -+ * avoid writing when we're going to change the day -+ * of the month. We will retry in the next minute. -+ * This basically means that if the RTC must not drift -+ * by more than 1 minute in 11 minutes. -+ */ ++ else if (rtc->ops->set_mmss) ++ err = rtc->ops->set_mmss(class_dev->dev, secs); ++ else if (rtc->ops->read_time && rtc->ops->set_time) { ++ struct rtc_time new, old; ++ ++ err = rtc->ops->read_time(class_dev->dev, &old); ++ if (err == 0) { ++ rtc_time_to_tm(secs, &new); ++ ++ /* ++ * avoid writing when we're going to change the day of ++ * the month. We will retry in the next minute. This ++ * basically means that if the RTC must not drift ++ * by more than 1 minute in 11 minutes. ++ */ + if (!((old.tm_hour == 23 && old.tm_min == 59) || -+ (new.tm_hour == 23 && new.tm_min == 59))) ++ (new.tm_hour == 23 && new.tm_min == 59))) + err = rtc->ops->set_time(class_dev->dev, &new); + } -+ else -+ err = -EINVAL; + } + else -+ err = rtc->ops->set_mmss(class_dev->dev, secs); ++ err = -EINVAL; + + mutex_unlock(&rtc->ops_lock); + + return err; +} -+EXPORT_SYMBOL(rtc_set_mmss); ++EXPORT_SYMBOL_GPL(rtc_set_mmss); + +int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ if ((err = mutex_lock_interruptible(&rtc->ops_lock))) -+ return err; ++ err = mutex_lock_interruptible(&rtc->ops_lock); ++ if (err) ++ return -EBUSY; + + if (rtc->ops == NULL) + err = -ENODEV; @@ -545,15 +1335,16 @@ + mutex_unlock(&rtc->ops_lock); + return err; +} -+EXPORT_SYMBOL(rtc_read_alarm); ++EXPORT_SYMBOL_GPL(rtc_read_alarm); + +int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ if ((err = mutex_lock_interruptible(&rtc->ops_lock))) -+ return err; ++ err = mutex_lock_interruptible(&rtc->ops_lock); ++ if (err) ++ return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; @@ -565,7 +1356,7 @@ + mutex_unlock(&rtc->ops_lock); + return err; +} -+EXPORT_SYMBOL(rtc_set_alarm); ++EXPORT_SYMBOL_GPL(rtc_set_alarm); + +void rtc_update_irq(struct class_device *class_dev, + unsigned long num, unsigned long events) @@ -584,7 +1375,7 @@ + wake_up_interruptible(&rtc->irq_queue); + kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); +} -+EXPORT_SYMBOL(rtc_update_irq); ++EXPORT_SYMBOL_GPL(rtc_update_irq); + +struct class_device *rtc_class_open(char *name) +{ @@ -607,13 +1398,13 @@ + + return class_dev; +} -+EXPORT_SYMBOL(rtc_class_open); ++EXPORT_SYMBOL_GPL(rtc_class_open); + +void rtc_class_close(struct class_device *class_dev) +{ + module_put(to_rtc_device(class_dev)->owner); +} -+EXPORT_SYMBOL(rtc_class_close); ++EXPORT_SYMBOL_GPL(rtc_class_close); + +int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task) +{ @@ -632,7 +1423,7 @@ + + return retval; +} -+EXPORT_SYMBOL(rtc_irq_register); ++EXPORT_SYMBOL_GPL(rtc_irq_register); + +void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task) +{ @@ -643,7 +1434,7 @@ + rtc->irq_task = NULL; + spin_unlock(&rtc->irq_task_lock); +} -+EXPORT_SYMBOL(rtc_irq_unregister); ++EXPORT_SYMBOL_GPL(rtc_irq_unregister); + +int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled) +{ @@ -661,7 +1452,7 @@ + + return err; +} -+EXPORT_SYMBOL(rtc_irq_set_state); ++EXPORT_SYMBOL_GPL(rtc_irq_set_state); + +int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) +{ @@ -672,8 +1463,10 @@ + /* allowed range is 2-8192 */ + if (freq < 2 || freq > 8192) + return -EINVAL; -+ -+/* if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) ++/* ++ FIXME: this does not belong here, will move where appropriate ++ at a later stage. It cannot hurt right now, trust me :) ++ if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + return -EACCES; +*/ + /* check if freq is a power of 2 */ @@ -689,115 +1482,15 @@ + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + + if (err == 0) { -+ if ((err = rtc->ops->irq_set_freq(class_dev->dev, freq)) == 0) ++ err = rtc->ops->irq_set_freq(class_dev->dev, freq); ++ if (err == 0) + rtc->irq_freq = freq; + } + return err; -+ +} --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/utils.c 2006-02-19 23:33:15.000000000 +0100 -@@ -0,0 +1,97 @@ -+/* -+ * RTC subsystem, utility functions -+ * -+ * Copyright (C) 2005 Tower Technologies -+ * Author: Alessandro Zummo <a.zummo@towertech.it> -+ * -+ * based on arch/arm/common/rtctime.c -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+*/ -+ -+#include <linux/rtc.h> -+ -+static const unsigned char rtc_days_in_month[] = { -+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -+}; -+ -+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) -+ -+int rtc_month_days(unsigned int month, unsigned int year) -+{ -+ return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); -+} -+EXPORT_SYMBOL(rtc_month_days); -+ -+/* -+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. -+ */ -+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) -+{ -+ int days, month, year; -+ -+ days = time / 86400; -+ time -= days * 86400; -+ -+ tm->tm_wday = (days + 4) % 7; -+ -+ year = 1970 + days / 365; -+ days -= (year - 1970) * 365 -+ + LEAPS_THRU_END_OF(year - 1) -+ - LEAPS_THRU_END_OF(1970 - 1); -+ if (days < 0) { -+ year -= 1; -+ days += 365 + LEAP_YEAR(year); -+ } -+ tm->tm_year = year - 1900; -+ tm->tm_yday = days + 1; -+ -+ for (month = 0; month < 11; month++) { -+ int newdays; -+ -+ newdays = days - rtc_month_days(month, year); -+ if (newdays < 0) -+ break; -+ days = newdays; -+ } -+ tm->tm_mon = month; -+ tm->tm_mday = days + 1; -+ -+ tm->tm_hour = time / 3600; -+ time -= tm->tm_hour * 3600; -+ tm->tm_min = time / 60; -+ tm->tm_sec = time - tm->tm_min * 60; -+} -+EXPORT_SYMBOL(rtc_time_to_tm); -+ -+/* -+ * Does the rtc_time represent a valid date/time? -+ */ -+int rtc_valid_tm(struct rtc_time *tm) -+{ -+ if (tm->tm_year < 70 || -+ tm->tm_mon >= 12 || -+ tm->tm_mday < 1 || -+ tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) || -+ tm->tm_hour >= 24 || -+ tm->tm_min >= 60 || -+ tm->tm_sec >= 60) -+ return -EINVAL; -+ -+ return 0; -+} -+EXPORT_SYMBOL(rtc_valid_tm); -+ -+/* -+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00. -+ */ -+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) -+{ -+ *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec); -+ return 0; -+} -+EXPORT_SYMBOL(rtc_tm_to_time); ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/hctosys.c 2006-02-21 00:34:57.000000000 +0100 -@@ -0,0 +1,67 @@ ++++ linux-ixp4xx/drivers/rtc/hctosys.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,69 @@ +/* + * RTC subsystem, initialize system time on startup + * @@ -834,8 +1527,10 @@ + return -ENODEV; + } + -+ if ((err = rtc_read_time(class_dev, &tm)) == 0) { -+ if (rtc_valid_tm(&tm) == 0) { ++ err = rtc_read_time(class_dev, &tm); ++ if (err == 0) { ++ err = rtc_valid_tm(&tm); ++ if (err == 0) { + struct timespec tv; + + tv.tv_nsec = NSEC_PER_SEC >> 1; @@ -865,231 +1560,38 @@ +} + +late_initcall(rtc_hctosys); ---- linux-rtc.orig/arch/arm/Kconfig 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/arch/arm/Kconfig 2006-02-21 00:36:42.000000000 +0100 -@@ -817,6 +817,8 @@ source "drivers/usb/Kconfig" - - source "drivers/mmc/Kconfig" - -+source "drivers/rtc/Kconfig" -+ - endmenu - - source "fs/Kconfig" ---- linux-rtc.orig/arch/arm/common/rtctime.c 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/arch/arm/common/rtctime.c 2006-02-21 00:36:42.000000000 +0100 -@@ -42,89 +42,6 @@ static struct rtc_ops *rtc_ops; - - #define rtc_epoch 1900UL - --static const unsigned char days_in_month[] = { -- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 --}; -- --#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) --#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) -- --static int month_days(unsigned int month, unsigned int year) --{ -- return days_in_month[month] + (LEAP_YEAR(year) && month == 1); --} -- --/* -- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. -- */ --void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) --{ -- int days, month, year; -- -- days = time / 86400; -- time -= days * 86400; -- -- tm->tm_wday = (days + 4) % 7; -- -- year = 1970 + days / 365; -- days -= (year - 1970) * 365 -- + LEAPS_THRU_END_OF(year - 1) -- - LEAPS_THRU_END_OF(1970 - 1); -- if (days < 0) { -- year -= 1; -- days += 365 + LEAP_YEAR(year); -- } -- tm->tm_year = year - 1900; -- tm->tm_yday = days + 1; -- -- for (month = 0; month < 11; month++) { -- int newdays; -- -- newdays = days - month_days(month, year); -- if (newdays < 0) -- break; -- days = newdays; -- } -- tm->tm_mon = month; -- tm->tm_mday = days + 1; -- -- tm->tm_hour = time / 3600; -- time -= tm->tm_hour * 3600; -- tm->tm_min = time / 60; -- tm->tm_sec = time - tm->tm_min * 60; --} --EXPORT_SYMBOL(rtc_time_to_tm); -- --/* -- * Does the rtc_time represent a valid date/time? -- */ --int rtc_valid_tm(struct rtc_time *tm) --{ -- if (tm->tm_year < 70 || -- tm->tm_mon >= 12 || -- tm->tm_mday < 1 || -- tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) || -- tm->tm_hour >= 24 || -- tm->tm_min >= 60 || -- tm->tm_sec >= 60) -- return -EINVAL; -- -- return 0; --} --EXPORT_SYMBOL(rtc_valid_tm); -- --/* -- * Convert Gregorian date to seconds since 01-01-1970 00:00:00. -- */ --int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) --{ -- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, -- tm->tm_hour, tm->tm_min, tm->tm_sec); -- -- return 0; --} --EXPORT_SYMBOL(rtc_tm_to_time); -- - /* - * Calculate the next alarm time given the requested alarm time mask - * and the current time. -@@ -143,13 +60,13 @@ void rtc_next_alarm_time(struct rtc_time - next->tm_sec = alrm->tm_sec; - } - --static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) -+static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm) - { - memset(tm, 0, sizeof(struct rtc_time)); - return ops->read_time(tm); - } - --static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) -+static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm) - { - int ret; - -@@ -160,7 +77,7 @@ static inline int rtc_set_time(struct rt - return ret; - } - --static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) -+static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) - { - int ret = -EINVAL; - if (ops->read_alarm) { -@@ -170,7 +87,7 @@ static inline int rtc_read_alarm(struct - return ret; - } - --static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) -+static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) - { - int ret = -EINVAL; - if (ops->set_alarm) -@@ -258,7 +175,7 @@ static int rtc_ioctl(struct inode *inode - - switch (cmd) { - case RTC_ALM_READ: -- ret = rtc_read_alarm(ops, &alrm); -+ ret = rtc_arm_read_alarm(ops, &alrm); - if (ret) - break; - ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); -@@ -280,11 +197,11 @@ static int rtc_ioctl(struct inode *inode - alrm.time.tm_wday = -1; - alrm.time.tm_yday = -1; - alrm.time.tm_isdst = -1; -- ret = rtc_set_alarm(ops, &alrm); -+ ret = rtc_arm_set_alarm(ops, &alrm); - break; - - case RTC_RD_TIME: -- ret = rtc_read_time(ops, &tm); -+ ret = rtc_arm_read_time(ops, &tm); - if (ret) - break; - ret = copy_to_user(uarg, &tm, sizeof(tm)); -@@ -302,7 +219,7 @@ static int rtc_ioctl(struct inode *inode - ret = -EFAULT; - break; - } -- ret = rtc_set_time(ops, &tm); -+ ret = rtc_arm_set_time(ops, &tm); - break; - - case RTC_EPOCH_SET: -@@ -333,11 +250,11 @@ static int rtc_ioctl(struct inode *inode - ret = -EFAULT; - break; - } -- ret = rtc_set_alarm(ops, &alrm); -+ ret = rtc_arm_set_alarm(ops, &alrm); - break; - - case RTC_WKALM_RD: -- ret = rtc_read_alarm(ops, &alrm); -+ ret = rtc_arm_read_alarm(ops, &alrm); - if (ret) - break; - ret = copy_to_user(uarg, &alrm, sizeof(alrm)); -@@ -427,7 +344,7 @@ static int rtc_read_proc(char *page, cha - struct rtc_time tm; - char *p = page; - -- if (rtc_read_time(ops, &tm) == 0) { -+ if (rtc_arm_read_time(ops, &tm) == 0) { - p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" -@@ -437,7 +354,7 @@ static int rtc_read_proc(char *page, cha - rtc_epoch); - } +--- linux-ixp4xx.orig/CREDITS 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/CREDITS 2006-03-08 01:59:26.000000000 +0100 +@@ -3741,10 +3741,11 @@ D: Mylex DAC960 PCI RAID driver + D: Miscellaneous kernel fixes -- if (rtc_read_alarm(ops, &alrm) == 0) { -+ if (rtc_arm_read_alarm(ops, &alrm) == 0) { - p += sprintf(p, "alrm_time\t: "); - if ((unsigned int)alrm.time.tm_hour <= 24) - p += sprintf(p, "%02d:", alrm.time.tm_hour); ---- linux-rtc.orig/include/asm-arm/rtc.h 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/include/asm-arm/rtc.h 2006-02-21 00:36:42.000000000 +0100 -@@ -25,9 +25,6 @@ struct rtc_ops { - int (*proc)(char *buf); - }; + N: Alessandro Zummo +-E: azummo@ita.flashnet.it +-W: http://freepage.logicom.it/azummo/ ++E: a.zummo@towertech.it + D: CMI8330 support is sb_card.c + D: ISAPnP fixes in sb_card.c ++D: ZyXEL omni.net lcd plus driver ++D: RTC subsystem + S: Italy --void rtc_time_to_tm(unsigned long, struct rtc_time *); --int rtc_tm_to_time(struct rtc_time *, unsigned long *); --int rtc_valid_tm(struct rtc_time *); - void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); - void rtc_update(unsigned long, unsigned long); - int register_rtc(struct rtc_ops *); ---- linux-rtc.orig/drivers/char/Kconfig 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/drivers/char/Kconfig 2006-02-21 00:36:42.000000000 +0100 -@@ -695,7 +695,7 @@ config NVRAM + N: Marc Zyngier +--- linux-ixp4xx.orig/MAINTAINERS 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/MAINTAINERS 2006-03-08 01:59:26.000000000 +0100 +@@ -2193,6 +2193,12 @@ M: p_gortmaker@yahoo.com + L: linux-kernel@vger.kernel.org + S: Maintained - config RTC - tristate "Enhanced Real Time Clock Support" -- depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV -+ depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM - ---help--- - If you say Y here and create a character special file /dev/rtc with - major number 10 and minor number 135 using mknod ("man mknod"), you ---- linux-rtc.orig/drivers/i2c/chips/x1205.c 2006-02-21 00:34:27.000000000 +0100 ++REAL TIME CLOCK (RTC) SUBSYSTEM ++P: Alessandro Zummo ++M: a.zummo@towertech.it ++L: linux-kernel@vger.kernel.org ++S: Maintained ++ + REISERFS FILE SYSTEM + P: Hans Reiser + M: reiserfs-dev@namesys.com +--- linux-ixp4xx.orig/drivers/i2c/chips/x1205.c 2006-03-08 01:59:09.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,698 +0,0 @@ -/* @@ -1790,8 +2292,8 @@ - -module_init(x1205_init); -module_exit(x1205_exit); ---- linux-rtc.orig/drivers/i2c/chips/Makefile 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/drivers/i2c/chips/Makefile 2006-02-21 00:36:43.000000000 +0100 +--- linux-ixp4xx.orig/drivers/i2c/chips/Makefile 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/drivers/i2c/chips/Makefile 2006-03-08 01:59:26.000000000 +0100 @@ -10,10 +10,8 @@ obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o @@ -1803,7 +2305,7 @@ ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG ---- linux-rtc.orig/drivers/i2c/chips/rtc8564.c 2006-02-21 00:34:27.000000000 +0100 +--- linux-ixp4xx.orig/drivers/i2c/chips/rtc8564.c 2006-03-08 01:59:09.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,385 +0,0 @@ -/* @@ -2191,7 +2693,7 @@ - -module_init(rtc8564_init); -module_exit(rtc8564_exit); ---- linux-rtc.orig/drivers/i2c/chips/rtc8564.h 2006-02-21 00:34:27.000000000 +0100 +--- linux-ixp4xx.orig/drivers/i2c/chips/rtc8564.h 2006-03-08 01:59:09.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/* @@ -2272,7 +2774,7 @@ -#define RTC8564_TD_1_60HZ (0x3) - -#define I2C_DRIVERID_RTC8564 0xf000 ---- linux-rtc.orig/include/linux/x1205.h 2006-02-21 00:34:27.000000000 +0100 +--- linux-ixp4xx.orig/include/linux/x1205.h 2006-03-08 01:59:09.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -/* @@ -2306,9 +2808,9 @@ - struct i2c_client_address_data *address_data); - -#endif /* __LINUX_X1205_H__ */ ---- linux-rtc.orig/drivers/i2c/chips/Kconfig 2006-02-21 00:34:27.000000000 +0100 -+++ linux-rtc/drivers/i2c/chips/Kconfig 2006-02-21 00:36:43.000000000 +0100 -@@ -65,15 +65,6 @@ config SENSORS_PCF8591 +--- linux-ixp4xx.orig/drivers/i2c/chips/Kconfig 2006-03-08 01:59:09.000000000 +0100 +1+++ linux-ixp4xx/drivers/i2c/chips/Kconfig 2006-03-08 01:59:26.000000000 +0100 +@@ -74,15 +74,6 @@ config SENSORS_RTC8564 This driver can also be built as a module. If so, the module will be called pcf8591. @@ -2324,7 +2826,7 @@ config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG -@@ -126,13 +117,4 @@ config SENSORS_MAX6875 +@@ -144,13 +135,4 @@ config RTC_X1205_I2C This driver can also be built as a module. If so, the module will be called max6875. @@ -2339,8 +2841,8 @@ - endmenu --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-sysfs.c 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,120 @@ ++++ linux-ixp4xx/drivers/rtc/rtc-sysfs.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,124 @@ +/* + * RTC subsystem, sysfs interface + * @@ -2368,7 +2870,8 @@ + ssize_t retval; + struct rtc_time tm; + -+ if ((retval = rtc_read_time(dev, &tm)) == 0) { ++ retval = rtc_read_time(dev, &tm); ++ if (retval == 0) { + retval = sprintf(buf, "%04d-%02d-%02d\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + } @@ -2382,7 +2885,8 @@ + ssize_t retval; + struct rtc_time tm; + -+ if ((retval = rtc_read_time(dev, &tm)) == 0) { ++ retval = rtc_read_time(dev, &tm); ++ if (retval == 0) { + retval = sprintf(buf, "%02d:%02d:%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec); + } @@ -2396,7 +2900,8 @@ + ssize_t retval; + struct rtc_time tm; + -+ if ((retval = rtc_read_time(dev, &tm)) == 0) { ++ retval = rtc_read_time(dev, &tm); ++ if (retval == 0) { + unsigned long time; + rtc_tm_to_time(&tm, &time); + retval = sprintf(buf, "%lu\n", time); @@ -2407,25 +2912,26 @@ +static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL); + +static struct attribute *rtc_attrs[] = { -+ &class_device_attr_name.attr, -+ &class_device_attr_date.attr, -+ &class_device_attr_time.attr, -+ &class_device_attr_since_epoch.attr, -+ NULL, ++ &class_device_attr_name.attr, ++ &class_device_attr_date.attr, ++ &class_device_attr_time.attr, ++ &class_device_attr_since_epoch.attr, ++ NULL, +}; + +static struct attribute_group rtc_attr_group = { -+ .attrs = rtc_attrs, ++ .attrs = rtc_attrs, +}; + +static int __devinit rtc_sysfs_add_device(struct class_device *class_dev, -+ struct class_interface *class_intf) ++ struct class_interface *class_intf) +{ + int err; + + dev_info(class_dev->dev, "rtc intf: sysfs\n"); + -+ if ((err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group)) != 0) ++ err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group); ++ if (err) + dev_err(class_dev->dev, + "failed to create sysfs attributes\n"); + @@ -2433,14 +2939,14 @@ +} + +static void rtc_sysfs_remove_device(struct class_device *class_dev, -+ struct class_interface *class_intf) ++ struct class_interface *class_intf) +{ + sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); +} + +/* interface registration */ + -+struct class_interface rtc_sysfs_interface = { ++static struct class_interface rtc_sysfs_interface = { + .add = &rtc_sysfs_add_device, + .remove = &rtc_sysfs_remove_device, +}; @@ -2462,12 +2968,12 @@ +MODULE_DESCRIPTION("RTC class sysfs interface"); +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-proc.c 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,158 @@ ++++ linux-ixp4xx/drivers/rtc/rtc-proc.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,162 @@ +/* + * RTC subsystem, proc interface + * -+ * Copyright (C) 2005 Tower Technologies ++ * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * based on arch/arm/common/rtctime.c @@ -2487,12 +2993,14 @@ + +static int rtc_proc_show(struct seq_file *seq, void *offset) +{ ++ int err; + struct class_device *class_dev = seq->private; + struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; + struct rtc_wkalrm alrm; + struct rtc_time tm; + -+ if (rtc_read_time(class_dev, &tm) == 0) { ++ err = rtc_read_time(class_dev, &tm); ++ if (err == 0) { + seq_printf(seq, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", @@ -2500,7 +3008,8 @@ + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + } + -+ if (rtc_read_alarm(class_dev, &alrm) == 0) { ++ err = rtc_read_alarm(class_dev, &alrm); ++ if (err == 0) { + seq_printf(seq, "alrm_time\t: "); + if ((unsigned int)alrm.time.tm_hour <= 24) + seq_printf(seq, "%02d:", alrm.time.tm_hour); @@ -2529,9 +3038,9 @@ + else + seq_printf(seq, "**\n"); + seq_printf(seq, "alrm_wakeup\t: %s\n", -+ alrm.enabled ? "yes" : "no"); ++ alrm.enabled ? "yes" : "no"); + seq_printf(seq, "alrm_pending\t: %s\n", -+ alrm.pending ? "yes" : "no"); ++ alrm.pending ? "yes" : "no"); + } + + if (ops->proc) @@ -2565,7 +3074,7 @@ +}; + +static int rtc_proc_add_device(struct class_device *class_dev, -+ struct class_interface *class_intf) ++ struct class_interface *class_intf) +{ + mutex_lock(&rtc_lock); + if (rtc_dev == NULL) { @@ -2573,7 +3082,8 @@ + + rtc_dev = class_dev; + -+ if ((ent = create_proc_entry("driver/rtc", 0, NULL))) { ++ ent = create_proc_entry("driver/rtc", 0, NULL); ++ if (ent) { + struct rtc_device *rtc = to_rtc_device(class_dev); + + ent->proc_fops = &rtc_proc_fops; @@ -2591,7 +3101,7 @@ +} + +static void rtc_proc_remove_device(struct class_device *class_dev, -+ struct class_interface *class_intf) ++ struct class_interface *class_intf) +{ + mutex_lock(&rtc_lock); + if (rtc_dev == class_dev) { @@ -2601,7 +3111,7 @@ + mutex_unlock(&rtc_lock); +} + -+struct class_interface rtc_proc_interface = { ++static struct class_interface rtc_proc_interface = { + .add = &rtc_proc_add_device, + .remove = &rtc_proc_remove_device, +}; @@ -2623,8 +3133,8 @@ +MODULE_DESCRIPTION("RTC class proc interface"); +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-dev.c 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,370 @@ ++++ linux-ixp4xx/drivers/rtc/rtc-dev.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,382 @@ +/* + * RTC subsystem, dev interface + * @@ -2641,6 +3151,7 @@ +#include <linux/module.h> +#include <linux/rtc.h> + ++static struct class *rtc_dev_class; +static dev_t rtc_devt; + +#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ @@ -2662,7 +3173,6 @@ + + err = ops->open ? ops->open(rtc->class_dev.dev) : 0; + if (err == 0) { -+ + spin_lock_irq(&rtc->irq_lock); + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); @@ -2738,8 +3248,8 @@ + return (data != 0) ? (POLLIN | POLLRDNORM) : 0; +} + -+static int rtc_dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, -+ unsigned long arg) ++static int rtc_dev_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct class_device *class_dev = file->private_data; @@ -2774,15 +3284,16 @@ + + switch (cmd) { + case RTC_ALM_READ: -+ if ((err = rtc_read_alarm(class_dev, &alarm)) < 0) ++ err = rtc_read_alarm(class_dev, &alarm); ++ if (err < 0) + return err; + -+ if ((err = copy_to_user(uarg, &alarm.time, sizeof(tm)))) ++ if (copy_to_user(uarg, &alarm.time, sizeof(tm))) + return -EFAULT; + break; + + case RTC_ALM_SET: -+ if ((err = copy_from_user(&alarm.time, uarg, sizeof(tm)))) ++ if (copy_from_user(&alarm.time, uarg, sizeof(tm))) + return -EFAULT; + + alarm.enabled = 0; @@ -2797,10 +3308,11 @@ + break; + + case RTC_RD_TIME: -+ if ((err = rtc_read_time(class_dev, &tm)) < 0) ++ err = rtc_read_time(class_dev, &tm); ++ if (err < 0) + return err; + -+ if ((err = copy_to_user(uarg, &tm, sizeof(tm)))) ++ if (copy_to_user(uarg, &tm, sizeof(tm))) + return -EFAULT; + break; + @@ -2808,7 +3320,7 @@ + if (!capable(CAP_SYS_TIME)) + return -EACCES; + -+ if ((err = copy_from_user(&tm, uarg, sizeof(tm)))) ++ if (copy_from_user(&tm, uarg, sizeof(tm))) + return -EFAULT; + + err = rtc_set_time(class_dev, &tm); @@ -2837,17 +3349,18 @@ + break; +#endif + case RTC_WKALM_SET: -+ if ((err = copy_from_user(&alarm, uarg, sizeof(alarm)))) ++ if (copy_from_user(&alarm, uarg, sizeof(alarm))) + return -EFAULT; + + err = rtc_set_alarm(class_dev, &alarm); + break; + + case RTC_WKALM_RD: -+ if ((err = rtc_read_alarm(class_dev, &alarm)) < 0) ++ err = rtc_read_alarm(class_dev, &alarm); ++ if (err < 0) + return err; + -+ if ((err = copy_to_user(uarg, &alarm, sizeof(alarm)))) ++ if (copy_to_user(uarg, &alarm, sizeof(alarm))) + return -EFAULT; + break; + @@ -2887,17 +3400,12 @@ + .fasync = rtc_dev_fasync, +}; + -+static ssize_t rtc_dev_show_dev(struct class_device *class_dev, char *buf) -+{ -+ return print_dev_t(buf, class_dev->devt); -+} -+static CLASS_DEVICE_ATTR(dev, S_IRUGO, rtc_dev_show_dev, NULL); -+ +/* insertion/removal hooks */ + +static int rtc_dev_add_device(struct class_device *class_dev, + struct class_interface *class_intf) +{ ++ int err = 0; + struct rtc_device *rtc = to_rtc_device(class_dev); + + if (rtc->id >= RTC_DEV_MAX) { @@ -2911,29 +3419,34 @@ + + cdev_init(&rtc->char_dev, &rtc_dev_fops); + rtc->char_dev.owner = rtc->owner; -+ class_dev->devt = MKDEV(MAJOR(rtc_devt), rtc->id); + -+ if (cdev_add(&rtc->char_dev, class_dev->devt, 1)) { ++ if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) { + cdev_del(&rtc->char_dev); -+ + dev_err(class_dev->dev, + "failed to add char device %d:%d\n", -+ MAJOR(class_dev->devt), -+ MINOR(class_dev->devt)); -+ -+ class_dev->devt = MKDEV(0, 0); ++ MAJOR(rtc_devt), rtc->id); + return -ENODEV; + } + -+ class_device_create_file(class_dev, &class_device_attr_dev); ++ rtc->rtc_dev = class_device_create(rtc_dev_class, NULL, ++ MKDEV(MAJOR(rtc_devt), rtc->id), ++ class_dev->dev, "rtc%d", rtc->id); ++ if (IS_ERR(rtc->rtc_dev)) { ++ dev_err(class_dev->dev, "cannot create rtc_dev device\n"); ++ err = PTR_ERR(rtc->rtc_dev); ++ goto err_cdev_del; ++ } + + dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n", -+ MAJOR(class_dev->devt), -+ MINOR(class_dev->devt)); -+ -+ kobject_uevent(&class_dev->kobj, KOBJ_ADD); ++ MAJOR(rtc->rtc_dev->devt), ++ MINOR(rtc->rtc_dev->devt)); + + return 0; ++ ++err_cdev_del: ++ ++ cdev_del(&rtc->char_dev); ++ return err; +} + +static void rtc_dev_remove_device(struct class_device *class_dev, @@ -2941,23 +3454,19 @@ +{ + struct rtc_device *rtc = to_rtc_device(class_dev); + -+ class_device_remove_file(class_dev, &class_device_attr_dev); -+ -+ if (MAJOR(class_dev->devt)) { ++ if (rtc->rtc_dev) { + dev_dbg(class_dev->dev, "removing char %d:%d\n", -+ MAJOR(class_dev->devt), -+ MINOR(class_dev->devt)); -+ cdev_del(&rtc->char_dev); -+ -+ kobject_uevent(&class_dev->kobj, KOBJ_REMOVE); ++ MAJOR(rtc->rtc_dev->devt), ++ MINOR(rtc->rtc_dev->devt)); + -+ class_dev->devt = MKDEV(0, 0); ++ class_device_unregister(rtc->rtc_dev); ++ cdev_del(&rtc->char_dev); + } +} + +/* interface registration */ + -+struct class_interface rtc_dev_interface = { ++static struct class_interface rtc_dev_interface = { + .add = &rtc_dev_add_device, + .remove = &rtc_dev_remove_device, +}; @@ -2966,26 +3475,39 @@ +{ + int err; + -+ if ((err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc")) < 0) { ++ rtc_dev_class = class_create(THIS_MODULE, "rtc-dev"); ++ if (IS_ERR(rtc_dev_class)) ++ return PTR_ERR(rtc_dev_class); ++ ++ err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); ++ if (err < 0) { + printk(KERN_ERR "%s: failed to allocate char dev region\n", + __FILE__); -+ return err; ++ goto err_destroy_class; + } + -+ if ((err = rtc_interface_register(&rtc_dev_interface)) < 0) { ++ err = rtc_interface_register(&rtc_dev_interface); ++ if (err < 0) { + printk(KERN_ERR "%s: failed to register the interface\n", + __FILE__); -+ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); -+ return err; ++ goto err_unregister_chrdev; + } + + return 0; ++ ++err_unregister_chrdev: ++ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); ++ ++err_destroy_class: ++ class_destroy(rtc_dev_class); ++ ++ return err; +} + +static void __exit rtc_dev_exit(void) +{ + class_interface_unregister(&rtc_dev_interface); -+ ++ class_destroy(rtc_dev_class); + unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); +} + @@ -2996,7 +3518,7 @@ +MODULE_DESCRIPTION("RTC class dev interface"); +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-x1205.c 2006-02-21 00:36:43.000000000 +0100 ++++ linux-ixp4xx/drivers/rtc/rtc-x1205.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,619 @@ +/* + * An i2c driver for the Xicor/Intersil X1205 RTC @@ -3374,7 +3896,7 @@ + if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { + dev_err(&client->adapter->dev, + "%s: could not read register %x\n", -+ __FUNCTION__, probe_zero_pattern[i]); ++ __FUNCTION__, probe_zero_pattern[i]); + + return -EIO; + } @@ -3618,8 +4140,8 @@ +module_init(x1205_init); +module_exit(x1205_exit); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-test.c 2006-02-21 00:36:43.000000000 +0100 -@@ -0,0 +1,206 @@ ++++ linux-ixp4xx/drivers/rtc/rtc-test.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,205 @@ +/* + * An RTC test device/driver + * Copyright (C) 2005 Tower Technologies @@ -3636,8 +4158,7 @@ +#include <linux/rtc.h> +#include <linux/platform_device.h> + -+struct platform_device *test0 = NULL, *test1 = NULL; -+ ++static struct platform_device *test0 = NULL, *test1 = NULL; + +static int test_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *alrm) @@ -3827,7 +4348,7 @@ +module_init(test_init); +module_exit(test_exit); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-ds1672.c 2006-02-21 00:36:43.000000000 +0100 ++++ linux-ixp4xx/drivers/rtc/rtc-ds1672.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,233 @@ +/* + * An rtc/i2c driver for the Dallas DS1672 @@ -3877,11 +4398,11 @@ + { client->addr, I2C_M_RD, 4, buf }, /* read date */ + }; + -+ /* read date registers */ -+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { -+ dev_err(&client->dev, "%s: read error\n", __FUNCTION__); -+ return -EIO; -+ } ++ /* read date registers */ ++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { ++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__); ++ return -EIO; ++ } + + dev_dbg(&client->dev, + "%s: raw read data - counters=%02x,%02x,%02x,%02x\n" @@ -4063,7 +4584,7 @@ +module_init(ds1672_init); +module_exit(ds1672_exit); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-pcf8563.c 2006-02-21 00:36:43.000000000 +0100 ++++ linux-ixp4xx/drivers/rtc/rtc-pcf8563.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,355 @@ +/* + * An I2C driver for the Philips PCF8563 RTC @@ -4421,7 +4942,7 @@ +module_init(pcf8563_init); +module_exit(pcf8563_exit); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-rtc/drivers/rtc/rtc-rs5c372.c 2006-02-21 00:36:43.000000000 +0100 ++++ linux-ixp4xx/drivers/rtc/rtc-rs5c372.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,295 @@ +/* + * An I2C driver for the Ricoh RS5C372 RTC @@ -4718,3 +5239,608 @@ +MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/rtc/rtc-ep93xx.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,163 @@ ++/* ++ * A driver for the RTC embedded in the Cirrus Logic EP93XX processors ++ * Copyright (c) 2006 Tower Technologies ++ * ++ * Author: Alessandro Zummo <a.zummo@towertech.it> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/module.h> ++#include <linux/rtc.h> ++#include <linux/platform_device.h> ++#include <asm/hardware.h> ++ ++#define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x)) ++#define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000) ++#define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C) ++#define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108) ++ ++#define DRV_VERSION "0.2" ++ ++static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, ++ unsigned short *delete) ++{ ++ unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); ++ ++ if (preload) ++ *preload = comp & 0xffff; ++ ++ if (delete) ++ *delete = (comp >> 16) & 0x1f; ++ ++ return 0; ++} ++ ++static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ unsigned long time = __raw_readl(EP93XX_RTC_DATA); ++ ++ rtc_time_to_tm(time, tm); ++ return 0; ++} ++ ++static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) ++{ ++ __raw_writel(secs + 1, EP93XX_RTC_LOAD); ++ return 0; ++} ++ ++static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ int err; ++ unsigned long secs; ++ ++ err = rtc_tm_to_time(tm, &secs); ++ if (err != 0) ++ return err; ++ ++ return ep93xx_rtc_set_mmss(dev, secs); ++} ++ ++static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) ++{ ++ unsigned short preload, delete; ++ ++ ep93xx_get_swcomp(dev, &preload, &delete); ++ ++ seq_printf(seq, "24hr\t\t: yes\n"); ++ seq_printf(seq, "preload\t\t: %d\n", preload); ++ seq_printf(seq, "delete\t\t: %d\n", delete); ++ ++ return 0; ++} ++ ++static struct rtc_class_ops ep93xx_rtc_ops = { ++ .read_time = ep93xx_rtc_read_time, ++ .set_time = ep93xx_rtc_set_time, ++ .set_mmss = ep93xx_rtc_set_mmss, ++ .proc = ep93xx_rtc_proc, ++}; ++ ++static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned short preload; ++ ++ ep93xx_get_swcomp(dev, &preload, NULL); ++ ++ return sprintf(buf, "%d\n", preload); ++} ++static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); ++ ++static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned short delete; ++ ++ ep93xx_get_swcomp(dev, NULL, &delete); ++ ++ return sprintf(buf, "%d\n", delete); ++} ++static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); ++ ++ ++static int __devinit ep93xx_rtc_probe(struct platform_device *dev) ++{ ++ struct rtc_device *rtc = rtc_device_register("ep93xx", ++ &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); ++ ++ if (IS_ERR(rtc)) { ++ dev_err(&dev->dev, "unable to register\n"); ++ return PTR_ERR(rtc); ++ } ++ ++ platform_set_drvdata(dev, rtc); ++ ++ device_create_file(&dev->dev, &dev_attr_comp_preload); ++ device_create_file(&dev->dev, &dev_attr_comp_delete); ++ ++ return 0; ++} ++ ++static int __devexit ep93xx_rtc_remove(struct platform_device *dev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(dev); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ ++ platform_set_drvdata(dev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver ep93xx_rtc_platform_driver = { ++ .driver = { ++ .name = "ep93xx-rtc", ++ .owner = THIS_MODULE, ++ }, ++ .probe = ep93xx_rtc_probe, ++ .remove = __devexit_p(ep93xx_rtc_remove), ++}; ++ ++static int __init ep93xx_rtc_init(void) ++{ ++ return platform_driver_register(&ep93xx_rtc_platform_driver); ++} ++ ++static void __exit ep93xx_rtc_exit(void) ++{ ++ platform_driver_unregister(&ep93xx_rtc_platform_driver); ++} ++ ++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); ++MODULE_DESCRIPTION("EP93XX RTC driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++module_init(ep93xx_rtc_init); ++module_exit(ep93xx_rtc_exit); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/drivers/rtc/rtc-sa1100.c 2006-03-08 01:59:26.000000000 +0100 +@@ -0,0 +1,392 @@ ++/* ++ * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx ++ * ++ * Copyright (c) 2000 Nils Faerber ++ * ++ * Based on rtc.c by Paul Gortmaker ++ * ++ * Original Driver by Nils Faerber <nils@kernelconcepts.de> ++ * ++ * Modifications from: ++ * CIH <cih@coventive.com> ++ * Nicolas Pitre <nico@cam.org> ++ * Andrew Christian <andrew.christian@hp.com> ++ * ++ * Converted to the RTC subsystem and Driver Model ++ * by Richard Purdie <rpurdie@rpsys.net> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/platform_device.h> ++#include <linux/module.h> ++#include <linux/rtc.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++ ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/rtc.h> ++ ++#ifdef CONFIG_ARCH_PXA ++#include <asm/arch/pxa-regs.h> ++#endif ++ ++#define TIMER_FREQ CLOCK_TICK_RATE ++#define RTC_DEF_DIVIDER 32768 - 1 ++#define RTC_DEF_TRIM 0 ++ ++static unsigned long rtc_freq = 1024; ++static struct rtc_time rtc_alarm; ++static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED; ++ ++static int rtc_update_alarm(struct rtc_time *alrm) ++{ ++ struct rtc_time alarm_tm, now_tm; ++ unsigned long now, time; ++ int ret; ++ ++ do { ++ now = RCNR; ++ rtc_time_to_tm(now, &now_tm); ++ rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); ++ ret = rtc_tm_to_time(&alarm_tm, &time); ++ if (ret != 0) ++ break; ++ ++ RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); ++ RTAR = time; ++ } while (now != RCNR); ++ ++ return ret; ++} ++ ++static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ struct platform_device *pdev = to_platform_device(dev_id); ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ unsigned int rtsr; ++ unsigned long events = 0; ++ ++ spin_lock(&sa1100_rtc_lock); ++ ++ rtsr = RTSR; ++ /* clear interrupt sources */ ++ RTSR = 0; ++ RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); ++ ++ /* clear alarm interrupt if it has occurred */ ++ if (rtsr & RTSR_AL) ++ rtsr &= ~RTSR_ALE; ++ RTSR = rtsr & (RTSR_ALE | RTSR_HZE); ++ ++ /* update irq data & counter */ ++ if (rtsr & RTSR_AL) ++ events |= RTC_AF | RTC_IRQF; ++ if (rtsr & RTSR_HZ) ++ events |= RTC_UF | RTC_IRQF; ++ ++ rtc_update_irq(&rtc->class_dev, 1, events); ++ ++ if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) ++ rtc_update_alarm(&rtc_alarm); ++ ++ spin_unlock(&sa1100_rtc_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static int rtc_timer1_count; ++ ++static irqreturn_t timer1_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ struct platform_device *pdev = to_platform_device(dev_id); ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ ++ /* ++ * If we match for the first time, rtc_timer1_count will be 1. ++ * Otherwise, we wrapped around (very unlikely but ++ * still possible) so compute the amount of missed periods. ++ * The match reg is updated only when the data is actually retrieved ++ * to avoid unnecessary interrupts. ++ */ ++ OSSR = OSSR_M1; /* clear match on timer1 */ ++ ++ rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF); ++ ++ if (rtc_timer1_count == 1) ++ rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); ++ ++ return IRQ_HANDLED; ++} ++ ++static int sa1100_rtc_read_callback(struct device *dev, int data) ++{ ++ if (data & RTC_PF) { ++ /* interpolate missed periods and set match for the next */ ++ unsigned long period = TIMER_FREQ/rtc_freq; ++ unsigned long oscr = OSCR; ++ unsigned long osmr1 = OSMR1; ++ unsigned long missed = (oscr - osmr1)/period; ++ data += missed << 8; ++ OSSR = OSSR_M1; /* clear match on timer 1 */ ++ OSMR1 = osmr1 + (missed + 1)*period; ++ /* Ensure we didn't miss another match in the mean time. ++ * Here we compare (match - OSCR) 8 instead of 0 -- ++ * see comment in pxa_timer_interrupt() for explanation. ++ */ ++ while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { ++ data += 0x100; ++ OSSR = OSSR_M1; /* clear match on timer 1 */ ++ OSMR1 = osmr1 + period; ++ } ++ } ++ return data; ++} ++ ++static int sa1100_rtc_open(struct device *dev) ++{ ++ int ret; ++ ++ ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT, ++ "rtc 1Hz", dev); ++ if (ret) { ++ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz); ++ goto fail_ui; ++ } ++ ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT, ++ "rtc Alrm", dev); ++ if (ret) { ++ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm); ++ goto fail_ai; ++ } ++ ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, ++ "rtc timer", dev); ++ if (ret) { ++ printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1); ++ goto fail_pi; ++ } ++ return 0; ++ ++ fail_pi: ++ free_irq(IRQ_RTCAlrm, NULL); ++ fail_ai: ++ free_irq(IRQ_RTC1Hz, NULL); ++ fail_ui: ++ return ret; ++} ++ ++static void sa1100_rtc_release(struct device *dev) ++{ ++ spin_lock_irq(&sa1100_rtc_lock); ++ RTSR = 0; ++ OIER &= ~OIER_E1; ++ OSSR = OSSR_M1; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ ++ free_irq(IRQ_OST1, dev); ++ free_irq(IRQ_RTCAlrm, dev); ++ free_irq(IRQ_RTC1Hz, dev); ++} ++ ++ ++static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, ++ unsigned long arg) ++{ ++ switch(cmd) { ++ case RTC_AIE_OFF: ++ spin_lock_irq(&sa1100_rtc_lock); ++ RTSR &= ~RTSR_ALE; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_AIE_ON: ++ spin_lock_irq(&sa1100_rtc_lock); ++ RTSR |= RTSR_ALE; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_UIE_OFF: ++ spin_lock_irq(&sa1100_rtc_lock); ++ RTSR &= ~RTSR_HZE; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_UIE_ON: ++ spin_lock_irq(&sa1100_rtc_lock); ++ RTSR |= RTSR_HZE; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_PIE_OFF: ++ spin_lock_irq(&sa1100_rtc_lock); ++ OIER &= ~OIER_E1; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_PIE_ON: ++ if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) ++ return -EACCES; ++ spin_lock_irq(&sa1100_rtc_lock); ++ OSMR1 = TIMER_FREQ/rtc_freq + OSCR; ++ OIER |= OIER_E1; ++ rtc_timer1_count = 1; ++ spin_unlock_irq(&sa1100_rtc_lock); ++ return 0; ++ case RTC_IRQP_READ: ++ return put_user(rtc_freq, (unsigned long *)arg); ++ case RTC_IRQP_SET: ++ if (arg < 1 || arg > TIMER_FREQ) ++ return -EINVAL; ++ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) ++ return -EACCES; ++ rtc_freq = arg; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ rtc_time_to_tm(RCNR, tm); ++ return 0; ++} ++ ++static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ unsigned long time; ++ int ret; ++ ++ ret = rtc_tm_to_time(tm, &time); ++ if (ret == 0) ++ RCNR = time; ++ return ret; ++} ++ ++static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); ++ alrm->pending = RTSR & RTSR_AL ? 1 : 0; ++ return 0; ++} ++ ++static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ int ret; ++ ++ spin_lock_irq(&sa1100_rtc_lock); ++ ret = rtc_update_alarm(&alrm->time); ++ if (ret == 0) { ++ memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time)); ++ ++ if (alrm->enabled) ++ enable_irq_wake(IRQ_RTCAlrm); ++ else ++ disable_irq_wake(IRQ_RTCAlrm); ++ } ++ spin_unlock_irq(&sa1100_rtc_lock); ++ ++ return ret; ++} ++ ++static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) ++{ ++ seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR); ++ seq_printf(seq, "alarm_IRQ\t: %s\n", ++ (RTSR & RTSR_ALE) ? "yes" : "no" ); ++ seq_printf(seq, "update_IRQ\t: %s\n", ++ (RTSR & RTSR_HZE) ? "yes" : "no"); ++ seq_printf(seq, "periodic_IRQ\t: %s\n", ++ (OIER & OIER_E1) ? "yes" : "no"); ++ seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); ++ ++ return 0; ++} ++ ++static struct rtc_class_ops sa1100_rtc_ops = { ++ .open = sa1100_rtc_open, ++ .read_callback = sa1100_rtc_read_callback, ++ .release = sa1100_rtc_release, ++ .ioctl = sa1100_rtc_ioctl, ++ .read_time = sa1100_rtc_read_time, ++ .set_time = sa1100_rtc_set_time, ++ .read_alarm = sa1100_rtc_read_alarm, ++ .set_alarm = sa1100_rtc_set_alarm, ++ .proc = sa1100_rtc_proc, ++}; ++ ++static int sa1100_rtc_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc; ++ ++ /* ++ * According to the manual we should be able to let RTTR be zero ++ * and then a default diviser for a 32.768KHz clock is used. ++ * Apparently this doesn't work, at least for my SA1110 rev 5. ++ * If the clock divider is uninitialized then reset it to the ++ * default value to get the 1Hz clock. ++ */ ++ if (RTTR == 0) { ++ RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); ++ printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); ++ /* The current RTC value probably doesn't make sense either */ ++ RCNR = 0; ++ } ++ ++ rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, ++ THIS_MODULE); ++ ++ if (IS_ERR(rtc)) { ++ dev_err(&pdev->dev, "Unable to register the RTC device\n"); ++ return PTR_ERR(rtc); ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n"); ++ ++ return 0; ++} ++ ++static int sa1100_rtc_remove(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(pdev); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ ++ return 0; ++} ++ ++static struct platform_driver sa1100_rtc_driver = { ++ .probe = sa1100_rtc_probe, ++ .remove = sa1100_rtc_remove, ++ .driver = { ++ .name = "sa1100-rtc", ++ }, ++}; ++ ++static int __init sa1100_rtc_init(void) ++{ ++ return platform_driver_register(&sa1100_rtc_driver); ++} ++ ++static void __exit sa1100_rtc_exit(void) ++{ ++ platform_driver_unregister(&sa1100_rtc_driver); ++} ++ ++module_init(sa1100_rtc_init); ++module_exit(sa1100_rtc_exit); ++ ++MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); ++MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); ++MODULE_LICENSE("GPL"); +--- linux-ixp4xx.orig/arch/arm/mach-pxa/generic.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-pxa/generic.c 2006-03-08 01:59:26.000000000 +0100 +@@ -319,6 +319,11 @@ void __init pxa_set_ficp_info(struct pxa + pxaficp_device.dev.platform_data = info; + } + ++static struct platform_device pxartc_device = { ++ .name = "sa1100-rtc", ++ .id = -1, ++}; ++ + static struct platform_device *devices[] __initdata = { + &pxamci_device, + &udc_device, +@@ -329,6 +334,7 @@ static struct platform_device *devices[] + &pxaficp_device, + &i2c_device, + &i2s_device, ++ &pxartc_device, + }; + + static int __init pxa_init(void) +--- linux-ixp4xx.orig/arch/arm/mach-sa1100/generic.c 2006-03-08 01:59:09.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-sa1100/generic.c 2006-03-08 01:59:26.000000000 +0100 +@@ -324,6 +324,11 @@ void sa11x0_set_irda_data(struct irda_pl + sa11x0ir_device.dev.platform_data = irda; + } + ++static struct platform_device sa11x0rtc_device = { ++ .name = "sa1100-rtc", ++ .id = -1, ++}; ++ + static struct platform_device *sa11x0_devices[] __initdata = { + &sa11x0udc_device, + &sa11x0uart1_device, +@@ -333,6 +338,7 @@ static struct platform_device *sa11x0_de + &sa11x0pcmcia_device, + &sa11x0fb_device, + &sa11x0mtd_device, ++ &sa11x0rtc_device, + }; + + static int __init sa1100_init(void) diff --git a/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-new-notifier.patch b/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-new-notifier.patch new file mode 100644 index 0000000000..2de12021a5 --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-new-notifier.patch @@ -0,0 +1,209 @@ +Add EEPROM notifiers + +These help board level code by allowing a callback when EEPROMs are +loaded, this permits system level configuration to be loaded from the +EEPROM. This is particularly useful when the ethernet MAC ids are +stored in EEPROM and when the ethernet hardware is generic (so it +has no board level knowledge), then the MACs can be loaded into +the 'maclist' code and read out by the ethernet config. + +Signed-off-by: John Bowler <jbowler@acm.org> + +--- + drivers/i2c/chips/eeprom.c | 63 ++++++++++++++++++++++++++------------- + include/linux/eeprom.h | 71 +++++++++++++++++++++++++++++++++++++++++++++ + include/linux/notifier.h | 3 + + 3 files changed, 116 insertions(+), 21 deletions(-) + +--- linux-ixp4xx.orig/drivers/i2c/chips/eeprom.c 2006-03-27 03:03:46.000000000 +0200 ++++ linux-ixp4xx/drivers/i2c/chips/eeprom.c 2006-03-27 03:03:47.000000000 +0200 +@@ -25,7 +25,6 @@ + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +- + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/module.h> +@@ -34,6 +33,8 @@ + #include <linux/jiffies.h> + #include <linux/i2c.h> + #include <linux/mutex.h> ++#include <linux/notifier.h> ++#include <linux/eeprom.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, +@@ -42,26 +43,7 @@ static unsigned short normal_i2c[] = { 0 + /* Insmod parameters */ + I2C_CLIENT_INSMOD_1(eeprom); + +- +-/* Size of EEPROM in bytes */ +-#define EEPROM_SIZE 256 +- +-/* possible types of eeprom devices */ +-enum eeprom_nature { +- UNKNOWN, +- VAIO, +-}; +- +-/* Each client has this additional data */ +-struct eeprom_data { +- struct i2c_client client; +- struct mutex update_lock; +- u8 valid; /* bitfield, bit!=0 if slice is valid */ +- unsigned long last_updated[8]; /* In jiffies, 8 slices */ +- u8 data[EEPROM_SIZE]; /* Register values */ +- enum eeprom_nature nature; +-}; +- ++static struct notifier_block *eeprom_chain; + + static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind); + static int eeprom_detach_client(struct i2c_client *client); +@@ -186,6 +168,7 @@ static int eeprom_detect(struct i2c_adap + data->valid = 0; + mutex_init(&data->update_lock); + data->nature = UNKNOWN; ++ data->attr = &eeprom_attr; + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -207,6 +190,9 @@ static int eeprom_detect(struct i2c_adap + /* create the sysfs eeprom file */ + sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + ++ /* call the notifier chain */ ++ notifier_call_chain(&eeprom_chain, EEPROM_REGISTER, data); ++ + return 0; + + exit_kfree: +@@ -228,6 +214,41 @@ static int eeprom_detach_client(struct i + return 0; + } + ++/** ++ * register_eeprom_notifier - register a 'user' of EEPROM devices. ++ * @nb: pointer to notifier info structure ++ * ++ * Registers a callback function to be called upon detection ++ * of an EEPROM device. Detection invokes the 'add' callback ++ * with the kobj of the mutex and a bin_attribute which allows ++ * read from the EEPROM. The intention is that the notifier ++ * will be able to read system configuration from the notifier. ++ * ++ * Only EEPROMs detected *after* the addition of the notifier ++ * are notified. I.e. EEPROMs already known to the system ++ * will not be notified - add the notifier from board level ++ * code! ++ */ ++int register_eeprom_notifier(struct notifier_block *nb) ++{ ++ return notifier_chain_register(&eeprom_chain, nb); ++} ++ ++/** ++ * unregister_eeprom_notifier - unregister a 'user' of EEPROM devices. ++ * @old: pointer to notifier info structure ++ * ++ * Removes a callback function from the list of 'users' to be ++ * notified upon detection of EEPROM devices. ++ */ ++int unregister_eeprom_notifier(struct notifier_block *nb) ++{ ++ return notifier_chain_unregister(&eeprom_chain, nb); ++} ++ ++EXPORT_SYMBOL_GPL(register_eeprom_notifier); ++EXPORT_SYMBOL_GPL(unregister_eeprom_notifier); ++ + static int __init eeprom_init(void) + { + return i2c_add_driver(&eeprom_driver); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-ixp4xx/include/linux/eeprom.h 2006-03-27 03:03:47.000000000 +0200 +@@ -0,0 +1,71 @@ ++#ifndef _LINUX_EEPROM_H ++#define _LINUX_EEPROM_H ++/* ++ * $Id: 45-eeprom-new-notifier.patch,v 1.2 2006/03/27 11:10:19 azummo Exp $ ++ * ++ * Copyright (C) 2006 John Bowler ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __KERNEL__ ++#error This is a kernel header ++#endif ++ ++#include <linux/list.h> ++#include <linux/kobject.h> ++#include <linux/sysfs.h> ++ ++/* Size of EEPROM in bytes */ ++#define EEPROM_SIZE 256 ++ ++/* possible types of eeprom devices */ ++enum eeprom_nature { ++ UNKNOWN, ++ VAIO, ++}; ++ ++/* Each client has this additional data */ ++struct eeprom_data { ++ struct i2c_client client; ++ struct mutex update_lock; ++ u8 valid; /* bitfield, bit!=0 if slice is valid */ ++ unsigned long last_updated[8]; /* In jiffies, 8 slices */ ++ u8 data[EEPROM_SIZE]; /* Register values */ ++ enum eeprom_nature nature; ++ struct bin_attribute *attr; ++}; ++ ++/* ++ * This is very basic. ++ * ++ * If an EEPROM is detected on the I2C bus (this only works for ++ * I2C EEPROMs) the eeprom_notifier::add method is called with ++ * both the I2C information and the kobject for the sysfs ++ * device which has been registers. It is then possible to ++ * read from the device via the bin_attribute::read method ++ * to extract configuration information. ++ * ++ * Register the notifier in the board level code, there is no ++ * need to unregister it but you can if you want (it will save ++ * a little bit or kernel memory to do so). ++ */ ++ ++extern int register_eeprom_notifier(struct notifier_block *nb); ++extern int unregister_eeprom_notifier(struct notifier_block *nb); ++ ++#endif /* _LINUX_EEPROM_H */ +--- linux-ixp4xx.orig/include/linux/notifier.h 2006-03-27 01:33:10.000000000 +0200 ++++ linux-ixp4xx/include/linux/notifier.h 2006-03-27 03:03:47.000000000 +0200 +@@ -72,5 +72,8 @@ extern int notifier_call_chain(struct no + #define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ + #define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ + ++/* eeprom notifier chain */ ++#define EEPROM_REGISTER 0x0001 ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_NOTIFIER_H */ diff --git a/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-notifier.patch b/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-notifier.patch deleted file mode 100644 index 0367477a48..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/45-eeprom-notifier.patch +++ /dev/null @@ -1,184 +0,0 @@ -Add EEPROM notifiers - -These help board level code by allowing a callback when EEPROMs are -loaded, this permits system level configuration to be loaded from the -EEPROM. This is particularly useful when the ethernet MAC ids are -stored in EEPROM and when the ethernet hardware is generic (so it -has no board level knowledge), then the MACs can be loaded into -the 'maclist' code and read out by the ethernet config. - -Signed-off-by: John Bowler <jbowler@acm.org> - ---- linux-2.6.15/drivers/i2c/chips/eeprom.c 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.15/drivers/i2c/chips/eeprom.c 1970-01-01 00:00:00.000000000 +0000 -@@ -25,7 +25,6 @@ - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -- - #include <linux/kernel.h> - #include <linux/init.h> - #include <linux/module.h> -@@ -33,6 +32,9 @@ - #include <linux/sched.h> - #include <linux/jiffies.h> - #include <linux/i2c.h> -+#include <linux/notifier.h> -+ -+#include <linux/eeprom.h> - - /* Addresses to scan */ - static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, -@@ -41,6 +43,9 @@ static unsigned short normal_i2c[] = { 0 - /* Insmod parameters */ - I2C_CLIENT_INSMOD_1(eeprom); - -+/* Notifier list */ -+static DECLARE_MUTEX(eeprom_notifier_mutex); -+static LIST_HEAD(eeprom_notifiers); - - /* Size of EEPROM in bytes */ - #define EEPROM_SIZE 256 -@@ -160,6 +165,7 @@ static int eeprom_detect(struct i2c_adap - struct i2c_client *new_client; - struct eeprom_data *data; - int err = 0; -+ struct list_head *this; - - /* There are three ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) -@@ -196,7 +202,7 @@ static int eeprom_detect(struct i2c_adap - - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" prefix as the signature. */ -- if (address == 0x57) { -+ if (list_empty(&eeprom_notifiers) && address == 0x57) { - if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P' - && i2c_smbus_read_byte(new_client) == 'C' - && i2c_smbus_read_byte(new_client) == 'G' -@@ -210,6 +216,14 @@ static int eeprom_detect(struct i2c_adap - /* create the sysfs eeprom file */ - sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); - -+ /* Call each notifier callback */ -+ down(&eeprom_notifier_mutex); -+ list_for_each(this, &eeprom_notifiers) { -+ struct eeprom_notifier *not = list_entry(this, struct eeprom_notifier, list); -+ not->add(address, kind, &new_client->dev.kobj, &eeprom_attr); -+ } -+ up(&eeprom_notifier_mutex); -+ - return 0; - - exit_kfree: -@@ -231,6 +245,51 @@ static int eeprom_detach_client(struct i - return 0; - } - -+/** -+ * register_eeprom_user - register a 'user' of EEPROM devices. -+ * @new: pointer to notifier info structure -+ * -+ * Registers a callback function to be called upon detection -+ * of an EEPROM device. Detection invokes the 'add' callback -+ * with the kobj of the mutex and a bin_attribute which allows -+ * read from the EEPROM. The intention is that the notifier -+ * will be able to read system configuration from the notifier. -+ * -+ * Only EEPROMs detected *after* the addition of the notifier -+ * are notified. I.e. EEPROMs already known to the system -+ * will not be notified - add the notifier from board level -+ * code! -+ */ -+void register_eeprom_user (struct eeprom_notifier *new) -+{ -+ down(&eeprom_notifier_mutex); -+ -+ list_add(&new->list, &eeprom_notifiers); -+ -+ up(&eeprom_notifier_mutex); -+} -+ -+/** -+ * unregister_eeprom_user - unregister a 'user' of EEPROM devices. -+ * @old: pointer to notifier info structure -+ * -+ * Removes a callback function from the list of 'users' to be -+ * notified upon detection of EEPROM devices. -+ */ -+void unregister_eeprom_user (struct eeprom_notifier *old) -+{ -+ down(&eeprom_notifier_mutex); -+ -+ list_del(&old->list); -+ -+ up(&eeprom_notifier_mutex); -+} -+ -+ -+EXPORT_SYMBOL(register_eeprom_user); -+EXPORT_SYMBOL(unregister_eeprom_user); -+ -+ - static int __init eeprom_init(void) - { - return i2c_add_driver(&eeprom_driver); ---- linux-2.6.15/include/linux/eeprom.h 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.15/include/linux/eeprom.h 1970-01-01 00:00:00.000000000 +0000 -@@ -0,0 +1,56 @@ -+#ifndef _LINUX_EEPROM_H -+#define _LINUX_EEPROM_H -+/* -+ * $Id: 45-eeprom-notifier.patch,v 1.1 2006/02/07 00:38:33 azummo Exp $ -+ * -+ * Copyright (C) 2006 John Bowler -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __KERNEL__ -+#error This is a kernel header -+#endif -+ -+#include <linux/list.h> -+#include <linux/kobject.h> -+#include <linux/sysfs.h> -+ -+/* -+ * This is very basic. -+ * -+ * If an EEPROM is detected on the I2C bus (this only works for -+ * I2C EEPROMs) the eeprom_notifier::add method is called with -+ * both the I2C information and the kobject for the sysfs -+ * device which has been registers. It is then possible to -+ * read from the device via the bin_attribute::read method -+ * to extract configuration information. -+ * -+ * Register the notifier in the board level code, there is no -+ * need to unregister it but you can if you want (it will save -+ * a little bit or kernel memory to do so). -+ */ -+struct eeprom_notifier { -+ void (*add)(int address, int kind, struct kobject *kobj, -+ struct bin_attribute *eeprom_attr); -+ struct list_head list; -+}; -+ -+extern void register_eeprom_user (struct eeprom_notifier *new); -+extern void unregister_eeprom_user (struct eeprom_notifier *old); -+ -+#endif /* _LINUX_EEPROM_H */ diff --git a/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch b/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch deleted file mode 100644 index d7fb8e55dc..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/50-i2c-bus-ixp4xx-hwmon.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- - drivers/i2c/busses/i2c-ixp4xx.c | 1 + - 1 file changed, 1 insertion(+) - ---- linux-ixp4xx.orig/drivers/i2c/busses/i2c-ixp4xx.c 2006-02-11 15:18:29.000000000 +0100 -+++ linux-ixp4xx/drivers/i2c/busses/i2c-ixp4xx.c 2006-02-18 16:20:12.000000000 +0100 -@@ -126,6 +126,7 @@ static int ixp4xx_i2c_probe(struct platf - drv_data->algo_data.timeout = 100; - - drv_data->adapter.id = I2C_HW_B_IXP4XX; -+ drv_data->adapter.class = I2C_CLASS_HWMON; - strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - I2C_NAME_SIZE); - drv_data->adapter.algo_data = &drv_data->algo_data; diff --git a/packages/linux/ixp4xx-kernel/2.6.16/70-artop-latency.patch b/packages/linux/ixp4xx-kernel/2.6.16/70-artop-latency.patch deleted file mode 100644 index ad3ad11999..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/70-artop-latency.patch +++ /dev/null @@ -1,27 +0,0 @@ -On some controllers the pci latency timer -default value does not allow burst mode. -This patch fixes the latency value if it -is <= 0x80. - -Signed-off-by: Alessandro Zummo <a.zummo@towertech.it> - ---- - drivers/scsi/pata_artop.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- linux-ixp4xx.orig/drivers/scsi/pata_artop.c 2006-02-21 02:53:43.000000000 +0100 -+++ linux-ixp4xx/drivers/scsi/pata_artop.c 2006-02-21 02:54:01.000000000 +0100 -@@ -450,6 +450,13 @@ static int artop_init_one (struct pci_de - pci_read_config_byte(pdev, 0x49, ®); - pci_write_config_byte(pdev, 0x49, reg & ~ 0x30); - -+ /* PCI latency must be > 0x80 for burst mode, tweak it -+ * if required. -+ */ -+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, ®); -+ if (reg <= 0x80) -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90); -+ - /* Enable IRQ output and burst mode */ - pci_read_config_byte(pdev, 0x4a, ®); - pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80); diff --git a/packages/linux/ixp4xx-kernel/2.6.16/75-dsmg600.patch b/packages/linux/ixp4xx-kernel/2.6.16/75-dsmg600.patch index 05d467d0be..3603bd3ca8 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/75-dsmg600.patch +++ b/packages/linux/ixp4xx-kernel/2.6.16/75-dsmg600.patch @@ -9,9 +9,9 @@ include/asm-arm/arch-ixp4xx/irqs.h | 10 ++ 8 files changed, 296 insertions(+) ---- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/Kconfig 2006-02-23 18:29:02.000000000 +0100 -+++ linux-ixp4xx/arch/arm/mach-ixp4xx/Kconfig 2006-02-23 18:29:11.000000000 +0100 -@@ -85,6 +85,14 @@ config MACH_NAS100D +--- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/Kconfig 2006-03-18 18:10:31.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/Kconfig 2006-03-18 18:10:34.000000000 +0100 +@@ -83,6 +83,14 @@ config MACH_NAS100D NAS 100d device. For more information on this platform, see http://www.nslu2-linux.org/wiki/NAS100d/HomePage @@ -27,7 +27,7 @@ # Avila and IXDP share the same source for now. Will change in future # --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-ixp4xx/arch/arm/mach-ixp4xx/dsmg600-pci.c 2006-02-23 18:29:11.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/dsmg600-pci.c 2006-03-18 18:10:34.000000000 +0100 @@ -0,0 +1,74 @@ +/* + * DSM-G600 board-level PCI initialization @@ -104,7 +104,7 @@ + +subsys_initcall(dsmg600_pci_init); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-ixp4xx/arch/arm/mach-ixp4xx/dsmg600-setup.c 2006-02-23 18:29:11.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/dsmg600-setup.c 2006-03-18 18:10:34.000000000 +0100 @@ -0,0 +1,139 @@ +/* + * DSM-G600 board-setup @@ -245,15 +245,15 @@ + .timer = &ixp4xx_timer, + .init_machine = dsmg600_init, +MACHINE_END ---- linux-ixp4xx.orig/arch/arm/tools/mach-types 2006-02-23 18:29:02.000000000 +0100 -+++ linux-ixp4xx/arch/arm/tools/mach-types 2006-02-23 18:29:39.000000000 +0100 +--- linux-ixp4xx.orig/arch/arm/tools/mach-types 2006-03-18 18:10:31.000000000 +0100 ++++ linux-ixp4xx/arch/arm/tools/mach-types 2006-03-18 18:10:34.000000000 +0100 @@ -969,3 +969,4 @@ mxc300_30ads MACH_MXC30030ADS MXC30030A fujitsu_wimaxsoc MACH_FUJITSU_WIMAXSOC FUJITSU_WIMAXSOC 956 dualpcmodem MACH_DUALPCMODEM DUALPCMODEM 957 gesbc9312 MACH_GESBC9312 GESBC9312 958 +dsmg600 MACH_DSMG600 DSMG600 964 --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/dsmg600.h 2006-02-23 18:29:11.000000000 +0100 ++++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/dsmg600.h 2006-03-18 18:10:34.000000000 +0100 @@ -0,0 +1,62 @@ +/* + * DSM-G600 platform specific definitions @@ -317,16 +317,16 @@ +#define DSMG600_IRQ_RSTBTN IRQ_IXP4XX_GPIO3 + +#define DSMG600_GPIO_PWROFF DSMG600_GPIO2 /* power off */ ---- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/Makefile 2006-02-23 18:29:02.000000000 +0100 -+++ linux-ixp4xx/arch/arm/mach-ixp4xx/Makefile 2006-02-23 18:29:11.000000000 +0100 +--- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/Makefile 2006-03-18 18:10:31.000000000 +0100 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/Makefile 2006-03-18 18:10:34.000000000 +0100 @@ -10,4 +10,5 @@ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote- obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o obj-$(CONFIG_MACH_NAS100D) += nas100d-pci.o nas100d-setup.o nas100d-power.o +obj-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o dsmg600-setup.o ---- linux-ixp4xx.orig/include/asm-arm/arch-ixp4xx/hardware.h 2006-02-23 18:29:02.000000000 +0100 -+++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/hardware.h 2006-02-23 18:29:11.000000000 +0100 +--- linux-ixp4xx.orig/include/asm-arm/arch-ixp4xx/hardware.h 2006-03-18 18:10:31.000000000 +0100 ++++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/hardware.h 2006-03-18 18:10:34.000000000 +0100 @@ -46,5 +46,6 @@ extern unsigned int processor_id; #include "prpmc1100.h" #include "nslu2.h" @@ -334,8 +334,8 @@ +#include "dsmg600.h" #endif /* _ASM_ARCH_HARDWARE_H */ ---- linux-ixp4xx.orig/include/asm-arm/arch-ixp4xx/irqs.h 2006-02-23 18:29:02.000000000 +0100 -+++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/irqs.h 2006-02-23 18:29:11.000000000 +0100 +--- linux-ixp4xx.orig/include/asm-arm/arch-ixp4xx/irqs.h 2006-03-18 18:10:31.000000000 +0100 ++++ linux-ixp4xx/include/asm-arm/arch-ixp4xx/irqs.h 2006-03-18 18:10:34.000000000 +0100 @@ -109,4 +109,14 @@ #define IRQ_NAS100D_PCI_INTD IRQ_IXP4XX_GPIO8 #define IRQ_NAS100D_PCI_INTE IRQ_IXP4XX_GPIO7 @@ -343,11 +343,11 @@ +/* + * D-Link DSM-G600 board IRQs + */ -+#define IRQ_DSMG600_PCI_INTA IRQ_IXP4XX_GPIO11 -+#define IRQ_DSMG600_PCI_INTB IRQ_IXP4XX_GPIO10 -+#define IRQ_DSMG600_PCI_INTC IRQ_IXP4XX_GPIO9 -+#define IRQ_DSMG600_PCI_INTD IRQ_IXP4XX_GPIO8 -+#define IRQ_DSMG600_PCI_INTE IRQ_IXP4XX_GPIO7 -+#define IRQ_DSMG600_PCI_INTF IRQ_IXP4XX_GPIO6 ++#define IRQ_DSMG600_PCI_INTA IRQ_IXP4XX_GPIO11 ++#define IRQ_DSMG600_PCI_INTB IRQ_IXP4XX_GPIO10 ++#define IRQ_DSMG600_PCI_INTC IRQ_IXP4XX_GPIO9 ++#define IRQ_DSMG600_PCI_INTD IRQ_IXP4XX_GPIO8 ++#define IRQ_DSMG600_PCI_INTE IRQ_IXP4XX_GPIO7 ++#define IRQ_DSMG600_PCI_INTF IRQ_IXP4XX_GPIO6 + #endif diff --git a/packages/linux/ixp4xx-kernel/2.6.16/82-nas100d-power.patch b/packages/linux/ixp4xx-kernel/2.6.16/82-nas100d-power.patch deleted file mode 100644 index 4ce02c907f..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/82-nas100d-power.patch +++ /dev/null @@ -1,15 +0,0 @@ - arch/arm/mach-ixp4xx/nas100d-power.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- linux-nslu2.orig/arch/arm/mach-ixp4xx/nas100d-power.c 2006-02-06 20:37:01.000000000 +0100 -+++ linux-nslu2/arch/arm/mach-ixp4xx/nas100d-power.c 2006-02-06 22:34:52.000000000 +0100 -@@ -56,6 +56,9 @@ static int __init nas100d_power_init(voi - - static void __exit nas100d_power_exit(void) - { -+ if (!(machine_is_nas100d())) -+ return; -+ - free_irq(NAS100D_RB_IRQ, NULL); - } - diff --git a/packages/linux/ixp4xx-kernel/2.6.16/92-nas100d-mac.patch b/packages/linux/ixp4xx-kernel/2.6.16/92-nas100d-mac.patch new file mode 100644 index 0000000000..59715a024e --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/92-nas100d-mac.patch @@ -0,0 +1,85 @@ + arch/arm/mach-ixp4xx/nas100d-setup.c | 64 +++++++++++++++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + +--- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/nas100d-setup.c 2006-03-27 03:03:47.000000000 +0200 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/nas100d-setup.c 2006-03-27 03:37:23.000000000 +0200 +@@ -15,6 +15,9 @@ + #include <linux/kernel.h> + #include <linux/serial.h> + #include <linux/serial_8250.h> ++#include <linux/mtd/mtd.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> + + #include <asm/mach-types.h> + #include <asm/mach/arch.h> +@@ -110,8 +113,69 @@ static void nas100d_power_off(void) + gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH); + } + ++/* ++ * When the RedBoot config partition is added the MAC address is read from ++ * it. ++ */ ++static struct sockaddr mac; ++ ++static void nas100d_flash_add(struct mtd_info *mtd) { ++ if (strcmp(mtd->name, "RedBoot config") == 0) { ++ size_t retlen; ++ int err; ++ /* the mac addr is at a known offset */ ++ err = mtd->read(mtd, 0x0FD8, 6, &retlen, (u8 *) &mac.sa_data); ++ if (err != 0 || retlen != 6) ++ printk(KERN_ERR "nas100d: mac addr read failed\n"); ++ else ++ printk(KERN_INFO ++ "nas100d: mac %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", ++ mac.sa_data[0], mac.sa_data[1], mac.sa_data[2], ++ mac.sa_data[3], mac.sa_data[4], mac.sa_data[5]); ++ } ++} ++ ++/* ++ * Nothing to do on remove at present. ++ */ ++static void nas100d_flash_remove(struct mtd_info *mtd) { ++} ++ ++static struct mtd_notifier nas100d_flash_notifier = { ++ .add = nas100d_flash_add, ++ .remove = nas100d_flash_remove, ++}; ++ ++static int nas100d_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = ptr; ++ ++ /* identify the ixp4xx eth, port 1 */ ++ if (dev->dev_addr[1] != 0x02 || dev->dev_addr[2] != 0xB3 ++ || dev->dev_addr[5] != 0x01) ++ return NOTIFY_DONE; ++ ++ if (event == NETDEV_REGISTER && is_valid_ether_addr(mac.sa_data)) { ++ mac.sa_family = dev->type; ++ dev_set_mac_address(dev, &mac); ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block nas100d_netdev_notifier = { ++ .notifier_call = nas100d_netdev_event, ++}; ++ + static void __init nas100d_init(void) + { ++ /* The flash has an ethernet MAC embedded in it which we need, ++ * that is all this notifier does. ++ */ ++ register_mtd_user(&nas100d_flash_notifier); ++ register_netdevice_notifier(&nas100d_netdev_notifier); ++ + ixp4xx_sys_init(); + + /* gpio 14 and 15 are _not_ clocks */ diff --git a/packages/linux/ixp4xx-kernel/2.6.16/92-nslu2-mac.patch b/packages/linux/ixp4xx-kernel/2.6.16/92-nslu2-mac.patch new file mode 100644 index 0000000000..31c5f04ebe --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/92-nslu2-mac.patch @@ -0,0 +1,88 @@ + arch/arm/mach-ixp4xx/nslu2-setup.c | 62 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) + +--- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-03-27 14:42:07.000000000 +0200 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-03-27 14:45:45.000000000 +0200 +@@ -16,6 +16,9 @@ + #include <linux/kernel.h> + #include <linux/serial.h> + #include <linux/serial_8250.h> ++#include <linux/mtd/mtd.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> + + #include <asm/mach-types.h> + #include <asm/mach/arch.h> +@@ -117,6 +120,59 @@ static void nslu2_power_off(void) + gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH); + } + ++/* ++ * When the RedBoot config partition is added the MAC address is read from ++ * it. ++ */ ++static struct sockaddr mac; ++ ++static void nslu2_flash_add(struct mtd_info *mtd) { ++ if (strcmp(mtd->name, "RedBoot config") == 0) { ++ size_t retlen; ++ int err; ++ /* the mac addr is at a known offset */ ++ err = mtd->read(mtd, 0x3FFD8, 6, &retlen, (u8 *) &mac.sa_data); ++ if (err != 0 || retlen != 6) ++ printk(KERN_ERR "nslu2: mac addr read failed\n"); ++ else ++ printk(KERN_INFO ++ "nslu2: mac %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", ++ mac.sa_data[0], mac.sa_data[1], mac.sa_data[2], ++ mac.sa_data[3], mac.sa_data[4], mac.sa_data[5]); ++ } ++} ++ ++static void nslu2_flash_remove(struct mtd_info *mtd) { ++} ++ ++static struct mtd_notifier nslu2_flash_notifier = { ++ .add = nslu2_flash_add, ++ .remove = nslu2_flash_remove, ++}; ++ ++ ++static int nslu2_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = ptr; ++ ++ /* identify the ixp4xx eth, port 1 */ ++ if (dev->dev_addr[1] != 0x02 || dev->dev_addr[2] != 0xB3 ++ || dev->dev_addr[5] != 0x01) ++ return NOTIFY_DONE; ++ ++ if (event == NETDEV_REGISTER && is_valid_ether_addr(mac.sa_data)) { ++ mac.sa_family = dev->type; ++ dev_set_mac_address(dev, &mac); ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block nslu2_netdev_notifier = { ++ .notifier_call = nslu2_netdev_event, ++}; ++ + static void __init nslu2_init(void) + { + /* The NSLU2 has a 33MHz crystal on board - 1.01% different +@@ -124,6 +180,12 @@ static void __init nslu2_init(void) + */ + ixp4xx_set_board_tick_rate(66000000); + ++ /* The flash has an ethernet MAC embedded in it which we need, ++ * that is all this notifier does. ++ */ ++ register_mtd_user(&nslu2_flash_notifier); ++ register_netdevice_notifier(&nslu2_netdev_notifier); ++ + ixp4xx_sys_init(); + + nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); diff --git a/packages/linux/ixp4xx-kernel/2.6.16/94-loft-setup.patch b/packages/linux/ixp4xx-kernel/2.6.16/94-loft-setup.patch index 62efa77495..6f82262967 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/94-loft-setup.patch +++ b/packages/linux/ixp4xx-kernel/2.6.16/94-loft-setup.patch @@ -1,20 +1,29 @@ --- - arch/arm/mach-ixp4xx/ixdp425-setup.c | 145 +++++++++++++++++++++++++++++++++-- - 1 file changed, 140 insertions(+), 5 deletions(-) + arch/arm/mach-ixp4xx/ixdp425-setup.c | 173 ++++++++++++++++++++++++++++++++--- + 1 file changed, 163 insertions(+), 10 deletions(-) ---- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-02-22 18:53:29.000000000 +0100 -+++ linux-ixp4xx/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-02-22 18:57:00.000000000 +0100 -@@ -15,7 +15,7 @@ - #include <linux/tty.h> +--- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-03-27 03:08:59.000000000 +0200 ++++ linux-ixp4xx/arch/arm/mach-ixp4xx/ixdp425-setup.c 2006-03-27 03:40:03.000000000 +0200 +@@ -11,20 +11,26 @@ + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/device.h> +-#include <linux/serial.h> +-#include <linux/tty.h> #include <linux/serial_8250.h> - #include <linux/slab.h> +-#include <linux/slab.h> - +-#include <asm/types.h> ++#include <linux/i2c.h> +#include <linux/eeprom.h> - #include <asm/types.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> #include <asm/setup.h> #include <asm/memory.h> -@@ -25,6 +25,14 @@ + #include <asm/hardware.h> + #include <asm/mach-types.h> +-#include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> @@ -29,7 +38,7 @@ static struct flash_platform_data ixdp425_flash_data = { .map_name = "cfi_probe", .width = 2, -@@ -176,22 +184,149 @@ MACHINE_START(AVILA, "Gateworks Avila Ne +@@ -176,22 +182,169 @@ MACHINE_START(AVILA, "Gateworks Avila Ne MACHINE_END #endif @@ -68,37 +77,56 @@ */ -#ifdef CONFIG_MACH_LOFT + -+#if defined(CONFIG_SENSORS_EEPROM) && defined(CONFIG_MACLIST) -+static void loft_eeprom_add(int address, int kind, struct kobject *kobj, -+ struct bin_attribute *eeprom_attr) { ++#if defined(CONFIG_SENSORS_EEPROM) ++static unsigned char loft_macs[12]; ++ ++static int loft_eeprom_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct eeprom_data *data = ptr; ++ + /* The MACs are the first 12 bytes in the eeprom at address 0x51 */ -+ if (address == 0x51) { -+ ssize_t retlen; -+ char data[12]; -+ -+ /* Two Macs, one at 0, the other at 6, maclist_add will -+ * complain if the ID is not a valid MAC. -+ */ -+ retlen = eeprom_attr->read(kobj, data, 0, sizeof data); -+ if (retlen >= 6) { -+ u8 mac[6]; -+ memcpy(mac, data+0, sizeof mac); -+ printk(KERN_INFO "LOFT MAC[0]: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -+ maclist_add(mac); -+ } -+ if (retlen >= 12) { -+ u8 mac[6]; -+ memcpy(mac, data+6, sizeof mac); -+ printk(KERN_INFO "LOFT MAC[1]: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -+ maclist_add(mac); -+ } ++ if (event == EEPROM_REGISTER && data->client.addr == 0x51) ++ data->attr->read(&data->client.dev.kobj, loft_macs, 0, 12); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block loft_eeprom_notifier = { ++ .notifier_call = loft_eeprom_event, ++}; ++ ++static int loft_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = ptr; ++ unsigned char *hwaddr = NULL; ++ ++ /* identify the ixp4xx eth */ ++ if (dev->dev_addr[1] != 0x02 || dev->dev_addr[2] != 0xB3) ++ return NOTIFY_DONE; ++ ++ if (event != NETDEV_REGISTER) ++ return NOTIFY_DONE; ++ ++ /* identify the port */ ++ if (dev->dev_addr[5] == 0x01) ++ hwaddr = &loft_macs[0]; ++ else if (dev->dev_addr[5] == 0x02) ++ hwaddr = &loft_macs[6]; ++ ++ if (hwaddr && is_valid_ether_addr(hwaddr)) { ++ struct sockaddr addr; ++ addr.sa_family = dev->type; ++ memcpy(addr.sa_data, hwaddr, ETH_ALEN); ++ dev_set_mac_address(dev, &addr); + } ++ ++ return NOTIFY_DONE; +} + -+static struct eeprom_notifier loft_eeprom_notifier = { -+ .add = loft_eeprom_add ++static struct notifier_block loft_netdev_notifier = { ++ .notifier_call = loft_netdev_event, +}; +#endif + @@ -114,7 +142,8 @@ + * that is all this notifier does. + */ +#ifdef CONFIG_SENSORS_EEPROM -+ register_eeprom_user(&loft_eeprom_notifier); ++ register_eeprom_notifier(&loft_eeprom_notifier); ++ register_netdevice_notifier(&loft_netdev_notifier); +#endif +} + diff --git a/packages/linux/ixp4xx-kernel/2.6.16/94-nas100d-setup.patch b/packages/linux/ixp4xx-kernel/2.6.16/94-nas100d-setup.patch deleted file mode 100644 index cdca7d2766..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/94-nas100d-setup.patch +++ /dev/null @@ -1,73 +0,0 @@ -Include a fixup machine start function in nas100d-setup.c to handle -the command line and memory setup parameters which are not specifiable -in the boot loader. - -Signed-off-by: John Bowler <jbowler@acm.org> - - arch/arm/mach-ixp4xx/nas100d-setup.c | 43 +++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - ---- linux-nslu2.orig/arch/arm/mach-ixp4xx/nas100d-setup.c 2006-02-10 19:19:53.000000000 +0100 -+++ linux-nslu2/arch/arm/mach-ixp4xx/nas100d-setup.c 2006-02-10 19:29:18.000000000 +0100 -@@ -17,6 +17,8 @@ - #include <linux/serial_8250.h> - #include <linux/mtd/mtd.h> - -+#include <asm/setup.h> -+#include <asm/memory.h> - #include <asm/mach-types.h> - #include <asm/mach/arch.h> - #include <asm/mach/flash.h> -@@ -161,11 +163,52 @@ static void __init nas100d_init(void) - platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices)); - } - -+/* -+ * NAS100D bootstrap may pass in parameters, but we zap the mem -+ * settings to be safe (the box always has 64MByte at 0). The -+ * passed in command line can override this default, we prepend -+ * to the config'ed default. -+ * -+ * NOTE: the startup sequence is: -+ * 1) Call the machine fixup -+ * 2) Parse the ATAG list, the ATAG_CMDLINE is copied in -+ * to default_command_line which is the value of *from -+ * 3) Parse the command line in *from (*not* -+ * default_command_line unless they are the same!) -+ * -+ * Setting mi->nr_banks causes (2) to 'squash' (set to ATAG_NONE) -+ * any ATAG_MEM tags, but mem= command line options cause nr_banks -+ * to be reset to 0 (on the first mem=) -+ */ -+static char nas100d_command_line[] __initdata = -+ "root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc " -+ "rtc-pcf8563.probe=0,0x51 " -+ CONFIG_CMDLINE; -+ -+static void __init nas100d_fixup(struct machine_desc *desc, -+ struct tag *tags, char **cmdline, struct meminfo *mi) -+{ -+ /* The NAS100D has one bank of 64MByte memory. -+ * NOTE: setting nr_banks != 0 causes kernel/setup.c to remove -+ * the mem tags from the tag list. We need do nothing here! -+ */ -+ mi->nr_banks=1; -+ mi->bank[0].start = 0; -+ mi->bank[0].size = (64*1024*1024); -+ mi->bank[0].node = PHYS_TO_NID(0); -+ -+ /* A command line in the ATAG list will override this one, -+ * as is intended. -+ */ -+ strlcpy(*cmdline, nas100d_command_line, COMMAND_LINE_SIZE); -+} -+ - MACHINE_START(NAS100D, "Iomega NAS 100d") - /* Maintainer: www.nslu2-linux.org */ - .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, - .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, - .boot_params = 0x00000100, -+ .fixup = nas100d_fixup, - .map_io = ixp4xx_map_io, - .init_irq = ixp4xx_init_irq, - .timer = &ixp4xx_timer, diff --git a/packages/linux/ixp4xx-kernel/2.6.16/96-nslu2-leds.patch b/packages/linux/ixp4xx-kernel/2.6.16/96-nslu2-leds.patch index 6b3b8d7d39..7890d392b0 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/96-nslu2-leds.patch +++ b/packages/linux/ixp4xx-kernel/2.6.16/96-nslu2-leds.patch @@ -8,9 +8,9 @@ Signed-off-by: John Bowler <jbowler@acm.org> --- linux-ixp4xx.orig/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-02-21 02:54:05.000000000 +0100 +++ linux-ixp4xx/arch/arm/mach-ixp4xx/nslu2-setup.c 2006-02-21 02:54:05.000000000 +0100 @@ -17,6 +17,9 @@ - #include <linux/serial.h> - #include <linux/serial_8250.h> #include <linux/mtd/mtd.h> + #include <linux/netdevice.h> + #include <linux/etherdevice.h> +#ifdef CONFIG_LEDS_CLASS +#include <linux/leds.h> +#endif diff --git a/packages/linux/ixp4xx-kernel/2.6.16/linux-2.6.16-i2c.patch b/packages/linux/ixp4xx-kernel/2.6.16/linux-2.6.16-i2c.patch new file mode 100644 index 0000000000..86c88c3746 --- /dev/null +++ b/packages/linux/ixp4xx-kernel/2.6.16/linux-2.6.16-i2c.patch @@ -0,0 +1,13671 @@ +--- linux-2.6.16.orig/include/linux/hwmon-sysfs.h 2006-03-22 17:06:11.000000000 +0100 ++++ linux-2.6.16/include/linux/hwmon-sysfs.h 2006-03-22 17:06:15.000000000 +0100 +@@ -27,11 +27,13 @@ + #define to_sensor_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct sensor_device_attribute, dev_attr) + +-#define SENSOR_DEVICE_ATTR(_name,_mode,_show,_store,_index) \ +-struct sensor_device_attribute sensor_dev_attr_##_name = { \ +- .dev_attr = __ATTR(_name,_mode,_show,_store), \ +- .index = _index, \ +-} ++#define SENSOR_ATTR(_name, _mode, _show, _store, _index) \ ++ { .dev_attr = __ATTR(_name, _mode, _show, _store), \ ++ .index = _index } ++ ++#define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index) \ ++struct sensor_device_attribute sensor_dev_attr_##_name \ ++ = SENSOR_ATTR(_name, _mode, _show, _store, _index) + + struct sensor_device_attribute_2 { + struct device_attribute dev_attr; +@@ -41,11 +43,13 @@ + #define to_sensor_dev_attr_2(_dev_attr) \ + container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr) + ++#define SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index) \ ++ { .dev_attr = __ATTR(_name, _mode, _show, _store), \ ++ .index = _index, \ ++ .nr = _nr } ++ + #define SENSOR_DEVICE_ATTR_2(_name,_mode,_show,_store,_nr,_index) \ +-struct sensor_device_attribute_2 sensor_dev_attr_##_name = { \ +- .dev_attr = __ATTR(_name,_mode,_show,_store), \ +- .index = _index, \ +- .nr = _nr, \ +-} ++struct sensor_device_attribute_2 sensor_dev_attr_##_name \ ++ = SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index) + + #endif /* _LINUX_HWMON_SYSFS_H */ +--- linux-2.6.16.orig/drivers/hwmon/pc87360.c 2006-03-22 17:06:11.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/pc87360.c 2006-03-22 17:06:15.000000000 +0100 +@@ -43,6 +43,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + static u8 devid; +@@ -183,8 +184,8 @@ + struct pc87360_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; +- struct semaphore update_lock; ++ struct mutex lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -283,7 +284,7 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long fan_min = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index])); + + /* If it wouldn't fit, change clock divisor */ +@@ -300,23 +301,31 @@ + /* Write new divider, preserve alarm bits */ + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index), + data->fan_status[attr->index] & 0xF9); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } + +-#define show_and_set_fan(offset) \ +-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ +- show_fan_input, NULL, offset-1); \ +-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \ +- show_fan_min, set_fan_min, offset-1); \ +-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ +- show_fan_div, NULL, offset-1); \ +-static SENSOR_DEVICE_ATTR(fan##offset##_status, S_IRUGO, \ +- show_fan_status, NULL, offset-1); +-show_and_set_fan(1) +-show_and_set_fan(2) +-show_and_set_fan(3) ++static struct sensor_device_attribute fan_input[] = { ++ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0), ++ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1), ++ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2), ++}; ++static struct sensor_device_attribute fan_status[] = { ++ SENSOR_ATTR(fan1_status, S_IRUGO, show_fan_status, NULL, 0), ++ SENSOR_ATTR(fan2_status, S_IRUGO, show_fan_status, NULL, 1), ++ SENSOR_ATTR(fan3_status, S_IRUGO, show_fan_status, NULL, 2), ++}; ++static struct sensor_device_attribute fan_div[] = { ++ SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0), ++ SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1), ++ SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2), ++}; ++static struct sensor_device_attribute fan_min[] = { ++ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0), ++ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 1), ++ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), ++}; + + static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) + { +@@ -335,21 +344,20 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->pwm[attr->index] = PWM_TO_REG(val, + FAN_CONFIG_INVERT(data->fan_conf, attr->index)); + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index), + data->pwm[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +-#define show_and_set_pwm(offset) \ +-static SENSOR_DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \ +- show_pwm, set_pwm, offset-1); +-show_and_set_pwm(1) +-show_and_set_pwm(2) +-show_and_set_pwm(3) ++static struct sensor_device_attribute pwm[] = { ++ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0), ++ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1), ++ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), ++}; + + static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) + { +@@ -386,11 +394,11 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); + pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN, + data->in_min[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf, +@@ -401,35 +409,67 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_max[attr->index] = IN_TO_REG(val, + data->in_vref); + pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX, + data->in_max[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +-#define show_and_set_in(offset) \ +-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ +- show_in_input, NULL, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ +- show_in_min, set_in_min, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ +- show_in_max, set_in_max, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_status, S_IRUGO, \ +- show_in_status, NULL, offset); +-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) ++static struct sensor_device_attribute in_input[] = { ++ SENSOR_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0), ++ SENSOR_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1), ++ SENSOR_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2), ++ SENSOR_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3), ++ SENSOR_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4), ++ SENSOR_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5), ++ SENSOR_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6), ++ SENSOR_ATTR(in7_input, S_IRUGO, show_in_input, NULL, 7), ++ SENSOR_ATTR(in8_input, S_IRUGO, show_in_input, NULL, 8), ++ SENSOR_ATTR(in9_input, S_IRUGO, show_in_input, NULL, 9), ++ SENSOR_ATTR(in10_input, S_IRUGO, show_in_input, NULL, 10), ++}; ++static struct sensor_device_attribute in_status[] = { ++ SENSOR_ATTR(in0_status, S_IRUGO, show_in_status, NULL, 0), ++ SENSOR_ATTR(in1_status, S_IRUGO, show_in_status, NULL, 1), ++ SENSOR_ATTR(in2_status, S_IRUGO, show_in_status, NULL, 2), ++ SENSOR_ATTR(in3_status, S_IRUGO, show_in_status, NULL, 3), ++ SENSOR_ATTR(in4_status, S_IRUGO, show_in_status, NULL, 4), ++ SENSOR_ATTR(in5_status, S_IRUGO, show_in_status, NULL, 5), ++ SENSOR_ATTR(in6_status, S_IRUGO, show_in_status, NULL, 6), ++ SENSOR_ATTR(in7_status, S_IRUGO, show_in_status, NULL, 7), ++ SENSOR_ATTR(in8_status, S_IRUGO, show_in_status, NULL, 8), ++ SENSOR_ATTR(in9_status, S_IRUGO, show_in_status, NULL, 9), ++ SENSOR_ATTR(in10_status, S_IRUGO, show_in_status, NULL, 10), ++}; ++static struct sensor_device_attribute in_min[] = { ++ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 0), ++ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 1), ++ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 2), ++ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 3), ++ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 4), ++ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 5), ++ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 6), ++ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 7), ++ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 8), ++ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 9), ++ SENSOR_ATTR(in10_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 10), ++}; ++static struct sensor_device_attribute in_max[] = { ++ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 0), ++ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 1), ++ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 2), ++ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 3), ++ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 4), ++ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 5), ++ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 6), ++ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 7), ++ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 8), ++ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 9), ++ SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), ++}; + + static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) + { +@@ -473,11 +513,11 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); + pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN, + data->in_min[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf, +@@ -488,11 +528,11 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_max[attr->index] = IN_TO_REG(val, data->in_vref); + pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX, + data->in_max[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf, +@@ -503,28 +543,51 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref); + pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT, + data->in_crit[attr->index-11]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +-#define show_and_set_therm(offset) \ +-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ +- show_therm_input, NULL, 11+offset-4); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ +- show_therm_min, set_therm_min, 11+offset-4); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ +- show_therm_max, set_therm_max, 11+offset-4); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ +- show_therm_crit, set_therm_crit, 11+offset-4); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ +- show_therm_status, NULL, 11+offset-4); +-show_and_set_therm(4) +-show_and_set_therm(5) +-show_and_set_therm(6) ++/* the +11 term below reflects the fact that VLM units 11,12,13 are ++ used in the chip to measure voltage across the thermistors ++*/ ++static struct sensor_device_attribute therm_input[] = { ++ SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0+11), ++ SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1+11), ++ SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2+11), ++}; ++static struct sensor_device_attribute therm_status[] = { ++ SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0+11), ++ SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1+11), ++ SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2+11), ++}; ++static struct sensor_device_attribute therm_min[] = { ++ SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR, ++ show_therm_min, set_therm_min, 0+11), ++ SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR, ++ show_therm_min, set_therm_min, 1+11), ++ SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR, ++ show_therm_min, set_therm_min, 2+11), ++}; ++static struct sensor_device_attribute therm_max[] = { ++ SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, ++ show_therm_max, set_therm_max, 0+11), ++ SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, ++ show_therm_max, set_therm_max, 1+11), ++ SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, ++ show_therm_max, set_therm_max, 2+11), ++}; ++static struct sensor_device_attribute therm_crit[] = { ++ SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR, ++ show_therm_crit, set_therm_crit, 0+11), ++ SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR, ++ show_therm_crit, set_therm_crit, 1+11), ++ SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR, ++ show_therm_crit, set_therm_crit, 2+11), ++}; + + static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) + { +@@ -592,11 +655,11 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_min[attr->index] = TEMP_TO_REG(val); + pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN, + data->temp_min[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf, +@@ -607,11 +670,11 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_max[attr->index] = TEMP_TO_REG(val); + pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX, + data->temp_max[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf, +@@ -622,28 +685,48 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_crit[attr->index] = TEMP_TO_REG(val); + pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT, + data->temp_crit[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +-#define show_and_set_temp(offset) \ +-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ +- show_temp_input, NULL, offset-1); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ +- show_temp_min, set_temp_min, offset-1); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ +- show_temp_max, set_temp_max, offset-1); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ +- show_temp_crit, set_temp_crit, offset-1); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ +- show_temp_status, NULL, offset-1); +-show_and_set_temp(1) +-show_and_set_temp(2) +-show_and_set_temp(3) ++static struct sensor_device_attribute temp_input[] = { ++ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0), ++ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1), ++ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2), ++}; ++static struct sensor_device_attribute temp_status[] = { ++ SENSOR_ATTR(temp1_status, S_IRUGO, show_temp_status, NULL, 0), ++ SENSOR_ATTR(temp2_status, S_IRUGO, show_temp_status, NULL, 1), ++ SENSOR_ATTR(temp3_status, S_IRUGO, show_temp_status, NULL, 2), ++}; ++static struct sensor_device_attribute temp_min[] = { ++ SENSOR_ATTR(temp1_min, S_IRUGO | S_IWUSR, ++ show_temp_min, set_temp_min, 0), ++ SENSOR_ATTR(temp2_min, S_IRUGO | S_IWUSR, ++ show_temp_min, set_temp_min, 1), ++ SENSOR_ATTR(temp3_min, S_IRUGO | S_IWUSR, ++ show_temp_min, set_temp_min, 2), ++}; ++static struct sensor_device_attribute temp_max[] = { ++ SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 0), ++ SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 1), ++ SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 2), ++}; ++static struct sensor_device_attribute temp_crit[] = { ++ SENSOR_ATTR(temp1_crit, S_IRUGO | S_IWUSR, ++ show_temp_crit, set_temp_crit, 0), ++ SENSOR_ATTR(temp2_crit, S_IRUGO | S_IWUSR, ++ show_temp_crit, set_temp_crit, 1), ++ SENSOR_ATTR(temp3_crit, S_IRUGO | S_IWUSR, ++ show_temp_crit, set_temp_crit, 2), ++}; + + static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) + { +@@ -749,22 +832,24 @@ + static int pc87360_detect(struct i2c_adapter *adapter) + { + int i; +- struct i2c_client *new_client; ++ struct i2c_client *client; + struct pc87360_data *data; + int err = 0; + const char *name = "pc87360"; + int use_thermistors = 0; ++ struct device *dev; + + if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + return -ENOMEM; + +- 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; ++ client = &data->client; ++ dev = &client->dev; ++ i2c_set_clientdata(client, data); ++ client->addr = address; ++ mutex_init(&data->lock); ++ client->adapter = adapter; ++ client->driver = &pc87360_driver; ++ client->flags = 0; + + data->fannr = 2; + data->innr = 0; +@@ -792,15 +877,15 @@ + break; + } + +- strcpy(new_client->name, name); ++ strlcpy(client->name, name, sizeof(client->name)); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&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.driver.name)) { +- dev_err(&new_client->dev, "Region 0x%x-0x%x already " ++ dev_err(&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--) +@@ -814,7 +899,7 @@ + if (data->fannr) + data->fan_conf = confreg[0] | (confreg[1] << 8); + +- if ((err = i2c_attach_client(new_client))) ++ if ((err = i2c_attach_client(client))) + goto ERROR2; + + /* Use the correct reference voltage +@@ -828,7 +913,7 @@ + PC87365_REG_TEMP_CONFIG); + } + data->in_vref = (i&0x02) ? 3025 : 2966; +- dev_dbg(&new_client->dev, "Using %s reference voltage\n", ++ dev_dbg(&client->dev, "Using %s reference voltage\n", + (i&0x02) ? "external" : "internal"); + + data->vid_conf = confreg[3]; +@@ -847,154 +932,64 @@ + if (devid == 0xe9 && data->address[1]) /* PC87366 */ + use_thermistors = confreg[2] & 0x40; + +- pc87360_init_client(new_client, use_thermistors); ++ pc87360_init_client(client, use_thermistors); + } + + /* Register sysfs hooks */ +- data->class_dev = hwmon_device_register(&new_client->dev); ++ data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto ERROR3; + } + + if (data->innr) { +- 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_in9_input.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in10_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_in8_min.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_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_in8_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in0_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in1_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in2_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in3_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in4_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in5_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in6_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in7_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in8_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in9_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_in10_status.dev_attr); +- +- 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); ++ for (i = 0; i < 11; i++) { ++ device_create_file(dev, &in_input[i].dev_attr); ++ device_create_file(dev, &in_min[i].dev_attr); ++ device_create_file(dev, &in_max[i].dev_attr); ++ device_create_file(dev, &in_status[i].dev_attr); ++ } ++ device_create_file(dev, &dev_attr_cpu0_vid); ++ device_create_file(dev, &dev_attr_vrm); ++ device_create_file(dev, &dev_attr_alarms_in); + } + + if (data->tempnr) { +- 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_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_status.dev_attr); +- +- device_create_file(&new_client->dev, &dev_attr_alarms_temp); +- } +- if (data->tempnr == 3) { +- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.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_crit.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_status.dev_attr); ++ for (i = 0; i < data->tempnr; i++) { ++ device_create_file(dev, &temp_input[i].dev_attr); ++ device_create_file(dev, &temp_min[i].dev_attr); ++ device_create_file(dev, &temp_max[i].dev_attr); ++ device_create_file(dev, &temp_crit[i].dev_attr); ++ device_create_file(dev, &temp_status[i].dev_attr); ++ } ++ device_create_file(dev, &dev_attr_alarms_temp); + } ++ + if (data->innr == 14) { +- device_create_file(&new_client->dev, &sensor_dev_attr_temp4_input.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp5_input.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp6_input.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp4_min.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp5_min.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp6_min.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp4_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp5_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp6_max.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp5_crit.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp6_crit.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp4_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp5_status.dev_attr); +- device_create_file(&new_client->dev, &sensor_dev_attr_temp6_status.dev_attr); +- } +- +- if (data->fannr) { +- if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { +- 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, +- &sensor_dev_attr_fan1_div.dev_attr); +- device_create_file(&new_client->dev, +- &sensor_dev_attr_fan1_status.dev_attr); +- } +- +- if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { +- device_create_file(&new_client->dev, +- &sensor_dev_attr_fan2_input.dev_attr); +- device_create_file(&new_client->dev, +- &sensor_dev_attr_fan2_min.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_status.dev_attr); +- } +- +- if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) +- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); +- if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) +- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); +- } +- if (data->fannr == 3) { +- if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { +- device_create_file(&new_client->dev, +- &sensor_dev_attr_fan3_input.dev_attr); +- device_create_file(&new_client->dev, +- &sensor_dev_attr_fan3_min.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_status.dev_attr); ++ for (i = 0; i < 3; i++) { ++ device_create_file(dev, &therm_input[i].dev_attr); ++ device_create_file(dev, &therm_min[i].dev_attr); ++ device_create_file(dev, &therm_max[i].dev_attr); ++ device_create_file(dev, &therm_crit[i].dev_attr); ++ device_create_file(dev, &therm_status[i].dev_attr); + } ++ } + +- if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) +- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); ++ for (i = 0; i < data->fannr; i++) { ++ if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { ++ device_create_file(dev, &fan_input[i].dev_attr); ++ device_create_file(dev, &fan_min[i].dev_attr); ++ device_create_file(dev, &fan_div[i].dev_attr); ++ device_create_file(dev, &fan_status[i].dev_attr); ++ } ++ if (FAN_CONFIG_CONTROL(data->fan_conf, i)) ++ device_create_file(dev, &pwm[i].dev_attr); + } + + return 0; + + ERROR3: +- i2c_detach_client(new_client); ++ i2c_detach_client(client); + ERROR2: + for (i = 0; i < 3; i++) { + if (data->address[i]) { +@@ -1033,11 +1028,11 @@ + { + int res; + +- down(&(data->lock)); ++ mutex_lock(&(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)); ++ mutex_unlock(&(data->lock)); + + return res; + } +@@ -1045,11 +1040,11 @@ + static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value) + { +- down(&(data->lock)); ++ mutex_lock(&(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)); ++ mutex_unlock(&(data->lock)); + } + + static void pc87360_init_client(struct i2c_client *client, int use_thermistors) +@@ -1071,7 +1066,7 @@ + } + + nr = data->innr < 11 ? data->innr : 11; +- for (i=0; i<nr; i++) { ++ for (i = 0; i < nr; i++) { + if (init >= init_in[i]) { + /* Forcibly enable voltage channel */ + reg = pc87360_read_value(data, LD_IN, i, +@@ -1088,14 +1083,14 @@ + + /* We can't blindly trust the Super-I/O space configuration bit, + most BIOS won't set it properly */ +- for (i=11; i<data->innr; i++) { ++ for (i = 11; i < data->innr; 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 (; i<data->tempnr; i++) { ++ for (; i < data->tempnr; i++) { + if (init >= init_temp[i]) { + /* Forcibly enable temperature channel */ + reg = pc87360_read_value(data, LD_TEMP, i, +@@ -1111,7 +1106,7 @@ + } + + if (use_thermistors) { +- for (i=11; i<data->innr; i++) { ++ for (i = 11; i < data->innr; i++) { + if (init >= init_in[i]) { + /* The pin may already be used by thermal + diodes */ +@@ -1221,7 +1216,7 @@ + struct pc87360_data *data = i2c_get_clientdata(client); + u8 i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Data update\n"); +@@ -1321,7 +1316,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/f71805f.c 2006-03-22 17:06:11.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/f71805f.c 2006-03-22 17:06:16.000000000 +0100 +@@ -30,6 +30,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-sysfs.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + static struct platform_device *pdev; +@@ -98,10 +99,6 @@ + #define ADDR_REG_OFFSET 0 + #define DATA_REG_OFFSET 1 + +-static struct resource f71805f_resource __initdata = { +- .flags = IORESOURCE_IO, +-}; +- + /* + * Registers + */ +@@ -131,10 +128,10 @@ + struct f71805f_data { + unsigned short addr; + const char *name; +- struct semaphore lock; ++ struct mutex lock; + struct class_device *class_dev; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ +@@ -150,7 +147,7 @@ + u8 temp_high[3]; + u8 temp_hyst[3]; + u8 temp_mode; +- u8 alarms[3]; ++ unsigned long alarms; + }; + + static inline long in_from_reg(u8 reg) +@@ -224,20 +221,20 @@ + { + u8 val; + +- down(&data->lock); ++ mutex_lock(&data->lock); + outb(reg, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + + return val; + } + + static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val) + { +- down(&data->lock); ++ mutex_lock(&data->lock); + outb(reg, data->addr + ADDR_REG_OFFSET); + outb(val, data->addr + DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + } + + /* It is important to read the MSB first, because doing so latches the +@@ -246,24 +243,24 @@ + { + u16 val; + +- down(&data->lock); ++ mutex_lock(&data->lock); + outb(reg, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET) << 8; + outb(++reg, data->addr + ADDR_REG_OFFSET); + val |= inb(data->addr + DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + + return val; + } + + static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val) + { +- down(&data->lock); ++ mutex_lock(&data->lock); + outb(reg, data->addr + ADDR_REG_OFFSET); + outb(val >> 8, data->addr + DATA_REG_OFFSET); + outb(++reg, data->addr + ADDR_REG_OFFSET); + outb(val & 0xff, data->addr + DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + } + + static struct f71805f_data *f71805f_update_device(struct device *dev) +@@ -271,7 +268,7 @@ + struct f71805f_data *data = dev_get_drvdata(dev); + int nr; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + /* Limit registers cache is refreshed after 60 seconds */ + if (time_after(jiffies, data->last_updated + 60 * HZ) +@@ -314,16 +311,15 @@ + data->temp[nr] = f71805f_read8(data, + F71805F_REG_TEMP(nr)); + } +- for (nr = 0; nr < 3; nr++) { +- data->alarms[nr] = f71805f_read8(data, +- F71805F_REG_STATUS(nr)); +- } ++ data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0)) ++ + (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8) ++ + (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16); + + data->last_updated = jiffies; + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +@@ -362,10 +358,10 @@ + struct f71805f_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_high[0] = in0_to_reg(val); + f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -376,18 +372,14 @@ + struct f71805f_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_low[0] = in0_to_reg(val); + f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } + +-static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); +-static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); +-static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); +- + static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) + { +@@ -426,10 +418,10 @@ + int nr = attr->index; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_high[nr] = in_to_reg(val); + f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -442,31 +434,14 @@ + int nr = attr->index; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_low[nr] = in_to_reg(val); + f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } + +-#define sysfs_in(offset) \ +-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ +- show_in, NULL, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ +- show_in_max, set_in_max, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ +- show_in_min, set_in_min, offset) +- +-sysfs_in(1); +-sysfs_in(2); +-sysfs_in(3); +-sysfs_in(4); +-sysfs_in(5); +-sysfs_in(6); +-sysfs_in(7); +-sysfs_in(8); +- + static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) + { +@@ -495,24 +470,14 @@ + int nr = attr->index; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->fan_low[nr] = fan_to_reg(val); + f71805f_write16(data, F71805F_REG_FAN_LOW(nr), data->fan_low[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } + +-#define sysfs_fan(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) +- +-sysfs_fan(1); +-sysfs_fan(2); +-sysfs_fan(3); +- + static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) + { +@@ -562,10 +527,10 @@ + int nr = attr->index; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_high[nr] = temp_to_reg(val); + f71805f_write8(data, F71805F_REG_TEMP_HIGH(nr), data->temp_high[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -578,35 +543,20 @@ + int nr = attr->index; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_hyst[nr] = temp_to_reg(val); + f71805f_write8(data, F71805F_REG_TEMP_HYST(nr), data->temp_hyst[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return count; + } + +-#define sysfs_temp(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##_max_hyst, S_IRUGO | S_IWUSR, \ +- show_temp_hyst, set_temp_hyst, offset - 1); \ +-static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO, \ +- show_temp_type, NULL, offset - 1) +- +-sysfs_temp(1); +-sysfs_temp(2); +-sysfs_temp(3); +- + static ssize_t show_alarms_in(struct device *dev, struct device_attribute + *devattr, char *buf) + { + struct f71805f_data *data = f71805f_update_device(dev); + +- return sprintf(buf, "%d\n", data->alarms[0] | +- ((data->alarms[1] & 0x01) << 8)); ++ return sprintf(buf, "%lu\n", data->alarms & 0x1ff); + } + + static ssize_t show_alarms_fan(struct device *dev, struct device_attribute +@@ -614,7 +564,7 @@ + { + struct f71805f_data *data = f71805f_update_device(dev); + +- return sprintf(buf, "%d\n", data->alarms[2] & 0x07); ++ return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07); + } + + static ssize_t show_alarms_temp(struct device *dev, struct device_attribute +@@ -622,12 +572,18 @@ + { + struct f71805f_data *data = f71805f_update_device(dev); + +- return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07); ++ return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07); + } + +-static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL); +-static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL); +-static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); ++static ssize_t show_alarm(struct device *dev, struct device_attribute ++ *devattr, char *buf) ++{ ++ struct f71805f_data *data = f71805f_update_device(dev); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ int nr = attr->index; ++ ++ return sprintf(buf, "%lu\n", (data->alarms >> nr) & 1); ++} + + static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +@@ -637,7 +593,104 @@ + return sprintf(buf, "%s\n", data->name); + } + +-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); ++static struct device_attribute f71805f_dev_attr[] = { ++ __ATTR(in0_input, S_IRUGO, show_in0, NULL), ++ __ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max), ++ __ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min), ++ __ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL), ++ __ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL), ++ __ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL), ++ __ATTR(name, S_IRUGO, show_name, NULL), ++}; ++ ++static struct sensor_device_attribute f71805f_sensor_attr[] = { ++ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), ++ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), ++ SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 1), ++ SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 1), ++ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), ++ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), ++ SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 2), ++ SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 2), ++ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), ++ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), ++ SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 3), ++ SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 3), ++ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), ++ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), ++ SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 4), ++ SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 4), ++ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4), ++ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), ++ SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 5), ++ SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 5), ++ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5), ++ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), ++ SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 6), ++ SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 6), ++ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6), ++ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), ++ SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 7), ++ SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 7), ++ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7), ++ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), ++ SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR, ++ show_in_max, set_in_max, 8), ++ SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR, ++ show_in_min, set_in_min, 8), ++ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8), ++ ++ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), ++ SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 0), ++ SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, ++ show_temp_hyst, set_temp_hyst, 0), ++ SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), ++ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11), ++ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), ++ SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 1), ++ SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, ++ show_temp_hyst, set_temp_hyst, 1), ++ SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), ++ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12), ++ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), ++ SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, ++ show_temp_max, set_temp_max, 2), ++ SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, ++ show_temp_hyst, set_temp_hyst, 2), ++ SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), ++ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), ++}; ++ ++static struct sensor_device_attribute f71805f_fan_attr[] = { ++ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), ++ SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR, ++ show_fan_min, set_fan_min, 0), ++ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16), ++ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), ++ SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR, ++ show_fan_min, set_fan_min, 1), ++ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17), ++ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), ++ SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR, ++ show_fan_min, set_fan_min, 2), ++ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18), ++}; + + /* + * Device registration and initialization +@@ -668,7 +721,7 @@ + { + struct f71805f_data *data; + struct resource *res; +- int err; ++ int i, err; + + if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { + err = -ENOMEM; +@@ -678,9 +731,9 @@ + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + data->addr = res->start; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + data->name = "f71805f"; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + platform_set_drvdata(pdev, data); + +@@ -695,76 +748,31 @@ + f71805f_init_device(data); + + /* Register sysfs interface files */ +- device_create_file(&pdev->dev, &dev_attr_in0_input); +- device_create_file(&pdev->dev, &dev_attr_in0_max); +- device_create_file(&pdev->dev, &dev_attr_in0_min); +- device_create_file(&pdev->dev, &sensor_dev_attr_in1_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in2_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in3_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in4_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in5_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in6_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in7_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in8_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in1_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in2_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in3_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in4_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in5_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in6_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in7_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in8_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in1_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in2_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in3_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in4_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in5_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in6_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in7_min.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_in8_min.dev_attr); +- if (data->fan_enabled & (1 << 0)) { +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan1_input.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan1_min.dev_attr); +- } +- if (data->fan_enabled & (1 << 1)) { +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan2_input.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan2_min.dev_attr); +- } +- if (data->fan_enabled & (1 << 2)) { +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan3_input.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_fan3_min.dev_attr); +- } +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp1_input.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp2_input.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp3_input.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp2_max.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp3_max.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp1_max_hyst.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp2_max_hyst.dev_attr); +- device_create_file(&pdev->dev, +- &sensor_dev_attr_temp3_max_hyst.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp1_type.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp2_type.dev_attr); +- device_create_file(&pdev->dev, &sensor_dev_attr_temp3_type.dev_attr); +- device_create_file(&pdev->dev, &dev_attr_alarms_in); +- device_create_file(&pdev->dev, &dev_attr_alarms_fan); +- device_create_file(&pdev->dev, &dev_attr_alarms_temp); +- device_create_file(&pdev->dev, &dev_attr_name); ++ for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) { ++ err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]); ++ if (err) ++ goto exit_class; ++ } ++ for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) { ++ err = device_create_file(&pdev->dev, ++ &f71805f_sensor_attr[i].dev_attr); ++ if (err) ++ goto exit_class; ++ } ++ for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) { ++ if (!(data->fan_enabled & (1 << (i / 3)))) ++ continue; ++ err = device_create_file(&pdev->dev, ++ &f71805f_fan_attr[i].dev_attr); ++ if (err) ++ goto exit_class; ++ } + + return 0; + ++exit_class: ++ dev_err(&pdev->dev, "Sysfs interface creation failed\n"); ++ hwmon_device_unregister(data->class_dev); + exit_free: + kfree(data); + exit: +@@ -793,6 +801,11 @@ + + static int __init f71805f_device_add(unsigned short address) + { ++ struct resource res = { ++ .start = address, ++ .end = address + REGION_LENGTH - 1, ++ .flags = IORESOURCE_IO, ++ }; + int err; + + pdev = platform_device_alloc(DRVNAME, address); +@@ -802,10 +815,8 @@ + goto exit; + } + +- f71805f_resource.start = address; +- f71805f_resource.end = address + REGION_LENGTH - 1; +- f71805f_resource.name = pdev->name; +- err = platform_device_add_resources(pdev, &f71805f_resource, 1); ++ res.name = pdev->name; ++ err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ali1535.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ali1535.c 2006-03-22 17:06:16.000000000 +0100 +@@ -63,7 +63,6 @@ + #include <linux/i2c.h> + #include <linux/init.h> + #include <asm/io.h> +-#include <asm/semaphore.h> + + + /* ALI1535 SMBus address offsets */ +@@ -136,7 +135,6 @@ + + static struct pci_driver ali1535_driver; + static unsigned short ali1535_smba; +-static DECLARE_MUTEX(i2c_ali1535_sem); + + /* Detect whether a ALI1535 can be found, and initialize it, where necessary. + Note the differences between kernels with the old PCI BIOS interface and +@@ -345,7 +343,6 @@ + int timeout; + s32 result = 0; + +- down(&i2c_ali1535_sem); + /* make sure SMBus is idle */ + temp = inb_p(SMBHSTSTS); + for (timeout = 0; +@@ -460,7 +457,6 @@ + break; + } + EXIT: +- up(&i2c_ali1535_sem); + return result; + } + +@@ -479,7 +475,7 @@ + + static struct i2c_adapter ali1535_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/chips/ds1374.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/ds1374.c 2006-03-22 17:06:14.000000000 +0100 +@@ -26,6 +26,7 @@ + #include <linux/i2c.h> + #include <linux/rtc.h> + #include <linux/bcd.h> ++#include <linux/mutex.h> + + #define DS1374_REG_TOD0 0x00 + #define DS1374_REG_TOD1 0x01 +@@ -41,7 +42,7 @@ + + #define DS1374_DRV_NAME "ds1374" + +-static DECLARE_MUTEX(ds1374_mutex); ++static DEFINE_MUTEX(ds1374_mutex); + + static struct i2c_driver ds1374_driver; + static struct i2c_client *save_client; +@@ -114,7 +115,7 @@ + ulong t1, t2; + int limit = 10; /* arbitrary retry limit */ + +- down(&ds1374_mutex); ++ mutex_lock(&ds1374_mutex); + + /* + * Since the reads are being performed one byte at a time using +@@ -127,7 +128,7 @@ + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + +- up(&ds1374_mutex); ++ mutex_unlock(&ds1374_mutex); + + if (t1 != t2) { + dev_warn(&save_client->dev, +@@ -145,7 +146,7 @@ + + t1 = *(ulong *) arg; + +- down(&ds1374_mutex); ++ mutex_lock(&ds1374_mutex); + + /* + * Since the writes are being performed one byte at a time using +@@ -158,7 +159,7 @@ + t2 = ds1374_read_rtc(); + } while (t1 != t2 && limit--); + +- up(&ds1374_mutex); ++ mutex_unlock(&ds1374_mutex); + + if (t1 != t2) + dev_warn(&save_client->dev, +--- linux-2.6.16.orig/drivers/i2c/chips/m41t00.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/m41t00.c 2006-03-22 17:06:14.000000000 +0100 +@@ -24,13 +24,14 @@ + #include <linux/i2c.h> + #include <linux/rtc.h> + #include <linux/bcd.h> ++#include <linux/mutex.h> + + #include <asm/time.h> + #include <asm/rtc.h> + + #define M41T00_DRV_NAME "m41t00" + +-static DECLARE_MUTEX(m41t00_mutex); ++static DEFINE_MUTEX(m41t00_mutex); + + static struct i2c_driver m41t00_driver; + static struct i2c_client *save_client; +@@ -54,7 +55,7 @@ + sec = min = hour = day = mon = year = 0; + sec1 = min1 = hour1 = day1 = mon1 = year1 = 0; + +- down(&m41t00_mutex); ++ mutex_lock(&m41t00_mutex); + do { + if (((sec = i2c_smbus_read_byte_data(save_client, 0)) >= 0) + && ((min = i2c_smbus_read_byte_data(save_client, 1)) +@@ -80,7 +81,7 @@ + mon1 = mon; + year1 = year; + } while (--limit > 0); +- up(&m41t00_mutex); ++ mutex_unlock(&m41t00_mutex); + + if (limit == 0) { + dev_warn(&save_client->dev, +@@ -125,7 +126,7 @@ + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_year); + +- down(&m41t00_mutex); ++ mutex_lock(&m41t00_mutex); + if ((i2c_smbus_write_byte_data(save_client, 0, tm.tm_sec & 0x7f) < 0) + || (i2c_smbus_write_byte_data(save_client, 1, tm.tm_min & 0x7f) + < 0) +@@ -140,7 +141,7 @@ + + dev_warn(&save_client->dev,"m41t00: can't write to rtc chip\n"); + +- up(&m41t00_mutex); ++ mutex_unlock(&m41t00_mutex); + return; + } + +--- linux-2.6.16.orig/drivers/i2c/i2c-core.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/i2c-core.c 2006-03-22 17:06:21.000000000 +0100 +@@ -31,14 +31,17 @@ + #include <linux/idr.h> + #include <linux/seq_file.h> + #include <linux/platform_device.h> ++#include <linux/mutex.h> + #include <asm/uaccess.h> + + + static LIST_HEAD(adapters); + static LIST_HEAD(drivers); +-static DECLARE_MUTEX(core_lists); ++static DEFINE_MUTEX(core_lists); + static DEFINE_IDR(i2c_adapter_idr); + ++static void i2c_notify(struct i2c_adapter *adap, struct i2c_driver *driver); ++ + /* match always succeeds, as we want the probe() to tell if we really accept this match */ + static int i2c_device_match(struct device *dev, struct device_driver *drv) + { +@@ -153,7 +156,7 @@ + struct list_head *item; + struct i2c_driver *driver; + +- down(&core_lists); ++ mutex_lock(&core_lists); + + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) { + res = -ENOMEM; +@@ -168,8 +171,8 @@ + } + + adap->nr = id & MAX_ID_MASK; +- init_MUTEX(&adap->bus_lock); +- init_MUTEX(&adap->clist_lock); ++ mutex_init(&adap->bus_lock); ++ mutex_init(&adap->clist_lock); + list_add_tail(&adap->list,&adapters); + INIT_LIST_HEAD(&adap->clients); + +@@ -197,13 +200,11 @@ + /* inform drivers of new adapters */ + list_for_each(item,&drivers) { + driver = list_entry(item, struct i2c_driver, list); +- if (driver->attach_adapter) +- /* We ignore the return code; if it fails, too bad */ +- driver->attach_adapter(adap); ++ i2c_notify(adap, driver); + } + + out_unlock: +- up(&core_lists); ++ mutex_unlock(&core_lists); + return res; + } + +@@ -216,7 +217,7 @@ + struct i2c_client *client; + int res = 0; + +- down(&core_lists); ++ mutex_lock(&core_lists); + + /* First make sure that this adapter was ever added */ + list_for_each_entry(adap_from_list, &adapters, list) { +@@ -272,7 +273,7 @@ + dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); + + out_unlock: +- up(&core_lists); ++ mutex_unlock(&core_lists); + return res; + } + +@@ -287,9 +288,7 @@ + { + struct list_head *item; + struct i2c_adapter *adapter; +- int res = 0; +- +- down(&core_lists); ++ int res; + + /* add the driver to the list of i2c drivers in the driver core */ + driver->driver.owner = owner; +@@ -297,22 +296,21 @@ + + res = driver_register(&driver->driver); + if (res) +- goto out_unlock; ++ return res; + ++ mutex_lock(&core_lists); ++ + list_add_tail(&driver->list,&drivers); + pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); + + /* now look for instances of driver on our adapters */ +- if (driver->attach_adapter) { +- list_for_each(item,&adapters) { +- adapter = list_entry(item, struct i2c_adapter, list); +- driver->attach_adapter(adapter); +- } ++ list_for_each(item, &adapters) { ++ adapter = list_entry(item, struct i2c_adapter, list); ++ i2c_notify(adapter, driver); + } + +- out_unlock: +- up(&core_lists); +- return res; ++ mutex_unlock(&core_lists); ++ return 0; + } + EXPORT_SYMBOL(i2c_register_driver); + +@@ -324,7 +322,7 @@ + + int res = 0; + +- down(&core_lists); ++ mutex_lock(&core_lists); + + /* Have a look at each adapter, if clients of this driver are still + * attached. If so, detach them to be able to kill the driver +@@ -363,7 +361,7 @@ + pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); + + out_unlock: +- up(&core_lists); ++ mutex_unlock(&core_lists); + return 0; + } + +@@ -384,9 +382,9 @@ + { + int rval; + +- down(&adapter->clist_lock); ++ mutex_lock(&adapter->clist_lock); + rval = __i2c_check_addr(adapter, addr); +- up(&adapter->clist_lock); ++ mutex_unlock(&adapter->clist_lock); + + return rval; + } +@@ -395,13 +393,13 @@ + { + struct i2c_adapter *adapter = client->adapter; + +- down(&adapter->clist_lock); ++ mutex_lock(&adapter->clist_lock); + if (__i2c_check_addr(client->adapter, client->addr)) { +- up(&adapter->clist_lock); ++ mutex_unlock(&adapter->clist_lock); + return -EBUSY; + } + list_add_tail(&client->list,&adapter->clients); +- up(&adapter->clist_lock); ++ mutex_unlock(&adapter->clist_lock); + + if (adapter->client_register) { + if (adapter->client_register(client)) { +@@ -450,12 +448,12 @@ + } + } + +- down(&adapter->clist_lock); ++ mutex_lock(&adapter->clist_lock); + list_del(&client->list); + init_completion(&client->released); + device_remove_file(&client->dev, &dev_attr_client_name); + device_unregister(&client->dev); +- up(&adapter->clist_lock); ++ mutex_unlock(&adapter->clist_lock); + wait_for_completion(&client->released); + + out: +@@ -513,19 +511,19 @@ + struct list_head *item; + struct i2c_client *client; + +- down(&adap->clist_lock); ++ mutex_lock(&adap->clist_lock); + list_for_each(item,&adap->clients) { + client = list_entry(item, struct i2c_client, list); + if (!try_module_get(client->driver->driver.owner)) + continue; + if (NULL != client->driver->command) { +- up(&adap->clist_lock); ++ mutex_unlock(&adap->clist_lock); + client->driver->command(client,cmd,arg); +- down(&adap->clist_lock); ++ mutex_lock(&adap->clist_lock); + } + module_put(client->driver->driver.owner); + } +- up(&adap->clist_lock); ++ mutex_unlock(&adap->clist_lock); + } + + static int __init i2c_init(void) +@@ -569,9 +567,9 @@ + } + #endif + +- down(&adap->bus_lock); ++ mutex_lock(&adap->bus_lock); + ret = adap->algo->master_xfer(adap,msgs,num); +- up(&adap->bus_lock); ++ mutex_unlock(&adap->bus_lock); + + return ret; + } else { +@@ -775,16 +773,53 @@ + return 0; + } + ++/* For explicitely attaching a driver to a given device */ ++int i2c_probe_device(struct i2c_adapter *adapter, int driver_id, ++ int addr, int kind) ++{ ++ struct list_head *item; ++ struct i2c_driver *driver = NULL; ++ ++ /* There's no way to probe addresses on this adapter... */ ++ if (kind < 0 && !i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_QUICK)) ++ return -EINVAL; ++ ++ mutex_lock(&core_lists); ++ list_for_each(item, &drivers) { ++ driver = list_entry(item, struct i2c_driver, list); ++ if (driver->id == driver_id) ++ break; ++ } ++ mutex_unlock(&core_lists); ++ if (!item) ++ return -ENOENT; ++ ++ return i2c_probe_address(adapter, addr, kind, driver->detect_client); ++} ++ ++static void i2c_notify(struct i2c_adapter *adap, struct i2c_driver *driver) ++{ ++ if (driver->attach_adapter) ++ driver->attach_adapter(adap); ++ ++ /* Probe devices if the driver provided the necessary information ++ (detect_client and address_data) */ ++ if (driver->detect_client && driver->address_data && ++ (driver->class & adap->class)) ++ i2c_probe(adap, driver->address_data, driver->detect_client); ++} ++ + struct i2c_adapter* i2c_get_adapter(int id) + { + struct i2c_adapter *adapter; + +- down(&core_lists); ++ mutex_lock(&core_lists); + adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + if (adapter && !try_module_get(adapter->owner)) + adapter = NULL; + +- up(&core_lists); ++ mutex_unlock(&core_lists); + return adapter; + } + +@@ -919,12 +954,11 @@ + u8 length, u8 *values) + { + union i2c_smbus_data data; +- int i; ++ + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; +- for (i = 1; i <= length; i++) +- data.block[i] = values[i-1]; + data.block[0] = length; ++ memcpy(&data.block[1], values, length); + return i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA,&data); +@@ -934,16 +968,14 @@ + s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) + { + union i2c_smbus_data data; +- int i; ++ + if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_READ,command, + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; +- else { +- for (i = 1; i <= data.block[0]; i++) +- values[i-1] = data.block[i]; +- return data.block[0]; +- } ++ ++ memcpy(values, &data.block[1], data.block[0]); ++ return data.block[0]; + } + + s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, +@@ -1118,10 +1150,10 @@ + flags &= I2C_M_TEN | I2C_CLIENT_PEC; + + if (adapter->algo->smbus_xfer) { +- down(&adapter->bus_lock); ++ mutex_lock(&adapter->bus_lock); + res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, + command,size,data); +- up(&adapter->bus_lock); ++ mutex_unlock(&adapter->bus_lock); + } else + res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, + command,size,data); +@@ -1153,6 +1185,7 @@ + EXPORT_SYMBOL(i2c_get_adapter); + EXPORT_SYMBOL(i2c_put_adapter); + EXPORT_SYMBOL(i2c_probe); ++EXPORT_SYMBOL(i2c_probe_device); + + EXPORT_SYMBOL(i2c_smbus_xfer); + EXPORT_SYMBOL(i2c_smbus_write_quick); +--- linux-2.6.16.orig/drivers/i2c/busses/scx200_acb.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/scx200_acb.c 2006-03-22 17:06:16.000000000 +0100 +@@ -1,27 +1,26 @@ +-/* linux/drivers/i2c/scx200_acb.c +- ++/* + Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> + + National Semiconductor SCx200 ACCESS.bus support +- ++ Also supports the AMD CS5535 and AMD CS5536 ++ + Based on i2c-keywest.c which is: + Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org> + Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> +- ++ + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (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 <linux/module.h> +@@ -32,7 +31,9 @@ + #include <linux/smp_lock.h> + #include <linux/pci.h> + #include <linux/delay.h> ++#include <linux/mutex.h> + #include <asm/io.h> ++#include <asm/msr.h> + + #include <linux/scx200.h> + +@@ -47,16 +48,7 @@ + module_param_array(base, int, NULL, 0); + MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers"); + +-#ifdef DEBUG +-#define DBG(x...) printk(KERN_DEBUG NAME ": " x) +-#else +-#define DBG(x...) +-#endif +- +-/* The hardware supports interrupt driven mode too, but I haven't +- implemented that. */ +-#define POLLED_MODE 1 +-#define POLL_TIMEOUT (HZ) ++#define POLL_TIMEOUT (HZ/5) + + enum scx200_acb_state { + state_idle, +@@ -79,12 +71,11 @@ + }; + + /* Physical interface */ +-struct scx200_acb_iface +-{ ++struct scx200_acb_iface { + struct scx200_acb_iface *next; + struct i2c_adapter adapter; + unsigned base; +- struct semaphore sem; ++ struct mutex mutex; + + /* State machine data */ + enum scx200_acb_state state; +@@ -100,7 +91,7 @@ + #define ACBSDA (iface->base + 0) + #define ACBST (iface->base + 1) + #define ACBST_SDAST 0x40 /* SDA Status */ +-#define ACBST_BER 0x20 ++#define ACBST_BER 0x20 + #define ACBST_NEGACK 0x10 /* Negative Acknowledge */ + #define ACBST_STASTR 0x08 /* Stall After Start */ + #define ACBST_MASTER 0x02 +@@ -109,9 +100,9 @@ + #define ACBCTL1 (iface->base + 3) + #define ACBCTL1_STASTRE 0x80 + #define ACBCTL1_NMINTE 0x40 +-#define ACBCTL1_ACK 0x10 +-#define ACBCTL1_STOP 0x02 +-#define ACBCTL1_START 0x01 ++#define ACBCTL1_ACK 0x10 ++#define ACBCTL1_STOP 0x02 ++#define ACBCTL1_START 0x01 + #define ACBADDR (iface->base + 4) + #define ACBCTL2 (iface->base + 5) + #define ACBCTL2_ENABLE 0x01 +@@ -122,8 +113,8 @@ + { + const char *errmsg; + +- DBG("state %s, status = 0x%02x\n", +- scx200_acb_state_name[iface->state], status); ++ dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n", ++ scx200_acb_state_name[iface->state], status); + + if (status & ACBST_BER) { + errmsg = "bus error"; +@@ -133,8 +124,17 @@ + errmsg = "not master"; + goto error; + } +- if (status & ACBST_NEGACK) +- goto negack; ++ if (status & ACBST_NEGACK) { ++ dev_dbg(&iface->adapter.dev, "negative ack in state %s\n", ++ scx200_acb_state_name[iface->state]); ++ ++ iface->state = state_idle; ++ iface->result = -ENXIO; ++ ++ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); ++ outb(ACBST_STASTR | ACBST_NEGACK, ACBST); ++ return; ++ } + + switch (iface->state) { + case state_idle: +@@ -160,10 +160,10 @@ + case state_repeat_start: + outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1); + /* fallthrough */ +- ++ + case state_quick: + if (iface->address_byte & 1) { +- if (iface->len == 1) ++ if (iface->len == 1) + outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1); + else + outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1); +@@ -202,26 +202,15 @@ + outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); + break; + } +- ++ + outb(*iface->ptr++, ACBSDA); + --iface->len; +- ++ + break; + } + + return; + +- negack: +- DBG("negative acknowledge in state %s\n", +- scx200_acb_state_name[iface->state]); +- +- iface->state = state_idle; +- iface->result = -ENXIO; +- +- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1); +- outb(ACBST_STASTR | ACBST_NEGACK, ACBST); +- return; +- + error: + dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg, + scx200_acb_state_name[iface->state]); +@@ -231,20 +220,9 @@ + iface->needs_reset = 1; + } + +-static void scx200_acb_timeout(struct scx200_acb_iface *iface) +-{ +- dev_err(&iface->adapter.dev, "timeout in state %s\n", +- scx200_acb_state_name[iface->state]); +- +- iface->state = state_idle; +- iface->result = -EIO; +- iface->needs_reset = 1; +-} +- +-#ifdef POLLED_MODE + static void scx200_acb_poll(struct scx200_acb_iface *iface) + { +- u8 status = 0; ++ u8 status; + unsigned long timeout; + + timeout = jiffies + POLL_TIMEOUT; +@@ -254,17 +232,21 @@ + scx200_acb_machine(iface, status); + return; + } +- msleep(10); ++ yield(); + } + +- scx200_acb_timeout(iface); ++ dev_err(&iface->adapter.dev, "timeout in state %s\n", ++ scx200_acb_state_name[iface->state]); ++ ++ iface->state = state_idle; ++ iface->result = -EIO; ++ iface->needs_reset = 1; + } +-#endif /* POLLED_MODE */ + + static void scx200_acb_reset(struct scx200_acb_iface *iface) + { + /* Disable the ACCESS.bus device and Configure the SCL +- frequency: 16 clock cycles */ ++ frequency: 16 clock cycles */ + outb(0x70, ACBCTL2); + /* Polling mode */ + outb(0, ACBCTL1); +@@ -283,9 +265,9 @@ + } + + static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, +- u16 address, unsigned short flags, +- char rw, u8 command, int size, +- union i2c_smbus_data *data) ++ u16 address, unsigned short flags, ++ char rw, u8 command, int size, ++ union i2c_smbus_data *data) + { + struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); + int len; +@@ -295,53 +277,47 @@ + + switch (size) { + case I2C_SMBUS_QUICK: +- len = 0; +- buffer = NULL; +- break; ++ len = 0; ++ buffer = NULL; ++ break; ++ + case I2C_SMBUS_BYTE: +- if (rw == I2C_SMBUS_READ) { +- len = 1; +- buffer = &data->byte; +- } else { +- len = 1; +- buffer = &command; +- } +- break; ++ len = 1; ++ buffer = rw ? &data->byte : &command; ++ break; ++ + case I2C_SMBUS_BYTE_DATA: +- len = 1; +- buffer = &data->byte; +- break; ++ len = 1; ++ buffer = &data->byte; ++ break; ++ + case I2C_SMBUS_WORD_DATA: + len = 2; +- cur_word = cpu_to_le16(data->word); +- buffer = (u8 *)&cur_word; ++ cur_word = cpu_to_le16(data->word); ++ buffer = (u8 *)&cur_word; + break; ++ + case I2C_SMBUS_BLOCK_DATA: +- len = data->block[0]; +- buffer = &data->block[1]; ++ len = data->block[0]; ++ buffer = &data->block[1]; + break; ++ + default: +- return -EINVAL; ++ return -EINVAL; + } + +- DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", +- size, address, command, len, rw == I2C_SMBUS_READ); ++ dev_dbg(&adapter->dev, ++ "size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n", ++ size, address, command, len, rw); + + if (!len && rw == I2C_SMBUS_READ) { +- dev_warn(&adapter->dev, "zero length read\n"); ++ dev_dbg(&adapter->dev, "zero length read\n"); + return -EINVAL; + } + +- if (len && !buffer) { +- dev_warn(&adapter->dev, "nonzero length but no buffer\n"); +- return -EFAULT; +- } +- +- down(&iface->sem); ++ mutex_lock(&iface->mutex); + +- iface->address_byte = address<<1; +- if (rw == I2C_SMBUS_READ) +- iface->address_byte |= 1; ++ iface->address_byte = (address << 1) | rw; + iface->command = command; + iface->ptr = buffer; + iface->len = len; +@@ -355,25 +331,21 @@ + else + iface->state = state_address; + +-#ifdef POLLED_MODE + while (iface->state != state_idle) + scx200_acb_poll(iface); +-#else /* POLLED_MODE */ +-#error Interrupt driven mode not implemented +-#endif /* POLLED_MODE */ + + if (iface->needs_reset) + scx200_acb_reset(iface); + + rc = iface->result; + +- up(&iface->sem); ++ mutex_unlock(&iface->mutex); + + if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ) +- data->word = le16_to_cpu(cur_word); ++ data->word = le16_to_cpu(cur_word); + + #ifdef DEBUG +- DBG(": transfer done, result: %d", rc); ++ dev_dbg(&adapter->dev, "transfer done, result: %d", rc); + if (buffer) { + int i; + printk(" data:"); +@@ -400,17 +372,18 @@ + }; + + static struct scx200_acb_iface *scx200_acb_list; ++static DECLARE_MUTEX(scx200_acb_list_mutex); + + static int scx200_acb_probe(struct scx200_acb_iface *iface) + { + u8 val; + + /* Disable the ACCESS.bus device and Configure the SCL +- frequency: 16 clock cycles */ ++ frequency: 16 clock cycles */ + outb(0x70, ACBCTL2); + + if (inb(ACBCTL2) != 0x70) { +- DBG("ACBCTL2 readback failed\n"); ++ pr_debug(NAME ": ACBCTL2 readback failed\n"); + return -ENXIO; + } + +@@ -418,7 +391,8 @@ + + val = inb(ACBCTL1); + if (val) { +- DBG("disabled, but ACBCTL1=0x%02x\n", val); ++ pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n", ++ val); + return -ENXIO; + } + +@@ -428,18 +402,19 @@ + + val = inb(ACBCTL1); + if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) { +- DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val); ++ pr_debug(NAME ": enabled, but NMINTE won't be set, " ++ "ACBCTL1=0x%02x\n", val); + return -ENXIO; + } + + return 0; + } + +-static int __init scx200_acb_create(int base, int index) ++static int __init scx200_acb_create(const char *text, int base, int index) + { + struct scx200_acb_iface *iface; + struct i2c_adapter *adapter; +- int rc = 0; ++ int rc; + char description[64]; + + iface = kzalloc(sizeof(*iface), GFP_KERNEL); +@@ -451,50 +426,51 @@ + + adapter = &iface->adapter; + i2c_set_adapdata(adapter, iface); +- snprintf(adapter->name, I2C_NAME_SIZE, "SCx200 ACB%d", index); ++ snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index); + adapter->owner = THIS_MODULE; + adapter->id = I2C_HW_SMBUS_SCX200; + adapter->algo = &scx200_acb_algorithm; +- adapter->class = I2C_CLASS_HWMON; ++ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_DATA; ++ ++ mutex_init(&iface->mutex); + +- init_MUTEX(&iface->sem); ++ snprintf(description, sizeof(description), "%s ACCESS.bus [%s]", ++ text, adapter->name); + +- snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); + if (request_region(base, 8, description) == 0) { +- dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n", ++ printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", + base, base + 8-1); + rc = -EBUSY; +- goto errout; ++ goto errout_free; + } + iface->base = base; + + rc = scx200_acb_probe(iface); + if (rc) { +- dev_warn(&adapter->dev, "probe failed\n"); +- goto errout; ++ printk(KERN_WARNING NAME ": probe failed\n"); ++ goto errout_release; + } + + scx200_acb_reset(iface); + + if (i2c_add_adapter(adapter) < 0) { +- dev_err(&adapter->dev, "failed to register\n"); ++ printk(KERN_ERR NAME ": failed to register\n"); + rc = -ENODEV; +- goto errout; ++ goto errout_release; + } + +- lock_kernel(); ++ down(&scx200_acb_list_mutex); + iface->next = scx200_acb_list; + scx200_acb_list = iface; +- unlock_kernel(); ++ up(&scx200_acb_list_mutex); + + return 0; + ++ errout_release: ++ release_region(iface->base, 8); ++ errout_free: ++ kfree(iface); + errout: +- if (iface) { +- if (iface->base) +- release_region(iface->base, 8); +- kfree(iface); +- } + return rc; + } + +@@ -504,50 +480,69 @@ + { }, + }; + ++static struct pci_device_id divil_pci[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, ++ { } /* NULL entry */ ++}; ++ ++#define MSR_LBAR_SMB 0x5140000B ++ ++static int scx200_add_cs553x(void) ++{ ++ u32 low, hi; ++ u32 smb_base; ++ ++ /* Grab & reserve the SMB I/O range */ ++ rdmsr(MSR_LBAR_SMB, low, hi); ++ ++ /* Check the IO mask and whether SMB is enabled */ ++ if (hi != 0x0000F001) { ++ printk(KERN_WARNING NAME ": SMBus not enabled\n"); ++ return -ENODEV; ++ } ++ ++ /* SMBus IO size is 8 bytes */ ++ smb_base = low & 0x0000FFF8; ++ ++ return scx200_acb_create("CS5535", smb_base, 0); ++} ++ + static int __init scx200_acb_init(void) + { + int i; +- int rc; ++ int rc = -ENODEV; + + pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); + + /* Verify that this really is a SCx200 processor */ +- if (pci_dev_present(scx200) == 0) +- return -ENODEV; ++ if (pci_dev_present(scx200)) { ++ for (i = 0; i < MAX_DEVICES; ++i) { ++ if (base[i] > 0) ++ rc = scx200_acb_create("SCx200", base[i], i); ++ } ++ } else if (pci_dev_present(divil_pci)) ++ rc = scx200_add_cs553x(); + +- rc = -ENXIO; +- for (i = 0; i < MAX_DEVICES; ++i) { +- if (base[i] > 0) +- rc = scx200_acb_create(base[i], i); +- } +- if (scx200_acb_list) +- return 0; + return rc; + } + + static void __exit scx200_acb_cleanup(void) + { + struct scx200_acb_iface *iface; +- lock_kernel(); ++ ++ down(&scx200_acb_list_mutex); + while ((iface = scx200_acb_list) != NULL) { + scx200_acb_list = iface->next; +- unlock_kernel(); ++ up(&scx200_acb_list_mutex); + + i2c_del_adapter(&iface->adapter); + release_region(iface->base, 8); + kfree(iface); +- lock_kernel(); ++ down(&scx200_acb_list_mutex); + } +- unlock_kernel(); ++ up(&scx200_acb_list_mutex); + } + + module_init(scx200_acb_init); + module_exit(scx200_acb_cleanup); +- +-/* +- Local variables: +- compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules" +- c-basic-offset: 8 +- End: +-*/ +- +--- linux-2.6.16.orig/Documentation/i2c/busses/scx200_acb 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/Documentation/i2c/busses/scx200_acb 2006-03-22 17:06:15.000000000 +0100 +@@ -6,9 +6,10 @@ + ----------------- + + * base: int +- Base addresses for the ACCESS.bus controllers ++ Base addresses for the ACCESS.bus controllers on SCx200 and SC1100 devices + + Description + ----------- + +-Enable the use of the ACCESS.bus controllers of a SCx200 processor. ++Enable the use of the ACCESS.bus controller on the Geode SCx200 and ++SC1100 processors and the CS5535 and CS5536 Geode companion devices. +--- linux-2.6.16.orig/drivers/i2c/busses/Kconfig 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/Kconfig 2006-03-22 17:06:16.000000000 +0100 +@@ -163,17 +163,22 @@ + I2C bus. + + config I2C_PIIX4 +- tristate "Intel PIIX4" ++ tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" + depends on I2C && PCI + help + If you say yes to this option, support will be included for the Intel + PIIX4 family of mainboard I2C interfaces. Specifically, the following +- versions of the chipset are supported: ++ versions of the chipset are supported (note that Serverworks is part ++ of Broadcom): + Intel PIIX4 + Intel 440MX ++ ATI IXP200 ++ ATI IXP300 ++ ATI IXP400 + Serverworks OSB4 + Serverworks CSB5 + Serverworks CSB6 ++ Serverworks HT-1000 + SMSC Victory66 + + This driver can also be built as a module. If so, the module +@@ -284,7 +289,10 @@ + This driver is a replacement for (and was inspired by) an older + driver named i2c-philips-par. The new driver supports more devices, + and makes it easier to add support for new devices. +- ++ ++ An adapter type parameter is now mandatory. Please read the file ++ Documentation/i2c/busses/i2c-parport for details. ++ + Another driver exists, named i2c-parport-light, which doesn't depend + on the parport driver. This is meant for embedded systems. Don't say + Y here if you intend to say Y or M there. +@@ -389,10 +397,11 @@ + also be specified with a module parameter. + + config SCx200_ACB +- tristate "NatSemi SCx200 ACCESS.bus" +- depends on I2C && PCI ++ tristate "Geode ACCESS.bus support" ++ depends on X86_32 && I2C && PCI + help +- Enable the use of the ACCESS.bus controllers of a SCx200 processor. ++ Enable the use of the ACCESS.bus controllers on the Geode SCx200 and ++ SC1100 processors and the CS5535 and CS5536 Geode companion devices. + + If you don't know what to do here, say N. + +--- linux-2.6.16.orig/drivers/hwmon/w83792d.c 2006-03-22 17:06:10.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/w83792d.c 2006-03-22 17:06:16.000000000 +0100 +@@ -43,6 +43,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-sysfs.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +@@ -271,7 +272,7 @@ + struct class_device *class_dev; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -300,7 +301,6 @@ + u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */ + }; + +-static int w83792d_attach_adapter(struct i2c_adapter *adapter); + static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind); + static int w83792d_detach_client(struct i2c_client *client); + static struct w83792d_data *w83792d_update_device(struct device *dev); +@@ -315,7 +315,9 @@ + .driver = { + .name = "w83792d", + }, +- .attach_adapter = w83792d_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = w83792d_detect, + .detach_client = w83792d_detach_client, + }; + +@@ -382,30 +384,40 @@ + store_in_reg(MIN, min); + store_in_reg(MAX, max); + +-#define sysfs_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, store_in_min, offset); \ +-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ +- show_in_max, store_in_max, offset); +- +-sysfs_in_reg(0); +-sysfs_in_reg(1); +-sysfs_in_reg(2); +-sysfs_in_reg(3); +-sysfs_in_reg(4); +-sysfs_in_reg(5); +-sysfs_in_reg(6); +-sysfs_in_reg(7); +-sysfs_in_reg(8); +- +-#define device_create_file_in(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute sda_in_input[] = { ++ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), ++ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), ++ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), ++ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), ++ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), ++ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), ++ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), ++ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), ++ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), ++}; ++static struct sensor_device_attribute sda_in_min[] = { ++ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), ++ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), ++ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), ++ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), ++ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), ++ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), ++ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), ++ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), ++ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), ++}; ++static struct sensor_device_attribute sda_in_max[] = { ++ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), ++ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), ++ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), ++ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), ++ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), ++ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), ++ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), ++ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), ++ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), ++}; ++ + + #define show_fan_reg(reg) \ + static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ +@@ -486,28 +498,33 @@ + return count; + } + +-#define sysfs_fan(offset) \ +-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ +- offset); \ +-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ +- show_fan_div, store_fan_div, offset); \ +-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ +- show_fan_min, store_fan_min, offset); +- +-sysfs_fan(1); +-sysfs_fan(2); +-sysfs_fan(3); +-sysfs_fan(4); +-sysfs_fan(5); +-sysfs_fan(6); +-sysfs_fan(7); +- +-#define device_create_file_fan(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute sda_fan_input[] = { ++ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1), ++ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2), ++ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3), ++ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4), ++ SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5), ++ SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6), ++ SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7), ++}; ++static struct sensor_device_attribute sda_fan_min[] = { ++ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1), ++ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2), ++ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3), ++ SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4), ++ SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5), ++ SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6), ++ SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7), ++}; ++static struct sensor_device_attribute sda_fan_div[] = { ++ SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1), ++ SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2), ++ SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3), ++ SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4), ++ SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5), ++ SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6), ++ SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7), ++}; + + + /* read/write the temperature1, includes measured value and limits */ +@@ -539,21 +556,6 @@ + return count; + } + +- +-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0); +-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1, +- store_temp1, 1); +-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, +- store_temp1, 2); +- +-#define device_create_file_temp1(client) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \ +-} while (0) +- +- + /* read/write the temperature2-3, includes measured value and limits */ + + static ssize_t show_temp23(struct device *dev, struct device_attribute *attr, +@@ -590,25 +592,23 @@ + return count; + } + +-#define sysfs_temp23(name,idx) \ +-static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \ +- idx, 0); \ +-static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \ +- show_temp23, store_temp23, idx, 2); \ +-static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \ +- show_temp23, store_temp23, idx, 4); +- +-sysfs_temp23(temp2,0) +-sysfs_temp23(temp3,1) +- +-#define device_create_file_temp_add(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \ +-device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \ +-device_create_file(&client->dev, \ +-&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute_2 sda_temp_input[] = { ++ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0), ++ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0), ++ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0), ++}; ++ ++static struct sensor_device_attribute_2 sda_temp_max[] = { ++ SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1), ++ SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2), ++ SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2), ++}; + ++static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { ++ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2), ++ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4), ++ SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4), ++}; + + /* get reatime status of all sensors items: voltage, temp, fan */ + static ssize_t +@@ -620,10 +620,6 @@ + + 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_pwm(struct device *dev, struct device_attribute *attr, +@@ -711,26 +707,19 @@ + return count; + } + +-#define sysfs_pwm(offset) \ +-static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ +- show_pwm, store_pwm, offset); \ +-static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ +- show_pwmenable, store_pwmenable, offset); \ +- +-sysfs_pwm(1); +-sysfs_pwm(2); +-sysfs_pwm(3); +- +- +-#define device_create_file_pwm(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \ +-} while (0) +- +-#define device_create_file_pwmenable(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute sda_pwm[] = { ++ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), ++ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), ++ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3), ++}; ++static struct sensor_device_attribute sda_pwm_enable[] = { ++ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, ++ show_pwmenable, store_pwmenable, 1), ++ SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, ++ show_pwmenable, store_pwmenable, 2), ++ SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, ++ show_pwmenable, store_pwmenable, 3), ++}; + + + static ssize_t +@@ -764,18 +753,14 @@ + return count; + } + +-#define sysfs_pwm_mode(offset) \ +-static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \ +- show_pwm_mode, store_pwm_mode, offset); +- +-sysfs_pwm_mode(1); +-sysfs_pwm_mode(2); +-sysfs_pwm_mode(3); +- +-#define device_create_file_pwm_mode(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute sda_pwm_mode[] = { ++ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, ++ show_pwm_mode, store_pwm_mode, 1), ++ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, ++ show_pwm_mode, store_pwm_mode, 2), ++ SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, ++ show_pwm_mode, store_pwm_mode, 3), ++}; + + + static ssize_t +@@ -788,12 +773,6 @@ + + static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); + +-#define device_create_file_chassis(client) \ +-do { \ +-device_create_file(&client->dev, &dev_attr_chassis); \ +-} while (0) +- +- + static ssize_t + show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) + { +@@ -824,13 +803,6 @@ + static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, + show_chassis_clear, store_chassis_clear); + +-#define device_create_file_chassis_clear(client) \ +-do { \ +-device_create_file(&client->dev, &dev_attr_chassis_clear); \ +-} while (0) +- +- +- + /* For Smart Fan I / Thermal Cruise */ + static ssize_t + show_thermal_cruise(struct device *dev, struct device_attribute *attr, +@@ -864,20 +836,14 @@ + return count; + } + +-#define sysfs_thermal_cruise(offset) \ +-static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \ +- show_thermal_cruise, store_thermal_cruise, offset); +- +-sysfs_thermal_cruise(1); +-sysfs_thermal_cruise(2); +-sysfs_thermal_cruise(3); +- +-#define device_create_file_thermal_cruise(client, offset) \ +-do { \ +-device_create_file(&client->dev, \ +-&sensor_dev_attr_thermal_cruise##offset.dev_attr); \ +-} while (0) +- ++static struct sensor_device_attribute sda_thermal_cruise[] = { ++ SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO, ++ show_thermal_cruise, store_thermal_cruise, 1), ++ SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO, ++ show_thermal_cruise, store_thermal_cruise, 2), ++ SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO, ++ show_thermal_cruise, store_thermal_cruise, 3), ++}; + + /* For Smart Fan I/Thermal Cruise and Smart Fan II */ + static ssize_t +@@ -916,19 +882,14 @@ + return count; + } + +-#define sysfs_tolerance(offset) \ +-static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \ +- show_tolerance, store_tolerance, offset); +- +-sysfs_tolerance(1); +-sysfs_tolerance(2); +-sysfs_tolerance(3); +- +-#define device_create_file_tolerance(client, offset) \ +-do { \ +-device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \ +-} while (0) +- ++static struct sensor_device_attribute sda_tolerance[] = { ++ SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO, ++ show_tolerance, store_tolerance, 1), ++ SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO, ++ show_tolerance, store_tolerance, 2), ++ SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO, ++ show_tolerance, store_tolerance, 3), ++}; + + /* For Smart Fan II */ + static ssize_t +@@ -964,28 +925,34 @@ + return count; + } + +-#define sysfs_sf2_point(offset, index) \ +-static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \ +- show_sf2_point, store_sf2_point, offset, index); +- +-sysfs_sf2_point(1, 1); /* Fan1 */ +-sysfs_sf2_point(2, 1); /* Fan1 */ +-sysfs_sf2_point(3, 1); /* Fan1 */ +-sysfs_sf2_point(4, 1); /* Fan1 */ +-sysfs_sf2_point(1, 2); /* Fan2 */ +-sysfs_sf2_point(2, 2); /* Fan2 */ +-sysfs_sf2_point(3, 2); /* Fan2 */ +-sysfs_sf2_point(4, 2); /* Fan2 */ +-sysfs_sf2_point(1, 3); /* Fan3 */ +-sysfs_sf2_point(2, 3); /* Fan3 */ +-sysfs_sf2_point(3, 3); /* Fan3 */ +-sysfs_sf2_point(4, 3); /* Fan3 */ +- +-#define device_create_file_sf2_point(client, offset, index) \ +-do { \ +-device_create_file(&client->dev, \ +-&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \ +-} while (0) ++static struct sensor_device_attribute_2 sda_sf2_point[] = { ++ SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 1, 1), ++ SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 2, 1), ++ SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 3, 1), ++ SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 4, 1), ++ ++ SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 1, 2), ++ SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 2, 2), ++ SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 3, 2), ++ SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 4, 2), ++ ++ SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 1, 3), ++ SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 2, 3), ++ SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 3, 3), ++ SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_point, store_sf2_point, 4, 3), ++}; + + + static ssize_t +@@ -1026,39 +993,28 @@ + return count; + } + +-#define sysfs_sf2_level(offset, index) \ +-static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \ +- show_sf2_level, store_sf2_level, offset, index); +- +-sysfs_sf2_level(1, 1); /* Fan1 */ +-sysfs_sf2_level(2, 1); /* Fan1 */ +-sysfs_sf2_level(3, 1); /* Fan1 */ +-sysfs_sf2_level(1, 2); /* Fan2 */ +-sysfs_sf2_level(2, 2); /* Fan2 */ +-sysfs_sf2_level(3, 2); /* Fan2 */ +-sysfs_sf2_level(1, 3); /* Fan3 */ +-sysfs_sf2_level(2, 3); /* Fan3 */ +-sysfs_sf2_level(3, 3); /* Fan3 */ +- +-#define device_create_file_sf2_level(client, offset, index) \ +-do { \ +-device_create_file(&client->dev, \ +-&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \ +-} while (0) +- +- +-/* This function is called when: +- * w83792d_driver is inserted (when this module is loaded), for each +- available adapter +- * when a new adapter is inserted (and w83792d_driver is still present) */ +-static int +-w83792d_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, w83792d_detect); +-} +- ++static struct sensor_device_attribute_2 sda_sf2_level[] = { ++ SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 1, 1), ++ SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 2, 1), ++ SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 3, 1), ++ ++ SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 1, 2), ++ SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 2, 2), ++ SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 3, 2), ++ ++ SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 1, 3), ++ SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 2, 3), ++ SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR, ++ show_sf2_level, store_sf2_level, 3, 3), ++}; + + static int + w83792d_create_subclient(struct i2c_adapter *adapter, +@@ -1147,12 +1103,19 @@ + return err; + } + ++static void device_create_file_fan(struct device *dev, int i) ++{ ++ device_create_file(dev, &sda_fan_input[i].dev_attr); ++ device_create_file(dev, &sda_fan_div[i].dev_attr); ++ device_create_file(dev, &sda_fan_min[i].dev_attr); ++} + + static int + w83792d_detect(struct i2c_adapter *adapter, int address, int kind) + { + int i = 0, val1 = 0, val2; +- struct i2c_client *new_client; ++ struct i2c_client *client; ++ struct device *dev; + struct w83792d_data *data; + int err = 0; + const char *client_name = ""; +@@ -1170,12 +1133,13 @@ + goto ERROR0; + } + +- new_client = &data->client; +- i2c_set_clientdata(new_client, data); +- new_client->addr = address; +- new_client->adapter = adapter; +- new_client->driver = &w83792d_driver; +- new_client->flags = 0; ++ client = &data->client; ++ dev = &client->dev; ++ i2c_set_clientdata(client, data); ++ client->addr = address; ++ client->adapter = adapter; ++ client->driver = &w83792d_driver; ++ client->flags = 0; + + /* Now, we do the remaining detection. */ + +@@ -1184,50 +1148,49 @@ + force_*=... parameter, and the Winbond will be reset to the right + bank. */ + if (kind < 0) { +- if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) { +- dev_warn(&new_client->dev, "Detection failed at step " +- "3\n"); ++ if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) { ++ dev_dbg(dev, "Detection failed at step 1\n"); + goto ERROR1; + } +- val1 = w83792d_read_value(new_client, W83792D_REG_BANK); +- val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); ++ val1 = w83792d_read_value(client, W83792D_REG_BANK); ++ val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN); + /* Check for Winbond ID if in bank 0 */ + if (!(val1 & 0x07)) { /* is Bank0 */ + if (((!(val1 & 0x80)) && (val2 != 0xa3)) || + ((val1 & 0x80) && (val2 != 0x5c))) { ++ dev_dbg(dev, "Detection failed at step 2\n"); + goto ERROR1; + } + } + /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR + should match */ +- if (w83792d_read_value(new_client, ++ if (w83792d_read_value(client, + W83792D_REG_I2C_ADDR) != address) { +- dev_warn(&new_client->dev, "Detection failed " +- "at step 5\n"); ++ dev_dbg(dev, "Detection failed at step 3\n"); + goto ERROR1; + } + } + + /* 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 */ +- w83792d_write_value(new_client, ++ w83792d_write_value(client, + W83792D_REG_BANK, +- (w83792d_read_value(new_client, ++ (w83792d_read_value(client, + W83792D_REG_BANK) & 0x78) | 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + /* get vendor ID */ +- val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); ++ val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN); + if (val2 != 0x5c) { /* the vendor is NOT Winbond */ + goto ERROR1; + } +- val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID); ++ val1 = w83792d_read_value(client, W83792D_REG_WCHIPID); + if (val1 == 0x7a) { + kind = w83792d; + } else { + if (kind == 0) +- dev_warn(&new_client->dev, ++ dev_warn(dev, + "w83792d: Ignoring 'force' parameter for" + " unknown chip at adapter %d, address" + " 0x%02x\n", i2c_adapter_id(adapter), +@@ -1239,120 +1202,86 @@ + if (kind == w83792d) { + client_name = "w83792d"; + } else { +- dev_err(&new_client->dev, "w83792d: Internal error: unknown" ++ dev_err(dev, "w83792d: Internal error: unknown" + " kind (%d)?!?", kind); + goto ERROR1; + } + + /* Fill in the remaining client fields and put into the global list */ +- strlcpy(new_client->name, client_name, I2C_NAME_SIZE); ++ strlcpy(client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ +- if ((err = i2c_attach_client(new_client))) ++ if ((err = i2c_attach_client(client))) + goto ERROR1; + + if ((err = w83792d_detect_subclients(adapter, address, +- kind, new_client))) ++ kind, client))) + goto ERROR2; + + /* Initialize the chip */ +- w83792d_init_client(new_client); ++ w83792d_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 7; i++) { +- data->fan_min[i] = w83792d_read_value(new_client, ++ data->fan_min[i] = w83792d_read_value(client, + W83792D_REG_FAN_MIN[i]); + } + + /* Register sysfs hooks */ +- data->class_dev = hwmon_device_register(&new_client->dev); ++ data->class_dev = hwmon_device_register(dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto ERROR3; + } +- 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_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); ++ for (i = 0; i < 9; i++) { ++ device_create_file(dev, &sda_in_input[i].dev_attr); ++ device_create_file(dev, &sda_in_max[i].dev_attr); ++ device_create_file(dev, &sda_in_min[i].dev_attr); ++ } ++ for (i = 0; i < 3; i++) ++ device_create_file_fan(dev, i); + + /* Read GPIO enable register to check if pins for fan 4,5 are used as + GPIO */ +- val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN); ++ val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN); + if (!(val1 & 0x40)) +- device_create_file_fan(new_client, 4); ++ device_create_file_fan(dev, 3); + if (!(val1 & 0x20)) +- device_create_file_fan(new_client, 5); ++ device_create_file_fan(dev, 4); + +- val1 = w83792d_read_value(new_client, W83792D_REG_PIN); ++ val1 = w83792d_read_value(client, W83792D_REG_PIN); + if (val1 & 0x40) +- device_create_file_fan(new_client, 6); ++ device_create_file_fan(dev, 5); + if (val1 & 0x04) +- device_create_file_fan(new_client, 7); ++ device_create_file_fan(dev, 6); ++ ++ for (i = 0; i < 3; i++) { ++ device_create_file(dev, &sda_temp_input[i].dev_attr); ++ device_create_file(dev, &sda_temp_max[i].dev_attr); ++ device_create_file(dev, &sda_temp_max_hyst[i].dev_attr); ++ device_create_file(dev, &sda_thermal_cruise[i].dev_attr); ++ device_create_file(dev, &sda_tolerance[i].dev_attr); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) { ++ device_create_file(dev, &sda_pwm[i].dev_attr); ++ device_create_file(dev, &sda_pwm_enable[i].dev_attr); ++ device_create_file(dev, &sda_pwm_mode[i].dev_attr); ++ } ++ ++ device_create_file(dev, &dev_attr_alarms); ++ device_create_file(dev, &dev_attr_chassis); ++ device_create_file(dev, &dev_attr_chassis_clear); ++ ++ for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++) ++ device_create_file(dev, &sda_sf2_point[i].dev_attr); + +- device_create_file_temp1(new_client); /* Temp1 */ +- device_create_file_temp_add(new_client, 2); /* Temp2 */ +- device_create_file_temp_add(new_client, 3); /* Temp3 */ +- +- device_create_file_alarms(new_client); +- +- device_create_file_pwm(new_client, 1); +- device_create_file_pwm(new_client, 2); +- device_create_file_pwm(new_client, 3); +- +- device_create_file_pwmenable(new_client, 1); +- device_create_file_pwmenable(new_client, 2); +- device_create_file_pwmenable(new_client, 3); +- +- device_create_file_pwm_mode(new_client, 1); +- device_create_file_pwm_mode(new_client, 2); +- device_create_file_pwm_mode(new_client, 3); +- +- device_create_file_chassis(new_client); +- device_create_file_chassis_clear(new_client); +- +- device_create_file_thermal_cruise(new_client, 1); +- device_create_file_thermal_cruise(new_client, 2); +- device_create_file_thermal_cruise(new_client, 3); +- +- device_create_file_tolerance(new_client, 1); +- device_create_file_tolerance(new_client, 2); +- device_create_file_tolerance(new_client, 3); +- +- device_create_file_sf2_point(new_client, 1, 1); /* Fan1 */ +- device_create_file_sf2_point(new_client, 2, 1); /* Fan1 */ +- device_create_file_sf2_point(new_client, 3, 1); /* Fan1 */ +- device_create_file_sf2_point(new_client, 4, 1); /* Fan1 */ +- device_create_file_sf2_point(new_client, 1, 2); /* Fan2 */ +- device_create_file_sf2_point(new_client, 2, 2); /* Fan2 */ +- device_create_file_sf2_point(new_client, 3, 2); /* Fan2 */ +- device_create_file_sf2_point(new_client, 4, 2); /* Fan2 */ +- device_create_file_sf2_point(new_client, 1, 3); /* Fan3 */ +- device_create_file_sf2_point(new_client, 2, 3); /* Fan3 */ +- device_create_file_sf2_point(new_client, 3, 3); /* Fan3 */ +- device_create_file_sf2_point(new_client, 4, 3); /* Fan3 */ +- +- device_create_file_sf2_level(new_client, 1, 1); /* Fan1 */ +- device_create_file_sf2_level(new_client, 2, 1); /* Fan1 */ +- device_create_file_sf2_level(new_client, 3, 1); /* Fan1 */ +- device_create_file_sf2_level(new_client, 1, 2); /* Fan2 */ +- device_create_file_sf2_level(new_client, 2, 2); /* Fan2 */ +- device_create_file_sf2_level(new_client, 3, 2); /* Fan2 */ +- device_create_file_sf2_level(new_client, 1, 3); /* Fan3 */ +- device_create_file_sf2_level(new_client, 2, 3); /* Fan3 */ +- device_create_file_sf2_level(new_client, 3, 3); /* Fan3 */ ++ for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++) ++ device_create_file(dev, &sda_sf2_level[i].dev_attr); + + return 0; + +@@ -1366,7 +1295,7 @@ + kfree(data->lm75[1]); + } + ERROR2: +- i2c_detach_client(new_client); ++ i2c_detach_client(client); + ERROR1: + kfree(data); + ERROR0: +@@ -1434,7 +1363,7 @@ + int i, j; + u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after + (jiffies - data->last_updated, (unsigned long) (HZ * 3)) +@@ -1545,7 +1474,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + #ifdef DEBUG + w83792d_print_debug(data, dev); +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-amd756-s4882.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-amd756-s4882.c 2006-03-22 17:06:15.000000000 +0100 +@@ -38,6 +38,7 @@ + #include <linux/slab.h> + #include <linux/init.h> + #include <linux/i2c.h> ++#include <linux/mutex.h> + + extern struct i2c_adapter amd756_smbus; + +@@ -45,7 +46,7 @@ + static struct i2c_algorithm *s4882_algo; + + /* Wrapper access functions for multiplexed SMBus */ +-static struct semaphore amd756_lock; ++static DEFINE_MUTEX(amd756_lock); + + static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, +@@ -59,12 +60,12 @@ + || addr == 0x18) + return -1; + +- down(&amd756_lock); ++ mutex_lock(&amd756_lock); + + error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, + command, size, data); + +- up(&amd756_lock); ++ mutex_unlock(&amd756_lock); + + return error; + } +@@ -87,7 +88,7 @@ + if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) + return -1; + +- down(&amd756_lock); ++ mutex_lock(&amd756_lock); + + if (last_channels != channels) { + union i2c_smbus_data mplxdata; +@@ -105,7 +106,7 @@ + command, size, data); + + UNLOCK: +- up(&amd756_lock); ++ mutex_unlock(&amd756_lock); + return error; + } + +@@ -166,8 +167,6 @@ + } + + printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); +- init_MUTEX(&amd756_lock); +- + /* Define the 5 virtual adapters and algorithms structures */ + if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter), + GFP_KERNEL))) { +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-isa.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-isa.c 2006-03-22 17:06:15.000000000 +0100 +@@ -125,7 +125,7 @@ + + static int __init i2c_isa_init(void) + { +- init_MUTEX(&isa_adapter.clist_lock); ++ mutex_init(&isa_adapter.clist_lock); + INIT_LIST_HEAD(&isa_adapter.clients); + + isa_adapter.nr = ANY_I2C_ISA_BUS; +--- linux-2.6.16.orig/drivers/i2c/chips/eeprom.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/eeprom.c 2006-03-22 17:06:16.000000000 +0100 +@@ -33,6 +33,7 @@ + #include <linux/sched.h> + #include <linux/jiffies.h> + #include <linux/i2c.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, +@@ -54,7 +55,7 @@ + /* Each client has this additional data */ + struct eeprom_data { + struct i2c_client client; +- struct semaphore update_lock; ++ struct mutex update_lock; + u8 valid; /* bitfield, bit!=0 if slice is valid */ + unsigned long last_updated[8]; /* In jiffies, 8 slices */ + u8 data[EEPROM_SIZE]; /* Register values */ +@@ -62,7 +63,6 @@ + }; + + +-static int eeprom_attach_adapter(struct i2c_adapter *adapter); + static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind); + static int eeprom_detach_client(struct i2c_client *client); + +@@ -72,7 +72,9 @@ + .name = "eeprom", + }, + .id = I2C_DRIVERID_EEPROM, +- .attach_adapter = eeprom_attach_adapter, ++ .class = I2C_CLASS_DATA, ++ .address_data = &addr_data, ++ .detect_client = eeprom_detect, + .detach_client = eeprom_detach_client, + }; + +@@ -81,7 +83,7 @@ + struct eeprom_data *data = i2c_get_clientdata(client); + int i, j; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (!(data->valid & (1 << slice)) || + time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { +@@ -107,7 +109,7 @@ + data->valid |= (1 << slice); + } + exit: +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + } + + static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count) +@@ -149,11 +151,6 @@ + .read = eeprom_read, + }; + +-static int eeprom_attach_adapter(struct i2c_adapter *adapter) +-{ +- return i2c_probe(adapter, &addr_data, eeprom_detect); +-} +- + /* This function is called by i2c_probe */ + static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) + { +@@ -187,7 +184,7 @@ + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + data->nature = UNKNOWN; + + /* Tell the I2C layer a new client has arrived */ +--- linux-2.6.16.orig/drivers/i2c/chips/max6875.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/max6875.c 2006-03-22 17:06:15.000000000 +0100 +@@ -31,7 +31,7 @@ + #include <linux/module.h> + #include <linux/slab.h> + #include <linux/i2c.h> +-#include <asm/semaphore.h> ++#include <linux/mutex.h> + + /* Do not scan - the MAX6875 access method will write to some EEPROM chips */ + static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +@@ -54,7 +54,7 @@ + /* Each client has this additional data */ + struct max6875_data { + struct i2c_client client; +- struct semaphore update_lock; ++ struct mutex update_lock; + + u32 valid; + u8 data[USER_EEPROM_SIZE]; +@@ -83,7 +83,7 @@ + if (slice >= USER_EEPROM_SLICES) + return; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + buf = &data->data[slice << SLICE_BITS]; + +@@ -122,7 +122,7 @@ + data->valid |= (1 << slice); + } + exit_up: +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + } + + static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, +@@ -196,7 +196,7 @@ + real_client->driver = &max6875_driver; + real_client->flags = 0; + strlcpy(real_client->name, "max6875", I2C_NAME_SIZE); +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Init fake client data */ + /* set the client data to the i2c_client so that it will get freed */ +--- linux-2.6.16.orig/drivers/i2c/chips/pcf8591.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/pcf8591.c 2006-03-22 17:06:15.000000000 +0100 +@@ -24,6 +24,7 @@ + #include <linux/init.h> + #include <linux/slab.h> + #include <linux/i2c.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, +@@ -74,7 +75,7 @@ + + struct pcf8591_data { + struct i2c_client client; +- struct semaphore update_lock; ++ struct mutex update_lock; + + u8 control; + u8 aout; +@@ -144,13 +145,13 @@ + struct pcf8591_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + if (val) + data->control |= PCF8591_CONTROL_AOEF; + else + data->control &= ~PCF8591_CONTROL_AOEF; + i2c_smbus_write_byte(client, data->control); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -200,7 +201,7 @@ + /* Fill in the remaining client fields and put it into the global + list */ + strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE); +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -265,7 +266,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8591_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) { + data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) +@@ -278,7 +279,7 @@ + } + value = i2c_smbus_read_byte(client); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + if ((channel == 2 && input_mode == 2) || + (channel != 3 && (input_mode == 1 || input_mode == 3))) +--- linux-2.6.16.orig/drivers/i2c/chips/tps65010.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/tps65010.c 2006-03-22 17:06:15.000000000 +0100 +@@ -32,6 +32,7 @@ + #include <linux/suspend.h> + #include <linux/debugfs.h> + #include <linux/seq_file.h> ++#include <linux/mutex.h> + + #include <asm/irq.h> + #include <asm/mach-types.h> +@@ -81,7 +82,7 @@ + + struct tps65010 { + struct i2c_client client; +- struct semaphore lock; ++ struct mutex lock; + int irq; + struct work_struct work; + struct dentry *file; +@@ -218,7 +219,7 @@ + seq_printf(s, "driver %s\nversion %s\nchip %s\n\n", + DRIVER_NAME, DRIVER_VERSION, chip); + +- down(&tps->lock); ++ mutex_lock(&tps->lock); + + /* FIXME how can we tell whether a battery is present? + * likely involves a charge gauging chip (like BQ26501). +@@ -300,7 +301,7 @@ + (v2 & (1 << (4 + i))) ? "rising" : "falling"); + } + +- up(&tps->lock); ++ mutex_unlock(&tps->lock); + return 0; + } + +@@ -416,7 +417,7 @@ + { + struct tps65010 *tps = _tps; + +- down(&tps->lock); ++ mutex_lock(&tps->lock); + + tps65010_interrupt(tps); + +@@ -444,7 +445,7 @@ + if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags)) + enable_irq(tps->irq); + +- up(&tps->lock); ++ mutex_unlock(&tps->lock); + } + + static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) +@@ -505,7 +506,7 @@ + if (!tps) + return 0; + +- init_MUTEX(&tps->lock); ++ mutex_init(&tps->lock); + INIT_WORK(&tps->work, tps65010_work, tps); + tps->irq = -1; + tps->client.addr = address; +@@ -695,7 +696,7 @@ + if ((gpio < GPIO1) || (gpio > GPIO4)) + return -EINVAL; + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + +@@ -720,7 +721,7 @@ + gpio, value ? "high" : "low", + i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return status; + } + EXPORT_SYMBOL(tps65010_set_gpio_out_value); +@@ -745,7 +746,7 @@ + led = LED2; + } + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, +@@ -771,7 +772,7 @@ + default: + printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n", + DRIVER_NAME); +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return -EINVAL; + } + +@@ -781,7 +782,7 @@ + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_on register\n", + DRIVER_NAME, led); +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return status; + } + +@@ -794,7 +795,7 @@ + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_per register\n", + DRIVER_NAME, led); +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return status; + } + +@@ -802,7 +803,7 @@ + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_PER + offs)); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + + return status; + } +@@ -820,7 +821,7 @@ + if (!the_tps) + return -ENODEV; + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2); + vdcdc2 &= ~(1 << 1); +@@ -831,7 +832,7 @@ + + pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return status; + } + EXPORT_SYMBOL(tps65010_set_vib); +@@ -848,7 +849,7 @@ + if (!the_tps) + return -ENODEV; + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, + mode ? "enable" : "disable", +@@ -876,7 +877,7 @@ + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + + return status; + } +@@ -894,7 +895,7 @@ + if (!the_tps) + return -ENODEV; + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); +@@ -909,7 +910,7 @@ + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + + return status; + } +@@ -931,7 +932,7 @@ + if (!the_tps || the_tps->por) + return -ENODEV; + +- down(&the_tps->lock); ++ mutex_lock(&the_tps->lock); + + pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", + DRIVER_NAME, +@@ -959,7 +960,7 @@ + if (status != 0) { + printk(KERN_ERR "%s: Failed to write chconfig register\n", + DRIVER_NAME); +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + return status; + } + +@@ -977,7 +978,7 @@ + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + +- up(&the_tps->lock); ++ mutex_unlock(&the_tps->lock); + + return status; + } +--- linux-2.6.16.orig/include/linux/i2c.h 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/include/linux/i2c.h 2006-03-22 17:06:21.000000000 +0100 +@@ -32,7 +32,7 @@ + #include <linux/mod_devicetable.h> + #include <linux/device.h> /* for struct device */ + #include <linux/sched.h> /* for completion */ +-#include <asm/semaphore.h> ++#include <linux/mutex.h> + + /* --- For i2c-isa ---------------------------------------------------- */ + +@@ -48,6 +48,7 @@ + struct i2c_adapter; + struct i2c_client; + struct i2c_driver; ++struct i2c_client_address_data; + union i2c_smbus_data; + + /* +@@ -116,6 +117,7 @@ + struct i2c_driver { + int id; + unsigned int class; ++ struct i2c_client_address_data *address_data; + + /* Notifies the driver that a new bus has appeared. This routine + * can be used by the driver to test if the bus meets its conditions +@@ -133,6 +135,15 @@ + */ + int (*detach_client)(struct i2c_client *); + ++ /* Requests that the driver validate an address on a bus and attach a ++ * new client. If this routine is supplied, it will be called for ++ * each device on new buses that appear, provided the bus class ++ * matches the class field and devices exist at the addresses listed ++ * in the address_data field. For most drivers, this mechanism can ++ * be used instead of an attach_adapter routine. ++ */ ++ int (*detect_client)(struct i2c_adapter *, int addr, int kind); ++ + /* a ioctl like command that can be used to perform specific functions + * with the device. + */ +@@ -225,8 +236,8 @@ + int (*client_unregister)(struct i2c_client *); + + /* data fields that are valid for all devices */ +- struct semaphore bus_lock; +- struct semaphore clist_lock; ++ struct mutex bus_lock; ++ struct mutex clist_lock; + + int timeout; + int retries; +@@ -262,7 +273,7 @@ + #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ + #define I2C_CLASS_TV_ANALOG (1<<1) /* bttv + friends */ + #define I2C_CLASS_TV_DIGITAL (1<<2) /* dvb cards */ +-#define I2C_CLASS_DDC (1<<3) /* i2c-matroxfb ? */ ++#define I2C_CLASS_DATA (1<<3) /* data storage */ + #define I2C_CLASS_CAM_ANALOG (1<<4) /* camera with analog CCD */ + #define I2C_CLASS_CAM_DIGITAL (1<<5) /* most webcams */ + #define I2C_CLASS_SOUND (1<<6) /* sound devices */ +@@ -329,6 +340,10 @@ + struct i2c_client_address_data *address_data, + int (*found_proc) (struct i2c_adapter *, int, int)); + ++/* Direct chip probing function to create clients by address */ ++extern int i2c_probe_device(struct i2c_adapter *adapter, int driver_id, ++ int addr, int kind); ++ + /* An ioctl like call to set div. parameters of the adapter. + */ + extern int i2c_control(struct i2c_client *,unsigned int, unsigned long); +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-pxa.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-pxa.c 2006-03-22 17:06:15.000000000 +0100 +@@ -647,7 +647,7 @@ + } + + /* +- * We are protected by the adapter bus semaphore. ++ * We are protected by the adapter bus mutex. + */ + static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) + { +--- linux-2.6.16.orig/drivers/hwmon/adm1021.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/adm1021.c 2006-03-22 17:06:16.000000000 +0100 +@@ -26,6 +26,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + + /* Addresses to scan */ +@@ -92,7 +93,7 @@ + struct class_device *class_dev; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -111,7 +112,6 @@ + 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); +@@ -130,7 +130,9 @@ + .name = "adm1021", + }, + .id = I2C_DRIVERID_ADM1021, +- .attach_adapter = adm1021_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = adm1021_detect, + .detach_client = adm1021_detach_client, + }; + +@@ -162,10 +164,10 @@ + struct adm1021_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm1021_write_value(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + set(temp_max, ADM1021_REG_TOS_W); +@@ -182,13 +184,6 @@ + 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_probe(adapter, &addr_data, adm1021_detect); +-} +- + static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) + { + int i; +@@ -275,7 +270,7 @@ + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -351,7 +346,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -375,7 +370,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/adm1025.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/adm1025.c 2006-03-22 17:06:16.000000000 +0100 +@@ -53,6 +53,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -107,7 +108,6 @@ + * 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); +@@ -122,7 +122,9 @@ + .name = "adm1025", + }, + .id = I2C_DRIVERID_ADM1025, +- .attach_adapter = adm1025_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = adm1025_detect, + .detach_client = adm1025_detach_client, + }; + +@@ -133,7 +135,7 @@ + struct adm1025_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -207,11 +209,11 @@ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } \ + static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ +@@ -221,11 +223,11 @@ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } \ + static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ +@@ -247,11 +249,11 @@ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } \ + static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ +@@ -261,11 +263,11 @@ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } \ + static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ +@@ -307,13 +309,6 @@ + * Real code + */ + +-static int adm1025_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, adm1025_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -404,7 +399,7 @@ + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -523,7 +518,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int i; +@@ -558,7 +553,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/adm1026.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/adm1026.c 2006-03-22 17:06:21.000000000 +0100 +@@ -32,6 +32,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +@@ -260,10 +261,10 @@ + struct adm1026_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ +@@ -294,13 +295,11 @@ + 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 int adm1026_read_value(struct i2c_client *client, u8 reg); ++static int adm1026_write_value(struct i2c_client *client, u8 reg, 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); +@@ -311,18 +310,12 @@ + .driver = { + .name = "adm1026", + }, +- .attach_adapter = adm1026_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = adm1026_detect, + .detach_client = adm1026_detach_client, + }; + +-static int adm1026_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) { +- return 0; +- } +- return i2c_probe(adapter, &addr_data, adm1026_detect); +-} +- + static int adm1026_detach_client(struct i2c_client *client) + { + struct adm1026_data *data = i2c_get_clientdata(client); +@@ -575,7 +568,7 @@ + int i; + long value, alarms, gpio; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + if (!data->valid + || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { + /* Things that change quickly */ +@@ -710,7 +703,7 @@ + dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); + data->vid = (data->gpio >> 11) & 0x1f; + data->valid = 1; +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return data; + } + +@@ -739,10 +732,10 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, +@@ -762,10 +755,10 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -813,10 +806,10 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) +@@ -831,10 +824,10 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -874,11 +867,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -939,7 +932,7 @@ + if (new_div == 0) { + return -EINVAL; + } +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + orig_div = data->fan_div[nr]; + data->fan_div[nr] = DIV_FROM_REG(new_div); + +@@ -958,7 +951,7 @@ + if (data->fan_div[nr] != orig_div) { + fixup_fan_min(dev,nr,orig_div); + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1001,11 +994,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, +@@ -1025,11 +1018,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1064,11 +1057,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1115,11 +1108,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1150,11 +1143,11 @@ + int val = simple_strtol(buf, NULL, 10); + + if ((val == 1) || (val==0)) { +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + return count; + } +@@ -1184,11 +1177,11 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1212,10 +1205,10 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->analog_out = DAC_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1267,7 +1260,7 @@ + int val = simple_strtol(buf, NULL, 10); + unsigned long mask; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->alarm_mask = val & 0x7fffffff; + mask = data->alarm_mask + | (data->gpio_mask & 0x10000 ? 0x80000000 : 0); +@@ -1282,7 +1275,7 @@ + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK4, + mask & 0xff); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1303,7 +1296,7 @@ + int val = simple_strtol(buf, NULL, 10); + long gpio; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->gpio = val & 0x1ffff; + gpio = data->gpio; + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); +@@ -1311,7 +1304,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1331,7 +1324,7 @@ + int val = simple_strtol(buf, NULL, 10); + long mask; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->gpio_mask = val & 0x1ffff; + mask = data->gpio_mask; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); +@@ -1339,7 +1332,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -1359,10 +1352,10 @@ + if (data->pwm1.enable == 1) { + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->pwm1.pwm = PWM_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + } + return count; + } +@@ -1378,14 +1371,14 @@ + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) +@@ -1406,7 +1399,7 @@ + int old_enable; + + if ((val >= 0) && (val < 3)) { +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + old_enable = data->pwm1.enable; + data->pwm1.enable = val; + data->config1 = (data->config1 & ~CFG1_PWM_AFC) +@@ -1424,7 +1417,7 @@ + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm1.pwm); + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + } + return count; + } +@@ -1541,7 +1534,7 @@ + /* Fill in the remaining client fields */ + data->type = kind; + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +--- linux-2.6.16.orig/drivers/hwmon/adm1031.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/adm1031.c 2006-03-22 17:06:16.000000000 +0100 +@@ -28,6 +28,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Following macros takes channel parameter starting from 0 to 2 */ + #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) +@@ -70,7 +71,7 @@ + struct adm1031_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + int chip_type; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ +@@ -97,7 +98,6 @@ + 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); +@@ -108,7 +108,9 @@ + .driver = { + .name = "adm1031", + }, +- .attach_adapter = adm1031_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = adm1031_detect, + .detach_client = adm1031_detach_client, + }; + +@@ -262,10 +264,10 @@ + + old_fan_mode = data->conf1; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return ret; + } + if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ +@@ -288,7 +290,7 @@ + } + data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); + adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -329,11 +331,11 @@ + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) +@@ -349,11 +351,11 @@ + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -405,11 +407,11 @@ + int val = simple_strtol(buf, NULL, 10); + int reg; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + data->pwm[nr] = PWM_TO_REG(val); +@@ -417,7 +419,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -511,7 +513,7 @@ + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + if (val) { + data->fan_min[nr] = + FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); +@@ -519,7 +521,7 @@ + data->fan_min[nr] = 0xff; + } + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t +@@ -540,7 +542,7 @@ + if (tmp == 0xff) + return -EINVAL; + +- down(&data->update_lock); ++ mutex_lock(&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 / +@@ -553,7 +555,7 @@ + data->fan_div[nr]); + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), + data->fan_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -627,11 +629,11 @@ + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t +@@ -643,11 +645,11 @@ + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t +@@ -659,11 +661,11 @@ + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -722,13 +724,6 @@ + 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_probe(adapter, &addr_data, adm1031_detect); +-} +- + /* This function is called by i2c_probe */ + static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) + { +@@ -778,7 +773,7 @@ + + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -891,7 +886,7 @@ + struct adm1031_data *data = i2c_get_clientdata(client); + int chan; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -965,7 +960,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/adm9240.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/adm9240.c 2006-03-22 17:06:16.000000000 +0100 +@@ -49,6 +49,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, +@@ -129,7 +130,6 @@ + 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); +@@ -141,7 +141,9 @@ + .name = "adm9240", + }, + .id = I2C_DRIVERID_ADM9240, +- .attach_adapter = adm9240_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = adm9240_detect, + .detach_client = adm9240_detach_client, + }; + +@@ -150,7 +152,7 @@ + enum chips type; + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; + unsigned long last_updated_measure; + unsigned long last_updated_config; +@@ -195,11 +197,11 @@ + struct adm9240_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_max[attr->index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index), + data->temp_max[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -246,11 +248,11 @@ + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_min[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index), + data->in_min[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -263,11 +265,11 @@ + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_max[attr->index] = IN_TO_REG(val, attr->index); + i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index), + data->in_max[attr->index]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -350,7 +352,7 @@ + int nr = attr->index; + u8 new_div; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (!val) { + data->fan_min[nr] = 255; +@@ -390,7 +392,7 @@ + i2c_smbus_write_byte_data(client, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -439,10 +441,10 @@ + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->aout = AOUT_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM9240_REG_ANALOG_OUT, data->aout); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +@@ -539,7 +541,7 @@ + /* fill in the remaining client fields and attach */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto exit_free; +@@ -621,13 +623,6 @@ + return err; + } + +-static int adm9240_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, adm9240_detect); +-} +- + static int adm9240_detach_client(struct i2c_client *client) + { + struct adm9240_data *data = i2c_get_clientdata(client); +@@ -691,7 +686,7 @@ + struct adm9240_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + /* minimum measurement cycle: 1.75 seconds */ + if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) +@@ -771,7 +766,7 @@ + data->last_updated_config = jiffies; + data->valid = 1; + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return data; + } + +--- linux-2.6.16.orig/drivers/hwmon/asb100.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/asb100.c 2006-03-22 17:06:16.000000000 +0100 +@@ -44,6 +44,7 @@ + #include <linux/err.h> + #include <linux/init.h> + #include <linux/jiffies.h> ++#include <linux/mutex.h> + #include "lm75.h" + + /* +@@ -182,10 +183,10 @@ + struct asb100_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + unsigned long last_updated; /* In jiffies */ + + /* array of 2 pointers to subclients */ +@@ -210,7 +211,6 @@ + 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); +@@ -221,7 +221,9 @@ + .name = "asb100", + }, + .id = I2C_DRIVERID_ASB100, +- .attach_adapter = asb100_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = asb100_detect, + .detach_client = asb100_detach_client, + }; + +@@ -245,11 +247,11 @@ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -331,10 +333,10 @@ + struct asb100_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -351,7 +353,7 @@ + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); +@@ -381,7 +383,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -461,7 +463,7 @@ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + switch (nr) { \ + case 1: case 2: \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ +@@ -472,7 +474,7 @@ + } \ + asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ + data->reg[nr]); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -574,11 +576,11 @@ + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -595,11 +597,11 @@ + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -611,18 +613,6 @@ + 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_probe(adapter, &addr_data, asb100_detect); +-} +- + static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, + int kind, struct i2c_client *new_client) + { +@@ -729,7 +719,7 @@ + } + + new_client = &data->client; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; +@@ -789,7 +779,7 @@ + data->type = kind; + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -885,7 +875,7 @@ + struct i2c_client *cl; + int res, bank; + +- down(&data->lock); ++ mutex_lock(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) +@@ -919,7 +909,7 @@ + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + +- up(&data->lock); ++ mutex_unlock(&data->lock); + + return res; + } +@@ -930,7 +920,7 @@ + struct i2c_client *cl; + int bank; + +- down(&data->lock); ++ mutex_lock(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) +@@ -960,7 +950,7 @@ + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + +- up(&data->lock); ++ mutex_unlock(&data->lock); + } + + static void asb100_init_client(struct i2c_client *client) +@@ -984,7 +974,7 @@ + struct asb100_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -1042,7 +1032,7 @@ + dev_dbg(&client->dev, "... device update complete\n"); + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/atxp1.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/atxp1.c 2006-03-22 17:06:16.000000000 +0100 +@@ -26,6 +26,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); +@@ -44,7 +45,6 @@ + + I2C_CLIENT_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); +@@ -53,14 +53,16 @@ + .driver = { + .name = "atxp1", + }, +- .attach_adapter = atxp1_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = atxp1_detect, + .detach_client = atxp1_detach_client, + }; + + struct atxp1_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + unsigned long last_updated; + u8 valid; + struct { +@@ -80,7 +82,7 @@ + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + +@@ -93,7 +95,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return(data); + } +@@ -251,13 +253,6 @@ + static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); + + +-static int atxp1_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, &atxp1_detect); +-}; +- + static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) + { + struct i2c_client * new_client; +@@ -309,7 +304,7 @@ + + data->valid = 0; + +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + err = i2c_attach_client(new_client); + +--- linux-2.6.16.orig/drivers/hwmon/ds1621.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/ds1621.c 2006-03-22 17:06:16.000000000 +0100 +@@ -28,6 +28,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include "lm75.h" + + /* Addresses to scan */ +@@ -72,7 +73,7 @@ + struct ds1621_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -80,7 +81,6 @@ + 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); +@@ -93,7 +93,9 @@ + .name = "ds1621", + }, + .id = I2C_DRIVERID_DS1621, +- .attach_adapter = ds1621_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = ds1621_detect, + .detach_client = ds1621_detach_client, + }; + +@@ -156,10 +158,10 @@ + struct ds1621_data *data = ds1621_update_client(dev); \ + u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = val; \ + ds1621_write_value(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -178,13 +180,6 @@ + static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); + + +-static int ds1621_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, ds1621_detect); +-} +- + /* This function is called by i2c_probe */ + static int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind) +@@ -242,7 +237,7 @@ + /* 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); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -297,7 +292,7 @@ + struct ds1621_data *data = i2c_get_clientdata(client); + u8 new_conf; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -327,7 +322,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/fscher.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/fscher.c 2006-03-22 17:06:16.000000000 +0100 +@@ -33,6 +33,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -104,7 +105,6 @@ + * 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); +@@ -122,7 +122,9 @@ + .name = "fscher", + }, + .id = I2C_DRIVERID_FSCHER, +- .attach_adapter = fscher_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = fscher_detect, + .detach_client = fscher_detach_client, + }; + +@@ -133,7 +135,7 @@ + struct fscher_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -284,13 +286,6 @@ + * Real code + */ + +-static int fscher_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, fscher_detect); +-} +- + static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) + { + struct i2c_client *new_client; +@@ -332,7 +327,7 @@ + * global list */ + strlcpy(new_client->name, "fscher", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -417,7 +412,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct fscher_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + +@@ -457,7 +452,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +@@ -472,10 +467,10 @@ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -490,10 +485,10 @@ + { + unsigned long v = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -518,14 +513,14 @@ + return -EINVAL; + } + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -552,10 +547,10 @@ + /* bits 2..7 reserved, 0 read only => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -609,10 +604,10 @@ + /* bits 1..7 reserved => mask with 0x01 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->global_control &= ~v; + fscher_write_value(client, reg, v); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -631,11 +626,11 @@ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->watchdog[2] &= ~0xf0; + data->watchdog[2] |= v; + fscher_write_value(client, reg, data->watchdog[2]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -651,10 +646,10 @@ + /* bits 0, 2..7 reserved => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->watchdog[1] &= ~v; + fscher_write_value(client, reg, v); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -669,10 +664,10 @@ + { + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->watchdog[0] = v; + fscher_write_value(client, reg, data->watchdog[0]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +--- linux-2.6.16.orig/drivers/hwmon/fscpos.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/fscpos.c 2006-03-22 17:06:16.000000000 +0100 +@@ -37,6 +37,7 @@ + #include <linux/init.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -85,12 +86,11 @@ + /* + * 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 int fscpos_read_value(struct i2c_client *client, u8 reg); ++static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value); + static struct fscpos_data *fscpos_update_device(struct device *dev); + static void fscpos_init_client(struct i2c_client *client); + +@@ -104,7 +104,9 @@ + .name = "fscpos", + }, + .id = I2C_DRIVERID_FSCPOS, +- .attach_adapter = fscpos_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = fscpos_detect, + .detach_client = fscpos_detach_client, + }; + +@@ -114,7 +116,7 @@ + struct fscpos_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* 0 until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -208,13 +210,13 @@ + return -EINVAL; + } + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -232,10 +234,10 @@ + if (v < 0) v = 0; + if (v > 255) v = 255; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->pwm[nr - 1] = v; + fscpos_write_value(client, reg, data->pwm[nr - 1]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -278,11 +280,11 @@ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->wdog_control &= ~0xf0; + data->wdog_control |= v; + fscpos_write_value(client, reg, data->wdog_control); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -304,10 +306,10 @@ + return -EINVAL; + } + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->wdog_state &= ~v; + fscpos_write_value(client, reg, v); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -321,10 +323,10 @@ + { + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->wdog_preset = v; + fscpos_write_value(client, reg, data->wdog_preset); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -431,13 +433,6 @@ + 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_probe(adapter, &addr_data, fscpos_detect); +-} +- + static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) + { + struct i2c_client *new_client; +@@ -483,7 +478,7 @@ + strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE); + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -579,7 +574,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct fscpos_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + int i; +@@ -625,7 +620,7 @@ + data->last_updated = jiffies; + data->valid = 1; + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return data; + } + +--- linux-2.6.16.orig/drivers/hwmon/gl518sm.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/gl518sm.c 2006-03-22 17:06:16.000000000 +0100 +@@ -43,6 +43,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +@@ -120,7 +121,7 @@ + struct class_device *class_dev; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -141,7 +142,6 @@ + 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); +@@ -155,7 +155,9 @@ + .name = "gl518sm", + }, + .id = I2C_DRIVERID_GL518, +- .attach_adapter = gl518_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = gl518_detect, + .detach_client = gl518_detach_client, + }; + +@@ -212,10 +214,10 @@ + struct gl518_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = type##_TO_REG(val); \ + gl518_write_value(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -228,12 +230,12 @@ + int regvalue; \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -265,7 +267,7 @@ + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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])); +@@ -280,7 +282,7 @@ + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -291,7 +293,7 @@ + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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])); +@@ -306,7 +308,7 @@ + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -343,13 +345,6 @@ + * Real code + */ + +-static int gl518_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, gl518_detect); +-} +- + static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) + { + int i; +@@ -407,7 +402,7 @@ + strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -525,7 +520,7 @@ + struct gl518_data *data = i2c_get_clientdata(client); + int val; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -586,7 +581,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/gl520sm.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/gl520sm.c 2006-03-22 17:06:16.000000000 +0100 +@@ -29,6 +29,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Type of the extra sensor */ + static unsigned short extra_sensor_type; +@@ -99,7 +100,6 @@ + * 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); +@@ -113,7 +113,9 @@ + .name = "gl520sm", + }, + .id = I2C_DRIVERID_GL520, +- .attach_adapter = gl520_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = gl520_detect, + .detach_client = gl520_detach_client, + }; + +@@ -121,7 +123,7 @@ + struct gl520_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until the following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -303,7 +305,7 @@ + long v = simple_strtol(buf, NULL, 10); + u8 r; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (n == 0) + r = VDD_TO_REG(v); +@@ -317,7 +319,7 @@ + else + gl520_write_value(client, reg, r); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -331,7 +333,7 @@ + else + r = IN_TO_REG(v); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + data->in_max[n] = r; + +@@ -340,7 +342,7 @@ + else + gl520_write_value(client, reg, r); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -373,7 +375,7 @@ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + r = FAN_TO_REG(v, data->fan_div[n - 1]); + data->fan_min[n - 1] = r; + +@@ -390,7 +392,7 @@ + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -409,7 +411,7 @@ + return -EINVAL; + } + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->fan_div[n - 1] = r; + + if (n == 1) +@@ -417,7 +419,7 @@ + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -425,10 +427,10 @@ + { + u8 r = simple_strtoul(buf, NULL, 10)?1:0; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->fan_off = r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -454,10 +456,10 @@ + { + long v = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -465,10 +467,10 @@ + { + long v = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -491,10 +493,10 @@ + { + u8 r = simple_strtoul(buf, NULL, 10)?0:1; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->beep_enable = !r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -502,11 +504,11 @@ + { + u8 r = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + r &= data->alarm_mask; + data->beep_mask = r; + gl520_write_value(client, reg, r); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -515,13 +517,6 @@ + * Real code + */ + +-static int gl520_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, gl520_detect); +-} +- + static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) + { + struct i2c_client *new_client; +@@ -561,7 +556,7 @@ + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -685,7 +680,7 @@ + struct gl520_data *data = i2c_get_clientdata(client); + int val; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + +@@ -750,7 +745,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/hdaps.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/hdaps.c 2006-03-22 17:06:15.000000000 +0100 +@@ -33,6 +33,7 @@ + #include <linux/module.h> + #include <linux/timer.h> + #include <linux/dmi.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ +@@ -70,10 +71,10 @@ + static int rest_x; + static int rest_y; + +-static DECLARE_MUTEX(hdaps_sem); ++static DEFINE_MUTEX(hdaps_mutex); + + /* +- * __get_latch - Get the value from a given port. Callers must hold hdaps_sem. ++ * __get_latch - Get the value from a given port. Callers must hold hdaps_mutex. + */ + static inline u8 __get_latch(u16 port) + { +@@ -82,7 +83,7 @@ + + /* + * __check_latch - Check a port latch for a given value. Returns zero if the +- * port contains the given value. Callers must hold hdaps_sem. ++ * port contains the given value. Callers must hold hdaps_mutex. + */ + static inline int __check_latch(u16 port, u8 val) + { +@@ -93,7 +94,7 @@ + + /* + * __wait_latch - Wait up to 100us for a port latch to get a certain value, +- * returning zero if the value is obtained. Callers must hold hdaps_sem. ++ * returning zero if the value is obtained. Callers must hold hdaps_mutex. + */ + static int __wait_latch(u16 port, u8 val) + { +@@ -110,7 +111,7 @@ + + /* + * __device_refresh - request a refresh from the accelerometer. Does not wait +- * for refresh to complete. Callers must hold hdaps_sem. ++ * for refresh to complete. Callers must hold hdaps_mutex. + */ + static void __device_refresh(void) + { +@@ -124,7 +125,7 @@ + /* + * __device_refresh_sync - request a synchronous refresh from the + * accelerometer. We wait for the refresh to complete. Returns zero if +- * successful and nonzero on error. Callers must hold hdaps_sem. ++ * successful and nonzero on error. Callers must hold hdaps_mutex. + */ + static int __device_refresh_sync(void) + { +@@ -134,7 +135,7 @@ + + /* + * __device_complete - indicate to the accelerometer that we are done reading +- * data, and then initiate an async refresh. Callers must hold hdaps_sem. ++ * data, and then initiate an async refresh. Callers must hold hdaps_mutex. + */ + static inline void __device_complete(void) + { +@@ -152,7 +153,7 @@ + { + int ret; + +- down(&hdaps_sem); ++ mutex_lock(&hdaps_mutex); + + /* do a sync refresh -- we need to be sure that we read fresh data */ + ret = __device_refresh_sync(); +@@ -163,7 +164,7 @@ + __device_complete(); + + out: +- up(&hdaps_sem); ++ mutex_unlock(&hdaps_mutex); + return ret; + } + +@@ -198,9 +199,9 @@ + { + int ret; + +- down(&hdaps_sem); ++ mutex_lock(&hdaps_mutex); + ret = __hdaps_read_pair(port1, port2, val1, val2); +- up(&hdaps_sem); ++ mutex_unlock(&hdaps_mutex); + + return ret; + } +@@ -213,7 +214,7 @@ + { + int total, ret = -ENXIO; + +- down(&hdaps_sem); ++ mutex_lock(&hdaps_mutex); + + outb(0x13, 0x1610); + outb(0x01, 0x161f); +@@ -279,7 +280,7 @@ + } + + out: +- up(&hdaps_sem); ++ mutex_unlock(&hdaps_mutex); + return ret; + } + +@@ -313,7 +314,7 @@ + }; + + /* +- * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem. ++ * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_mutex. + */ + static void hdaps_calibrate(void) + { +@@ -325,7 +326,7 @@ + int x, y; + + /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ +- if (down_trylock(&hdaps_sem)) { ++ if (!mutex_trylock(&hdaps_mutex)) { + mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); + return; + } +@@ -340,7 +341,7 @@ + mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); + + out: +- up(&hdaps_sem); ++ mutex_unlock(&hdaps_mutex); + } + + +@@ -420,9 +421,9 @@ + struct device_attribute *attr, + const char *buf, size_t count) + { +- down(&hdaps_sem); ++ mutex_lock(&hdaps_mutex); + hdaps_calibrate(); +- up(&hdaps_sem); ++ mutex_unlock(&hdaps_mutex); + + return count; + } +--- linux-2.6.16.orig/drivers/hwmon/it87.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/it87.c 2006-03-22 17:06:16.000000000 +0100 +@@ -41,6 +41,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + +@@ -194,10 +195,10 @@ + struct it87_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -219,14 +220,12 @@ + }; + + +-static int it87_attach_adapter(struct i2c_adapter *adapter); + static int it87_isa_attach_adapter(struct i2c_adapter *adapter); + 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 int it87_read_value(struct i2c_client *client, u8 reg); ++static int it87_write_value(struct i2c_client *client, u8 reg, 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); +@@ -237,7 +236,9 @@ + .name = "it87", + }, + .id = I2C_DRIVERID_IT87, +- .attach_adapter = it87_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = it87_detect, + .detach_client = it87_detach_client, + }; + +@@ -290,11 +291,11 @@ + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, +@@ -307,11 +308,11 @@ + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -381,10 +382,10 @@ + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, +@@ -397,10 +398,10 @@ + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_temp_offset(offset) \ +@@ -440,7 +441,7 @@ + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + data->sensor &= ~(1 << nr); + data->sensor &= ~(8 << nr); +@@ -450,11 +451,11 @@ + else if (val == 2) + data->sensor |= 8 << nr; + else if (val != 0) { +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_sensor_offset(offset) \ +@@ -524,7 +525,7 @@ + int val = simple_strtol(buf, NULL, 10); + u8 reg = it87_read_value(client, IT87_REG_FAN_DIV); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + switch (nr) { + case 0: data->fan_div[nr] = reg & 0x07; break; + case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break; +@@ -533,7 +534,7 @@ + + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, +@@ -548,7 +549,7 @@ + int i, min[3]; + u8 old; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + old = it87_read_value(client, IT87_REG_FAN_DIV); + + for (i = 0; i < 3; i++) +@@ -576,7 +577,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_pwm_enable(struct device *dev, +@@ -589,7 +590,7 @@ + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (val == 0) { + int tmp; +@@ -606,11 +607,11 @@ + /* 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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, +@@ -626,11 +627,11 @@ + if (val < 0 || val > 255) + return -EINVAL; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -696,17 +697,6 @@ + #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_probe(adapter, &addr_data, it87_detect); +-} +- + static int it87_isa_attach_adapter(struct i2c_adapter *adapter) + { + return it87_detect(adapter, isa_address, -1); +@@ -776,7 +766,7 @@ + + new_client = &data->client; + if (is_isa) +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; +@@ -823,7 +813,7 @@ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -950,10 +940,10 @@ + + int res; + if (i2c_is_isa_client(client)) { +- down(&data->lock); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + res = inb_p(client->addr + IT87_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +@@ -969,10 +959,10 @@ + struct it87_data *data = i2c_get_clientdata(client); + + if (i2c_is_isa_client(client)) { +- down(&data->lock); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + outb_p(value, client->addr + IT87_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +@@ -1098,7 +1088,7 @@ + struct it87_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -1160,7 +1150,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm63.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm63.c 2006-03-22 17:06:16.000000000 +0100 +@@ -45,6 +45,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -126,7 +127,6 @@ + * 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); +@@ -142,7 +142,9 @@ + .driver = { + .name = "lm63", + }, +- .attach_adapter = lm63_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm63_detect, + .detach_client = lm63_detach_client, + }; + +@@ -153,7 +155,7 @@ + struct lm63_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -192,13 +194,13 @@ + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -222,12 +224,12 @@ + return -EPERM; + + val = simple_strtoul(buf, NULL, 10); +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -253,10 +255,10 @@ + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -284,13 +286,13 @@ + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -314,11 +316,11 @@ + long val = simple_strtol(buf, NULL, 10); + long hyst; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -329,9 +331,19 @@ + return sprintf(buf, "%u\n", data->alarms); + } + ++static ssize_t show_alarm(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, "%u\n", (data->alarms >> attr->index) & 1); ++} ++ + 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 SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); + + static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); + static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); +@@ -339,13 +351,18 @@ + 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(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); + + static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); ++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2); + static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); ++static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); + static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); ++static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); + static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); ++static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); + static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, + set_temp2_crit_hyst); + +@@ -355,13 +372,6 @@ + * Real code + */ + +-static int lm63_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm63_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -427,7 +437,7 @@ + + strlcpy(new_client->name, "lm63", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -448,6 +458,8 @@ + &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, ++ &sensor_dev_attr_fan1_min_alarm.dev_attr); + } + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); +@@ -456,13 +468,23 @@ + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, ++ &sensor_dev_attr_temp2_input_fault.dev_attr); ++ device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, ++ &sensor_dev_attr_temp2_min_alarm.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_max_alarm.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_max_alarm.dev_attr); ++ device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); ++ device_create_file(&new_client->dev, ++ &sensor_dev_attr_temp2_crit_alarm.dev_attr); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + +@@ -530,7 +552,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + if (data->config & 0x04) { /* tachometer enabled */ +@@ -582,7 +604,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm75.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm75.c 2006-03-22 17:06:16.000000000 +0100 +@@ -25,6 +25,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include "lm75.h" + + +@@ -47,7 +48,7 @@ + struct lm75_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 temp_input; /* Register values */ +@@ -55,7 +56,6 @@ + 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); +@@ -70,7 +70,9 @@ + .name = "lm75", + }, + .id = I2C_DRIVERID_LM75, +- .attach_adapter = lm75_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm75_detect, + .detach_client = lm75_detach_client, + }; + +@@ -91,10 +93,10 @@ + struct lm75_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = LM75_TEMP_TO_REG(temp); \ + lm75_write_value(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + set(temp_max, LM75_REG_TEMP_OS); +@@ -104,13 +106,6 @@ + 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_probe(adapter, &addr_data, lm75_detect); +-} +- + /* This function is called by i2c_probe */ + static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) + { +@@ -188,7 +183,7 @@ + /* 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); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -264,7 +259,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -277,7 +272,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm77.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm77.c 2006-03-22 17:06:16.000000000 +0100 +@@ -32,6 +32,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; +@@ -51,7 +52,7 @@ + struct lm77_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + int temp_input; /* Temperatures */ +@@ -62,7 +63,6 @@ + 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); +@@ -77,7 +77,9 @@ + .driver = { + .name = "lm77", + }, +- .attach_adapter = lm77_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm77_detect, + .detach_client = lm77_detach_client, + }; + +@@ -139,10 +141,10 @@ + struct lm77_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = val; \ + lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -157,11 +159,11 @@ + struct lm77_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -173,7 +175,7 @@ + long val = simple_strtoul(buf, NULL, 10); + int oldcrithyst; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + oldcrithyst = data->temp_crit - data->temp_hyst; + data->temp_crit = val; + data->temp_hyst = data->temp_crit - oldcrithyst; +@@ -181,7 +183,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -204,13 +206,6 @@ + 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_probe(adapter, &addr_data, lm77_detect); +-} +- + /* This function is called by i2c_probe */ + static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) + { +@@ -306,7 +301,7 @@ + /* 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); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -380,7 +375,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -406,7 +401,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm78.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm78.c 2006-03-22 17:06:16.000000000 +0100 +@@ -27,6 +27,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + /* Addresses to scan */ +@@ -131,10 +132,10 @@ + struct lm78_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -152,13 +153,12 @@ + }; + + +-static int lm78_attach_adapter(struct i2c_adapter *adapter); + static int lm78_isa_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 int lm78_read_value(struct i2c_client *client, u8 reg); ++static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value); + static struct lm78_data *lm78_update_device(struct device *dev); + static void lm78_init_client(struct i2c_client *client); + +@@ -168,7 +168,9 @@ + .name = "lm78", + }, + .id = I2C_DRIVERID_LM78, +- .attach_adapter = lm78_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm78_detect, + .detach_client = lm78_detach_client, + }; + +@@ -207,10 +209,10 @@ + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -221,10 +223,10 @@ + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -288,10 +290,10 @@ + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -307,10 +309,10 @@ + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -342,10 +344,10 @@ + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -368,7 +370,7 @@ + unsigned long min; + u8 reg; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + +@@ -380,7 +382,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -398,7 +400,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -464,17 +466,6 @@ + } + 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_probe(adapter, &addr_data, lm78_detect); +-} +- + static int lm78_isa_attach_adapter(struct i2c_adapter *adapter) + { + return lm78_detect(adapter, isa_address, -1); +@@ -548,7 +539,7 @@ + + new_client = &data->client; + if (is_isa) +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; +@@ -598,7 +589,7 @@ + data->type = kind; + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -697,10 +688,10 @@ + int res; + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); +- down(&data->lock); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + res = inb_p(client->addr + LM78_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +@@ -717,10 +708,10 @@ + { + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); +- down(&data->lock); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + outb_p(value, client->addr + LM78_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +@@ -742,7 +733,7 @@ + struct lm78_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -786,7 +777,7 @@ + data->fan_div[2] = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm80.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm80.c 2006-03-22 17:06:16.000000000 +0100 +@@ -28,6 +28,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, +@@ -108,7 +109,7 @@ + struct lm80_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -130,7 +131,6 @@ + * 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); +@@ -147,7 +147,9 @@ + .name = "lm80", + }, + .id = I2C_DRIVERID_LM80, +- .attach_adapter = lm80_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm80_detect, + .detach_client = lm80_detach_client, + }; + +@@ -191,10 +193,10 @@ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock);\ ++ mutex_lock(&data->update_lock);\ + data->value = IN_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ +- up(&data->update_lock);\ ++ mutex_unlock(&data->update_lock);\ + return count; \ + } + set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); +@@ -241,10 +243,10 @@ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock);\ ++ mutex_lock(&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);\ ++ mutex_unlock(&data->update_lock);\ + return count; \ + } + set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); +@@ -263,7 +265,7 @@ + u8 reg; + + /* Save fan_min */ +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + +@@ -275,7 +277,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -286,7 +288,7 @@ + /* 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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -325,10 +327,10 @@ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = TEMP_LIMIT_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); +@@ -386,13 +388,6 @@ + * Real code + */ + +-static int lm80_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm80_detect); +-} +- + static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) + { + int i, cur; +@@ -437,7 +432,7 @@ + /* 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); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -545,7 +540,7 @@ + struct lm80_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(&client->dev, "Starting lm80 update\n"); +@@ -585,7 +580,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm83.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm83.c 2006-03-22 17:06:16.000000000 +0100 +@@ -12,6 +12,10 @@ + * Since the datasheet omits to give the chip stepping code, I give it + * here: 0x03 (at register 0xff). + * ++ * Also supports the LM82 temp sensor, which is basically a stripped down ++ * model of the LM83. Datasheet is here: ++ * http://www.national.com/pf/LM/LM82.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 +@@ -35,6 +39,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -51,7 +56,7 @@ + * Insmod parameters + */ + +-I2C_CLIENT_INSMOD_1(lm83); ++I2C_CLIENT_INSMOD_2(lm83, lm82); + + /* + * The LM83 registers +@@ -114,7 +119,6 @@ + * 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); +@@ -128,7 +132,9 @@ + .name = "lm83", + }, + .id = I2C_DRIVERID_LM83, +- .attach_adapter = lm83_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm83_detect, + .detach_client = lm83_detach_client, + }; + +@@ -139,7 +145,7 @@ + struct lm83_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -171,11 +177,11 @@ + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -209,13 +215,6 @@ + * Real code + */ + +-static int lm83_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm83_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -282,6 +281,9 @@ + if (man_id == 0x01) { /* National Semiconductor */ + if (chip_id == 0x03) { + kind = lm83; ++ } else ++ if (chip_id == 0x01) { ++ kind = lm82; + } + } + +@@ -295,12 +297,15 @@ + + if (kind == lm83) { + name = "lm83"; ++ } else ++ if (kind == lm82) { ++ name = "lm82"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -318,32 +323,46 @@ + goto exit_detach; + } + ++ /* ++ * The LM82 can only monitor one external diode which is ++ * at the same register as the LM83 temp3 entry - so we ++ * declare 1 and 3 common, and then 2 and 4 only for the LM83. ++ */ ++ + 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); + ++ if (kind == lm83) { ++ device_create_file(&new_client->dev, ++ &sensor_dev_attr_temp2_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_temp2_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_temp2_crit.dev_attr); ++ device_create_file(&new_client->dev, ++ &sensor_dev_attr_temp4_crit.dev_attr); ++ } ++ + return 0; + + exit_detach: +@@ -373,7 +392,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int nr; +@@ -393,7 +412,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm85.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm85.c 2006-03-22 17:06:16.000000000 +0100 +@@ -31,6 +31,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* Addresses to scan */ + static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +@@ -331,10 +332,10 @@ + struct lm85_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ +@@ -368,13 +369,12 @@ + 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 int lm85_read_value(struct i2c_client *client, u8 reg); ++static int lm85_write_value(struct i2c_client *client, u8 reg, int value); + static struct lm85_data *lm85_update_device(struct device *dev); + static void lm85_init_client(struct i2c_client *client); + +@@ -384,7 +384,9 @@ + .name = "lm85", + }, + .id = I2C_DRIVERID_LM85, +- .attach_adapter = lm85_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm85_detect, + .detach_client = lm85_detach_client, + }; + +@@ -407,10 +409,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -499,10 +501,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) +@@ -559,10 +561,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_in_max(struct device *dev, char *buf, int nr) +@@ -577,10 +579,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_in_reg(offset) \ +@@ -640,10 +642,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +@@ -658,10 +660,10 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_temp_reg(offset) \ +@@ -713,12 +715,12 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) +@@ -733,11 +735,11 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) +@@ -752,7 +754,7 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->autofan[nr].min_off = val; + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] + | data->syncpwm3 +@@ -760,7 +762,7 @@ + | (data->autofan[1].min_off ? 0x40 : 0) + | (data->autofan[2].min_off ? 0x80 : 0) + ); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) +@@ -775,13 +777,13 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define pwm_auto(offset) \ +@@ -857,7 +859,7 @@ + int min; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); +@@ -871,7 +873,7 @@ + (data->zone[2].hyst << 4) + ); + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) +@@ -886,7 +888,7 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->zone[nr].limit = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), + data->zone[nr].limit); +@@ -913,7 +915,7 @@ + (data->zone[2].hyst << 4) + ); + } +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) +@@ -930,7 +932,7 @@ + int min; + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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( +@@ -938,7 +940,7 @@ + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + ((data->zone[nr].range & 0x0f) << 4) + | (data->autofan[nr].freq & 0x07)); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) +@@ -953,11 +955,11 @@ + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define temp_auto(offset) \ +@@ -1017,13 +1019,6 @@ + temp_auto(2); + temp_auto(3); + +-static int lm85_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm85_detect); +-} +- + static int lm85_detect(struct i2c_adapter *adapter, int address, + int kind) + { +@@ -1149,7 +1144,7 @@ + /* Fill in the remaining client fields */ + data->type = kind; + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -1368,7 +1363,7 @@ + struct lm85_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if ( !data->valid || + time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { +@@ -1571,7 +1566,7 @@ + + data->valid = 1; + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm87.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm87.c 2006-03-22 17:06:16.000000000 +0100 +@@ -60,6 +60,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -150,7 +151,6 @@ + * 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); +@@ -165,7 +165,9 @@ + .name = "lm87", + }, + .id = I2C_DRIVERID_LM87, +- .attach_adapter = lm87_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm87_detect, + .detach_client = lm87_detach_client, + }; + +@@ -176,7 +178,7 @@ + struct lm87_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -253,11 +255,11 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + + static void set_in_max(struct device *dev, const char *buf, int nr) +@@ -266,11 +268,11 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + + #define set_in(offset) \ +@@ -327,10 +329,10 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + + static void set_temp_high(struct device *dev, const char *buf, int nr) +@@ -339,10 +341,10 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + + #define set_temp(offset) \ +@@ -411,11 +413,11 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + } + + /* Note: we save and restore the fan minimum here, because its value is +@@ -431,7 +433,7 @@ + unsigned long min; + u8 reg; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr])); + +@@ -441,7 +443,7 @@ + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -459,7 +461,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -522,10 +524,10 @@ + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->aout = AOUT_TO_REG(val); + lm87_write_value(client, LM87_REG_AOUT, data->aout); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +@@ -534,13 +536,6 @@ + * Real code + */ + +-static int lm87_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm87_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -589,7 +584,7 @@ + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -744,7 +739,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + int i, j; +@@ -813,7 +808,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm90.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm90.c 2006-03-22 17:06:16.000000000 +0100 +@@ -78,6 +78,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* + * Addresses to scan +@@ -174,7 +175,6 @@ + * 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); +@@ -190,7 +190,9 @@ + .name = "lm90", + }, + .id = I2C_DRIVERID_LM90, +- .attach_adapter = lm90_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm90_detect, + .detach_client = lm90_detach_client, + }; + +@@ -201,7 +203,7 @@ + struct lm90_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int kind; +@@ -247,13 +249,13 @@ + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -281,7 +283,7 @@ + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + if (data->kind == adt7461) + data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); + else +@@ -290,7 +292,7 @@ + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -311,11 +313,11 @@ + long val = simple_strtol(buf, NULL, 10); + long hyst; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -326,23 +328,42 @@ + 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 ssize_t show_alarm(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", (data->alarms >> attr->index) & 1); ++} ++ ++static struct sensor_device_attribute lm90_sensor_attr[] = { ++ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0), ++ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0), ++ SENSOR_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2), ++ SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, ++ set_temp8, 1), ++ SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5), ++ SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, ++ set_temp11, 1), ++ SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3), ++ SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, ++ set_temp8, 2), ++ SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6), ++ SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, ++ set_temp11, 2), ++ SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4), ++ SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, ++ set_temp8, 3), ++ SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0), ++ SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, ++ set_temp8, 4), ++ SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1), ++ SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, ++ set_temphyst, 3), ++ SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4), ++}; ++ + static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + /* pec used for ADM1032 only */ +@@ -413,13 +434,6 @@ + return 0; + } + +-static int lm90_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm90_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -428,7 +442,7 @@ + { + struct i2c_client *new_client; + struct lm90_data *data; +- int err = 0; ++ int i, err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) +@@ -558,7 +572,7 @@ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + data->kind = kind; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -574,26 +588,13 @@ + goto exit_detach; + } + +- 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); ++ for (i = 0; i < ARRAY_SIZE(lm90_sensor_attr); i++) { ++ err = device_create_file(&new_client->dev, ++ &lm90_sensor_attr[i].dev_attr); ++ if (err) ++ goto exit_class; ++ } ++ + device_create_file(&new_client->dev, &dev_attr_alarms); + + if (new_client->flags & I2C_CLIENT_PEC) +@@ -601,6 +602,9 @@ + + return 0; + ++exit_class: ++ dev_err(&new_client->dev, "Sysfs interface creation failed\n"); ++ hwmon_device_unregister(data->class_dev); + exit_detach: + i2c_detach_client(new_client); + exit_free: +@@ -646,7 +650,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + u8 oldh, newh, l; +@@ -692,7 +696,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/lm92.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/lm92.c 2006-03-22 17:06:16.000000000 +0100 +@@ -46,6 +46,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* The LM92 and MAX6635 have 2 two-state pins for address selection, + resulting in 4 possible addresses. */ +@@ -96,7 +97,7 @@ + struct lm92_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -114,7 +115,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { +@@ -134,7 +135,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +@@ -158,10 +159,10 @@ + struct lm92_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + set_temp(temp1_crit, LM92_REG_TEMP_CRIT); +@@ -194,11 +195,11 @@ + struct lm92_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -348,7 +349,7 @@ + /* Fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the i2c subsystem a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -383,13 +384,6 @@ + return err; + } + +-static int lm92_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, lm92_detect); +-} +- + static int lm92_detach_client(struct i2c_client *client) + { + struct lm92_data *data = i2c_get_clientdata(client); +@@ -414,7 +408,9 @@ + .name = "lm92", + }, + .id = I2C_DRIVERID_LM92, +- .attach_adapter = lm92_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = lm92_detect, + .detach_client = lm92_detach_client, + }; + +--- linux-2.6.16.orig/drivers/hwmon/max1619.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/max1619.c 2006-03-22 17:06:16.000000000 +0100 +@@ -33,6 +33,7 @@ + #include <linux/i2c.h> + #include <linux/hwmon.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, +@@ -78,7 +79,6 @@ + * 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); +@@ -93,7 +93,9 @@ + .driver = { + .name = "max1619", + }, +- .attach_adapter = max1619_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = max1619_detect, + .detach_client = max1619_detach_client, + }; + +@@ -104,7 +106,7 @@ + struct max1619_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -141,10 +143,10 @@ + struct max1619_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, reg, data->value); \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + +@@ -175,13 +177,6 @@ + * Real code + */ + +-static int max1619_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, max1619_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -262,7 +257,7 @@ + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -330,7 +325,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Updating max1619 data.\n"); +@@ -353,7 +348,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/sis5595.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/sis5595.c 2006-03-22 17:06:15.000000000 +0100 +@@ -60,6 +60,7 @@ + #include <linux/err.h> + #include <linux/init.h> + #include <linux/jiffies.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + +@@ -167,9 +168,9 @@ + struct sis5595_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + char maxins; /* == 3 if temp enabled, otherwise == 4 */ +@@ -192,8 +193,8 @@ + static int sis5595_detect(struct i2c_adapter *adapter); + 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 int sis5595_read_value(struct i2c_client *client, u8 reg); ++static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value); + static struct sis5595_data *sis5595_update_device(struct device *dev); + static void sis5595_init_client(struct i2c_client *client); + +@@ -231,10 +232,10 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -245,10 +246,10 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -310,10 +311,10 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -329,10 +330,10 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -364,10 +365,10 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -390,7 +391,7 @@ + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + +- down(&data->update_lock); ++ mutex_lock(&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); +@@ -403,7 +404,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -419,7 +420,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -527,7 +528,7 @@ + + new_client = &data->client; + new_client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->adapter = adapter; + new_client->driver = &sis5595_driver; +@@ -548,7 +549,7 @@ + strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -635,20 +636,20 @@ + int res; + + struct sis5595_data *data = i2c_get_clientdata(client); +- down(&data->lock); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&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); ++ mutex_lock(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } + +@@ -667,7 +668,7 @@ + struct sis5595_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -707,7 +708,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/smsc47b397.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/smsc47b397.c 2006-03-22 17:06:15.000000000 +0100 +@@ -35,6 +35,7 @@ + #include <linux/hwmon.h> + #include <linux/err.h> + #include <linux/init.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + /* Address is autodetected, there is no default value */ +@@ -92,9 +93,9 @@ + struct smsc47b397_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + +- struct semaphore update_lock; ++ struct mutex update_lock; + unsigned long last_updated; /* in jiffies */ + int valid; + +@@ -108,10 +109,10 @@ + struct smsc47b397_data *data = i2c_get_clientdata(client); + int res; + +- down(&data->lock); ++ mutex_lock(&data->lock); + outb(reg, client->addr); + res = inb_p(client->addr + 1); +- up(&data->lock); ++ mutex_unlock(&data->lock); + return res; + } + +@@ -121,7 +122,7 @@ + struct smsc47b397_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + dev_dbg(&client->dev, "starting device update...\n"); +@@ -144,7 +145,7 @@ + dev_dbg(&client->dev, "... device update complete\n"); + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +@@ -254,14 +255,14 @@ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&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); ++ mutex_init(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto error_free; +--- linux-2.6.16.orig/drivers/hwmon/smsc47m1.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/smsc47m1.c 2006-03-22 17:06:15.000000000 +0100 +@@ -34,6 +34,7 @@ + #include <linux/hwmon.h> + #include <linux/err.h> + #include <linux/init.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + /* Address is autodetected, there is no default value */ +@@ -102,9 +103,9 @@ + struct smsc47m1_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + +- struct semaphore update_lock; ++ struct mutex update_lock; + unsigned long last_updated; /* In jiffies */ + + u8 fan[2]; /* Register value */ +@@ -188,18 +189,18 @@ + struct smsc47m1_data *data = i2c_get_clientdata(client); + long rpmdiv, val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); + + if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { +- up(&data->update_lock); ++ mutex_unlock(&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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -220,14 +221,14 @@ + if (new_div == old_div) /* No change */ + return count; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -241,7 +242,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -257,12 +258,12 @@ + if (val < 0 || val > 255) + return -EINVAL; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -278,12 +279,12 @@ + if (val != 0 && val != 1) + return -EINVAL; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + + return count; + } +@@ -408,13 +409,13 @@ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&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); ++ mutex_init(&data->update_lock); + + /* If no function is properly configured, there's no point in + actually registering the chip. */ +@@ -512,17 +513,17 @@ + { + int res; + +- down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); ++ mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + res = inb_p(client->addr + reg); +- up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); ++ mutex_unlock(&((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); ++ mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + outb_p(value, client->addr + reg); +- up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); ++ mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + } + + static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, +@@ -531,7 +532,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { + int i; +@@ -558,7 +559,7 @@ + data->last_updated = jiffies; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return data; + } + +--- linux-2.6.16.orig/drivers/hwmon/via686a.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/via686a.c 2006-03-22 17:06:15.000000000 +0100 +@@ -39,6 +39,7 @@ + #include <linux/hwmon.h> + #include <linux/err.h> + #include <linux/init.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + +@@ -296,7 +297,7 @@ + struct via686a_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -355,11 +356,11 @@ + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_in_max(struct device *dev, const char *buf, +@@ -368,11 +369,11 @@ + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_in_offset(offset) \ +@@ -432,11 +433,11 @@ + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp_hyst(struct device *dev, const char *buf, +@@ -445,11 +446,11 @@ + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + #define show_temp_offset(offset) \ +@@ -508,10 +509,10 @@ + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_fan_div(struct device *dev, const char *buf, +@@ -521,12 +522,12 @@ + int val = simple_strtol(buf, NULL, 10); + int old; + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -639,7 +640,7 @@ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; +@@ -733,7 +734,7 @@ + struct via686a_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -788,7 +789,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/vt8231.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/vt8231.c 2006-03-22 17:06:15.000000000 +0100 +@@ -35,6 +35,7 @@ + #include <linux/hwmon-sysfs.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + + static int force_addr; +@@ -148,7 +149,7 @@ + + struct vt8231_data { + struct i2c_client client; +- struct semaphore update_lock; ++ struct mutex update_lock; + struct class_device *class_dev; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ +@@ -223,10 +224,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); + vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -239,10 +240,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); + vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -281,11 +282,11 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, + 0, 255); + vt8231_write_value(client, regvoltmin[5], data->in_min[5]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -296,11 +297,11 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, + 0, 255); + vt8231_write_value(client, regvoltmax[5], data->in_max[5]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -351,10 +352,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); + vt8231_write_value(client, regtempmax[0], data->temp_max[0]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr, +@@ -364,10 +365,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); + vt8231_write_value(client, regtempmin[0], data->temp_min[0]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -407,10 +408,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); + vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, +@@ -422,10 +423,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); + vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -520,10 +521,10 @@ + struct vt8231_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -539,7 +540,7 @@ + long min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; +@@ -548,7 +549,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +@@ -558,7 +559,7 @@ + + old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); + vt8231_write_value(client, VT8231_REG_FANDIV, old); +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -660,7 +661,7 @@ + /* Fill in the remaining client fields and put into the global list */ + strlcpy(client->name, "vt8231", I2C_NAME_SIZE); + +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) +@@ -745,7 +746,7 @@ + int i; + u16 low; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -804,7 +805,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/w83627ehf.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/w83627ehf.c 2006-03-22 17:06:16.000000000 +0100 +@@ -30,10 +30,7 @@ + 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. ++ w83627ehf 10 5 - 3 0x88 0x5ca3 + */ + + #include <linux/module.h> +@@ -42,7 +39,9 @@ + #include <linux/i2c.h> + #include <linux/i2c-isa.h> + #include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + #include "lm75.h" + +@@ -119,6 +118,14 @@ + static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; + static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; + ++/* The W83627EHF registers for nr=7,8,9 are in bank 5 */ ++#define W83627EHF_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ ++ (0x554 + (((nr) - 7) * 2))) ++#define W83627EHF_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ ++ (0x555 + (((nr) - 7) * 2))) ++#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ ++ (0x550 + (nr) - 7)) ++ + #define W83627EHF_REG_TEMP1 0x27 + #define W83627EHF_REG_TEMP1_HYST 0x3a + #define W83627EHF_REG_TEMP1_OVER 0x39 +@@ -134,6 +141,10 @@ + #define W83627EHF_REG_DIODE 0x59 + #define W83627EHF_REG_SMI_OVT 0x4C + ++#define W83627EHF_REG_ALARM1 0x459 ++#define W83627EHF_REG_ALARM2 0x45A ++#define W83627EHF_REG_ALARM3 0x45B ++ + /* + * Conversions + */ +@@ -170,6 +181,20 @@ + return (temp + 500) / 1000; + } + ++/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ ++ ++static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; ++ ++static inline long in_from_reg(u8 reg, u8 nr) ++{ ++ return reg * scale_in[nr]; ++} ++ ++static inline u8 in_to_reg(u32 val, u8 nr) ++{ ++ return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255); ++} ++ + /* + * Data structures and manipulation thereof + */ +@@ -177,13 +202,16 @@ + struct w83627ehf_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ ++ u8 in[10]; /* Register value */ ++ u8 in_max[10]; /* Register value */ ++ u8 in_min[10]; /* Register value */ + u8 fan[5]; + u8 fan_min[5]; + u8 fan_div[5]; +@@ -194,6 +222,7 @@ + s16 temp[2]; + s16 temp_max[2]; + s16 temp_max_hyst[2]; ++ u32 alarms; + }; + + static inline int is_word_sized(u16 reg) +@@ -230,7 +259,7 @@ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int res, word_sized = is_word_sized(reg); + +- down(&data->lock); ++ mutex_lock(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); +@@ -242,7 +271,7 @@ + } + w83627ehf_reset_bank(client, reg); + +- up(&data->lock); ++ mutex_unlock(&data->lock); + + return res; + } +@@ -252,7 +281,7 @@ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int word_sized = is_word_sized(reg); + +- down(&data->lock); ++ mutex_lock(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); +@@ -264,7 +293,7 @@ + outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(client, reg); + +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } + +@@ -322,7 +351,7 @@ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { +@@ -347,6 +376,16 @@ + data->fan_div[3] |= (i >> 5) & 0x04; + } + ++ /* Measured voltages and limits */ ++ for (i = 0; i < 10; i++) { ++ data->in[i] = w83627ehf_read_value(client, ++ W83627EHF_REG_IN(i)); ++ data->in_min[i] = w83627ehf_read_value(client, ++ W83627EHF_REG_IN_MIN(i)); ++ data->in_max[i] = w83627ehf_read_value(client, ++ W83627EHF_REG_IN_MAX(i)); ++ } ++ + /* Measured fan speeds and limits */ + for (i = 0; i < 5; i++) { + if (!(data->has_fan & (1 << i))) +@@ -393,23 +432,136 @@ + W83627EHF_REG_TEMP_HYST[i]); + } + ++ data->alarms = w83627ehf_read_value(client, ++ W83627EHF_REG_ALARM1) | ++ (w83627ehf_read_value(client, ++ W83627EHF_REG_ALARM2) << 8) | ++ (w83627ehf_read_value(client, ++ W83627EHF_REG_ALARM3) << 16); ++ + data->last_updated = jiffies; + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return data; + } + + /* + * Sysfs callback functions + */ ++#define show_in_reg(reg) \ ++static ssize_t \ ++show_##reg(struct device *dev, struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ struct w83627ehf_data *data = w83627ehf_update_device(dev); \ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ ++ int nr = sensor_attr->index; \ ++ return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], 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, 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); \ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ ++ int nr = sensor_attr->index; \ ++ u32 val = simple_strtoul(buf, NULL, 10); \ ++ \ ++ mutex_lock(&data->update_lock); \ ++ data->in_##reg[nr] = in_to_reg(val, nr); \ ++ w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \ ++ data->in_##reg[nr]); \ ++ mutex_unlock(&data->update_lock); \ ++ return count; \ ++} ++ ++store_in_reg(MIN, min) ++store_in_reg(MAX, max) ++ ++static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct w83627ehf_data *data = w83627ehf_update_device(dev); ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int nr = sensor_attr->index; ++ return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01); ++} ++ ++static struct sensor_device_attribute sda_in_input[] = { ++ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), ++ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), ++ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), ++ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), ++ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), ++ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), ++ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), ++ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), ++ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), ++ SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), ++}; ++ ++static struct sensor_device_attribute sda_in_alarm[] = { ++ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), ++ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), ++ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), ++ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), ++ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), ++ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21), ++ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20), ++ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16), ++ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17), ++ SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19), ++}; ++ ++static struct sensor_device_attribute sda_in_min[] = { ++ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), ++ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), ++ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), ++ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), ++ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), ++ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), ++ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), ++ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), ++ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), ++ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), ++}; ++ ++static struct sensor_device_attribute sda_in_max[] = { ++ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), ++ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), ++ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), ++ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), ++ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), ++ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), ++ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), ++ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), ++ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), ++ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), ++}; ++ ++static void device_create_file_in(struct device *dev, int i) ++{ ++ device_create_file(dev, &sda_in_input[i].dev_attr); ++ device_create_file(dev, &sda_in_alarm[i].dev_attr); ++ device_create_file(dev, &sda_in_min[i].dev_attr); ++ device_create_file(dev, &sda_in_max[i].dev_attr); ++} + + #define show_fan_reg(reg) \ + static ssize_t \ +-show_##reg(struct device *dev, char *buf, int nr) \ ++show_##reg(struct device *dev, struct device_attribute *attr, \ ++ char *buf) \ + { \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ ++ int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", \ + fan_from_reg(data->reg[nr], \ + div_from_reg(data->fan_div[nr]))); \ +@@ -418,23 +570,28 @@ + show_fan_reg(fan_min); + + static ssize_t +-show_fan_div(struct device *dev, char *buf, int nr) ++show_fan_div(struct device *dev, struct device_attribute *attr, ++ char *buf) + { + struct w83627ehf_data *data = w83627ehf_update_device(dev); +- return sprintf(buf, "%u\n", +- div_from_reg(data->fan_div[nr])); ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int nr = sensor_attr->index; ++ 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) ++store_fan_min(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); ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int nr = sensor_attr->index; + unsigned int val = simple_strtoul(buf, NULL, 10); + unsigned int reg; + u8 new_div; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + if (!val) { + /* No min limit, alarm disabled */ + data->fan_min[nr] = 255; +@@ -482,63 +639,55 @@ + } + w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + data->fan_min[nr]); +- up(&data->update_lock); ++ mutex_unlock(&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); ++static struct sensor_device_attribute sda_fan_input[] = { ++ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), ++ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), ++ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), ++ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), ++ SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), ++}; + +-#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); ++static struct sensor_device_attribute sda_fan_alarm[] = { ++ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), ++ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), ++ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 10), ++ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 11), ++ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23), ++}; + +-#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); ++static struct sensor_device_attribute sda_fan_min[] = { ++ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, ++ store_fan_min, 0), ++ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, ++ store_fan_min, 1), ++ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, ++ store_fan_min, 2), ++ SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, ++ store_fan_min, 3), ++ SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, ++ store_fan_min, 4), ++}; ++ ++static struct sensor_device_attribute sda_fan_div[] = { ++ SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0), ++ SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1), ++ SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2), ++ SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3), ++ SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4), ++}; ++ ++static void device_create_file_fan(struct device *dev, int i) ++{ ++ device_create_file(dev, &sda_fan_input[i].dev_attr); ++ device_create_file(dev, &sda_fan_alarm[i].dev_attr); ++ device_create_file(dev, &sda_fan_div[i].dev_attr); ++ device_create_file(dev, &sda_fan_min[i].dev_attr); ++} + + #define show_temp1_reg(reg) \ + static ssize_t \ +@@ -561,27 +710,24 @@ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&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) \ ++show_##reg(struct device *dev, struct device_attribute *attr, \ ++ char *buf) \ + { \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ ++ int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", \ + LM75_TEMP_FROM_REG(data->reg[nr])); \ + } +@@ -591,55 +737,45 @@ + + #define store_temp_reg(REG, reg) \ + static ssize_t \ +-store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ ++store_##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); \ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ ++ int nr = sensor_attr->index; \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&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); ++static struct sensor_device_attribute sda_temp[] = { ++ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), ++ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), ++ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), ++ SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, ++ store_temp1_max, 0), ++ SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, ++ store_temp_max, 0), ++ SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, ++ store_temp_max, 1), ++ SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, ++ store_temp1_max_hyst, 0), ++ SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, ++ store_temp_max_hyst, 0), ++ SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, ++ store_temp_max_hyst, 1), ++ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), ++ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), ++ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), ++}; + + /* + * Driver and client management +@@ -673,6 +809,7 @@ + { + struct i2c_client *client; + struct w83627ehf_data *data; ++ struct device *dev; + int i, err = 0; + + if (!request_region(address + REGION_OFFSET, REGION_LENGTH, +@@ -689,14 +826,15 @@ + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + client->adapter = adapter; + client->driver = &w83627ehf_driver; + client->flags = 0; ++ dev = &client->dev; + + strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) +@@ -720,42 +858,21 @@ + data->has_fan |= (1 << 4); + + /* Register sysfs hooks */ +- data->class_dev = hwmon_device_register(&client->dev); ++ data->class_dev = hwmon_device_register(dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_detach; + } + +- 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); ++ for (i = 0; i < 10; i++) ++ device_create_file_in(dev, i); ++ ++ for (i = 0; i < 5; i++) { ++ if (data->has_fan & (1 << i)) ++ device_create_file_fan(dev, i); ++ } ++ for (i = 0; i < ARRAY_SIZE(sda_temp); i++) ++ device_create_file(dev, &sda_temp[i].dev_attr); + + return 0; + +--- linux-2.6.16.orig/drivers/hwmon/w83627hf.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/w83627hf.c 2006-03-22 17:06:21.000000000 +0100 +@@ -28,6 +28,7 @@ + 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) ++ w83687thf 7 3 3 3 0x90 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, +@@ -45,7 +46,9 @@ + #include <linux/i2c-isa.h> + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> ++#include <linux/hwmon-sysfs.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + #include "lm75.h" + +@@ -62,7 +65,7 @@ + static unsigned short address; + + /* Insmod parameters */ +-enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf }; ++enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf }; + + static int reset; + module_param(reset, bool, 0); +@@ -100,6 +103,10 @@ + #define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ + #define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ + ++#define W83687THF_VID_EN 0x29 /* w83687thf only */ ++#define W83687THF_VID_CFG 0xF0 /* w83687thf only */ ++#define W83687THF_VID_DATA 0xF1 /* w83687thf only */ ++ + static inline void + superio_outb(int reg, int val) + { +@@ -138,6 +145,7 @@ + #define W627THF_DEVID 0x82 + #define W697_DEVID 0x60 + #define W637_DEVID 0x70 ++#define W687THF_DEVID 0x85 + #define WINB_ACT_REG 0x30 + #define WINB_BASE_REG 0x60 + /* Constants specified below */ +@@ -201,11 +209,11 @@ + #define W83627HF_REG_PWM1 0x5A + #define W83627HF_REG_PWM2 0x5B + +-#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_PWM1 0x01 /* 697HF/637HF/687THF too */ ++#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ ++#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ + +-#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ ++#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */ + + static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; + static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, +@@ -285,10 +293,10 @@ + struct w83627hf_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -318,16 +326,15 @@ + Default = 3435. + Other Betas unimplemented */ + u8 vrm; +- u8 vrm_ovt; /* Register value, 627thf & 637hf only */ ++ u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ + }; + + + static int w83627hf_detect(struct i2c_adapter *adapter); + 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 int w83627hf_read_value(struct i2c_client *client, u16 reg); ++static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value); + static struct w83627hf_data *w83627hf_update_device(struct device *dev); + static void w83627hf_init_client(struct i2c_client *client); + +@@ -360,12 +367,12 @@ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + store_in_reg(MIN, min) +@@ -413,7 +420,8 @@ + long in0; + + if ((data->vrm_ovt & 0x01) && +- (w83627thf == data->type || w83637hf == data->type)) ++ (w83627thf == data->type || w83637hf == data->type ++ || w83687thf == data->type)) + + /* use VRM9 calculation */ + in0 = (long)((reg * 488 + 70000 + 50) / 100); +@@ -451,10 +459,11 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && +- (w83627thf == data->type || w83637hf == data->type)) ++ (w83627thf == data->type || w83637hf == data->type ++ || w83687thf == data->type)) + + /* use VRM9 calculation */ + data->in_min[0] = +@@ -465,7 +474,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -478,10 +487,11 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && +- (w83627thf == data->type || w83637hf == data->type)) ++ (w83627thf == data->type || w83637hf == data->type ++ || w83687thf == data->type)) + + /* use VRM9 calculation */ + data->in_max[0] = +@@ -492,7 +502,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -507,6 +517,10 @@ + 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); \ ++device_create_file(&client->dev, \ ++ &sensor_dev_attr_in##offset##_alarm.dev_attr); \ ++device_create_file(&client->dev, \ ++ &sensor_dev_attr_in##offset##_beep.dev_attr); \ + } while (0) + + #define show_fan_reg(reg) \ +@@ -529,13 +543,13 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -570,6 +584,10 @@ + 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, \ ++ &sensor_dev_attr_fan##offset##_alarm.dev_attr); \ ++device_create_file(&client->dev, \ ++ &sensor_dev_attr_fan##offset##_beep.dev_attr); \ + } while (0) + + #define show_temp_reg(reg) \ +@@ -597,7 +615,7 @@ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ +@@ -609,7 +627,7 @@ + data->temp_##reg); \ + } \ + \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + store_temp_reg(OVER, max); +@@ -651,6 +669,10 @@ + 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); \ ++device_create_file(&client->dev, \ ++ &sensor_dev_attr_temp##offset##_alarm.dev_attr); \ ++device_create_file(&client->dev, \ ++ &sensor_dev_attr_temp##offset##_beep.dev_attr); \ + } while (0) + + static ssize_t +@@ -693,76 +715,152 @@ + } + static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + #define device_create_file_alarms(client) \ +-device_create_file(&client->dev, &dev_attr_alarms) ++do { \ ++device_create_file(&client->dev, &dev_attr_alarms); \ ++device_create_file(&client->dev, &sensor_dev_attr_chassis_alarm.dev_attr); \ ++} while (0) + +-#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)); \ ++static ssize_t ++show_alarm_bit(struct device *dev, struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct w83627hf_data *data = w83627hf_update_device(dev); ++ ++ return sprintf(buf, "%u\n", (data->alarms >> attr->index) & 1); + } +-show_beep_reg(ENABLE, enable) +-show_beep_reg(MASK, mask) ++static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm_bit, NULL, 0); ++static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm_bit, NULL, 1); ++static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm_bit, NULL, 2); ++static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm_bit, NULL, 3); ++static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm_bit, NULL, 8); ++static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm_bit, NULL, 9); ++static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm_bit, NULL, 10); ++static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm_bit, NULL, 16); ++static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm_bit, NULL, 17); ++static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm_bit, NULL, 6); ++static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm_bit, NULL, 7); ++static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm_bit, NULL, 11); ++static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm_bit, NULL, 4); ++static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm_bit, NULL, 5); ++static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm_bit, NULL, 13); ++static SENSOR_DEVICE_ATTR(chassis_alarm, S_IRUGO, show_alarm_bit, NULL, 12); + +-#define BEEP_ENABLE 0 /* Store beep_enable */ +-#define BEEP_MASK 1 /* Store beep_mask */ ++static ssize_t show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct w83627hf_data *data = w83627hf_update_device(dev); ++ return sprintf(buf, "%ld\n", ++ (long)BEEP_MASK_FROM_REG(data->beep_mask)); ++} + + static ssize_t +-store_beep_reg(struct device *dev, const char *buf, size_t count, +- int update_mask) ++store_beep_mask(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, val2; +- +- val = simple_strtoul(buf, NULL, 10); ++ u32 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); +- } ++ mutex_lock(&data->update_lock); + ++ 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); + w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, +- val2 | data->beep_enable << 7); ++ ((data->beep_mask >> 8) & 0x7f) ++ | data->beep_enable << 7); + +- up(&data->update_lock); ++ mutex_unlock(&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); ++static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, \ ++ show_beep_mask, store_beep_mask); + + #define device_create_file_beep(client) \ + do { \ +-device_create_file(&client->dev, &dev_attr_beep_enable); \ ++device_create_file(&client->dev, &sensor_dev_attr_beep_enable.dev_attr); \ + device_create_file(&client->dev, &dev_attr_beep_mask); \ ++device_create_file(&client->dev, &sensor_dev_attr_chassis_beep.dev_attr); \ + } while (0) + + static ssize_t ++show_beep_bit(struct device *dev, struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct w83627hf_data *data = w83627hf_update_device(dev); ++ ++ return sprintf(buf, "%u\n", (data->beep_mask >> attr->index) & 1); ++} ++ ++static ssize_t ++store_beep_bit(struct device *dev, struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct w83627hf_data *data = i2c_get_clientdata(client); ++ u16 beepreg[3] = { W83781D_REG_BEEP_INTS1, W83781D_REG_BEEP_INTS2, ++ W83781D_REG_BEEP_INTS3 }; ++ u32 val; ++ u8 reg; ++ ++ val = simple_strtoul(buf, NULL, 10); ++ if (val != 0 && val != 1) ++ return -EINVAL; ++ ++ mutex_lock(&data->update_lock); ++ ++ reg = w83627hf_read_value(client, beepreg[attr->index >> 3]); ++ if (val) { ++ reg |= 1 << (attr->index & 0x07); ++ data->beep_mask |= 1 << attr->index; ++ } else { ++ reg &= ~(1 << (attr->index & 0x07)); ++ data->beep_mask &= ~(1 << attr->index); ++ } ++ w83627hf_write_value(client, beepreg[attr->index >> 3], reg); ++ ++ mutex_unlock(&data->update_lock); ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 0); ++static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 1); ++static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 2); ++static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 3); ++static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 8); ++static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 9); ++static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 10); ++static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 16); ++static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 17); ++static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 6); ++static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 7); ++static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 11); ++static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 4); ++static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 5); ++static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 13); ++static SENSOR_DEVICE_ATTR(chassis_beep, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 12); ++static SENSOR_DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, show_beep_bit, ++ store_beep_bit, 15); ++ ++static ssize_t + show_fan_div_reg(struct device *dev, char *buf, int nr) + { + struct w83627hf_data *data = w83627hf_update_device(dev); +@@ -783,7 +881,7 @@ + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], +@@ -805,7 +903,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -848,7 +946,7 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (data->type == w83627thf) { + /* bits 0-3 are reserved in 627THF */ +@@ -865,7 +963,7 @@ + data->pwm[nr - 1]); + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -907,7 +1005,7 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ +@@ -941,7 +1039,7 @@ + break; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -980,7 +1078,8 @@ + if(val != W627_DEVID && + val != W627THF_DEVID && + val != W697_DEVID && +- val != W637_DEVID) { ++ val != W637_DEVID && ++ val != W687THF_DEVID) { + superio_exit(); + return -ENODEV; + } +@@ -1034,6 +1133,8 @@ + kind = w83627thf; + else if(val == W637_DEVID) + kind = w83637hf; ++ else if (val == W687THF_DEVID) ++ kind = w83687thf; + else { + dev_info(&adapter->dev, + "Unsupported chip (dev_id=0x%02X).\n", val); +@@ -1057,7 +1158,7 @@ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83627hf_driver; + new_client->flags = 0; +@@ -1071,13 +1172,15 @@ + client_name = "w83697hf"; + } else if (kind == w83637hf) { + client_name = "w83637hf"; ++ } else if (kind == w83687thf) { ++ client_name = "w83687thf"; + } + + /* 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); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -1106,7 +1209,7 @@ + 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) { ++ if (kind == w83627hf || kind == w83697hf) { + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + } +@@ -1139,7 +1242,7 @@ + + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); +- if (kind == w83627thf || kind == w83637hf) ++ if (kind == w83627thf || kind == w83637hf || kind == w83687thf) + device_create_file_pwm(new_client, 3); + + device_create_file_sensor(new_client, 1); +@@ -1187,7 +1290,7 @@ + struct w83627hf_data *data = i2c_get_clientdata(client); + int res, word_sized; + +- down(&data->lock); ++ mutex_lock(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) +@@ -1213,7 +1316,7 @@ + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } +- up(&data->lock); ++ mutex_unlock(&data->lock); + return res; + } + +@@ -1247,12 +1350,39 @@ + return res; + } + ++static int w83687thf_read_vid(struct i2c_client *client) ++{ ++ int res = 0xff; ++ ++ superio_enter(); ++ superio_select(W83627HF_LD_HWM); ++ ++ /* Make sure these GPIO pins are enabled */ ++ if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) { ++ dev_dbg(&client->dev, "VID disabled, no VID function\n"); ++ goto exit; ++ } ++ ++ /* Make sure the pins are configured for input */ ++ if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) { ++ dev_dbg(&client->dev, "VID configured as output, " ++ "no VID function\n"); ++ goto exit; ++ } ++ ++ res = superio_inb(W83687THF_VID_DATA) & 0x3f; ++ ++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); ++ mutex_lock(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) +@@ -1277,7 +1407,7 @@ + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } + +@@ -1324,10 +1454,13 @@ + data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); + } else if (w83627thf == data->type) { + data->vid = w83627thf_read_gpio5(client); ++ } else if (w83687thf == data->type) { ++ data->vid = w83687thf_read_vid(client); + } + + /* Read VRM & OVT Config only once */ +- if (w83627thf == data->type || w83637hf == data->type) { ++ if (w83627thf == data->type || w83637hf == data->type ++ || w83687thf == data->type) { + data->vrm_ovt = + w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + } +@@ -1387,14 +1520,14 @@ + struct w83627hf_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&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) ++ ((data->type != w83627hf && data->type != w83697hf) + && (i == 5 || i == 6))) + continue; + data->in[i] = +@@ -1470,7 +1603,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/w83781d.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/w83781d.c 2006-03-22 17:06:16.000000000 +0100 +@@ -42,6 +42,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-vid.h> + #include <linux/err.h> ++#include <linux/mutex.h> + #include <asm/io.h> + #include "lm75.h" + +@@ -56,6 +57,10 @@ + I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + ++static int reset; ++module_param(reset, bool, 0); ++MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); ++ + static int init = 1; + module_param(init, bool, 0); + MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); +@@ -226,10 +231,10 @@ + struct w83781d_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore lock; ++ struct mutex lock; + enum chips type; + +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + +@@ -262,14 +267,12 @@ + u8 vrm; + }; + +-static int w83781d_attach_adapter(struct i2c_adapter *adapter); + static int w83781d_isa_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 int w83781d_read_value(struct i2c_client *client, u16 reg); ++static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value); + static struct w83781d_data *w83781d_update_device(struct device *dev); + static void w83781d_init_client(struct i2c_client *client); + +@@ -278,7 +281,9 @@ + .name = "w83781d", + }, + .id = I2C_DRIVERID_W83781D, +- .attach_adapter = w83781d_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = w83781d_detect, + .detach_client = w83781d_detach_client, + }; + +@@ -311,11 +316,11 @@ + \ + val = simple_strtoul(buf, NULL, 10) / 10; \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&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); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + store_in_reg(MIN, min); +@@ -381,13 +386,13 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -446,7 +451,7 @@ + \ + val = simple_strtol(buf, NULL, 10); \ + \ +- down(&data->update_lock); \ ++ mutex_lock(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ +@@ -458,7 +463,7 @@ + data->temp_##reg); \ + } \ + \ +- up(&data->update_lock); \ ++ mutex_unlock(&data->update_lock); \ + return count; \ + } + store_temp_reg(OVER, max); +@@ -571,7 +576,7 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val, data->type); +@@ -592,7 +597,7 @@ + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -637,7 +642,7 @@ + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], +@@ -662,7 +667,7 @@ + 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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -709,10 +714,10 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&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); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -725,7 +730,7 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + switch (val) { + case 0: +@@ -742,11 +747,11 @@ + break; + + default: +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return -EINVAL; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -808,7 +813,7 @@ + + val = simple_strtoul(buf, NULL, 10); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ +@@ -841,7 +846,7 @@ + break; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + return count; + } + +@@ -865,18 +870,6 @@ + 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_probe(adapter, &addr_data, w83781d_detect); +-} +- + static int + w83781d_isa_attach_adapter(struct i2c_adapter *adapter) + { +@@ -1073,7 +1066,7 @@ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; +- init_MUTEX(&data->lock); ++ mutex_init(&data->lock); + new_client->adapter = adapter; + new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver; + new_client->flags = 0; +@@ -1178,7 +1171,7 @@ + data->type = kind; + + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) +@@ -1325,7 +1318,7 @@ + int res, word_sized, bank; + struct i2c_client *cl; + +- down(&data->lock); ++ mutex_lock(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) +@@ -1383,7 +1376,7 @@ + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } +- up(&data->lock); ++ mutex_unlock(&data->lock); + return res; + } + +@@ -1394,7 +1387,7 @@ + int word_sized, bank; + struct i2c_client *cl; + +- down(&data->lock); ++ mutex_lock(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) +@@ -1447,7 +1440,7 @@ + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } +- up(&data->lock); ++ mutex_unlock(&data->lock); + return 0; + } + +@@ -1459,8 +1452,17 @@ + int type = data->type; + u8 tmp; + +- if (init && type != as99127f) { /* this resets registers we don't have ++ if (reset && type != as99127f) { /* this resets registers we don't have + documentation for on the as99127f */ ++ /* Resetting the chip has been the default for a long time, ++ but it causes the BIOS initializations (fan clock dividers, ++ thermal sensor types...) to be lost, so it is now optional. ++ It might even go away if nobody reports it as being useful, ++ as I see very little reason why this would be needed at ++ all. */ ++ dev_info(&client->dev, "If reset=1 solved a problem you were " ++ "having, please report!\n"); ++ + /* save these registers */ + i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + p = w83781d_read_value(client, W83781D_REG_PWMCLK12); +@@ -1477,6 +1479,13 @@ + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + ++ /* Disable power-on abnormal beep, as advised by the datasheet. ++ Already done if reset=1. */ ++ if (init && !reset && type != as99127f) { ++ i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); ++ w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); ++ } ++ + data->vrm = vid_which_vrm(); + + if ((type != w83781d) && (type != as99127f)) { +@@ -1533,7 +1542,7 @@ + struct w83781d_data *data = i2c_get_clientdata(client); + int i; + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { +@@ -1641,7 +1650,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/drivers/hwmon/w83l785ts.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/w83l785ts.c 2006-03-22 17:06:16.000000000 +0100 +@@ -39,6 +39,7 @@ + #include <linux/hwmon.h> + #include <linux/hwmon-sysfs.h> + #include <linux/err.h> ++#include <linux/mutex.h> + + /* How many retries on register read error */ + #define MAX_RETRIES 5 +@@ -80,7 +81,6 @@ + * 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); +@@ -96,7 +96,9 @@ + .name = "w83l785ts", + }, + .id = I2C_DRIVERID_W83L785TS, +- .attach_adapter = w83l785ts_attach_adapter, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = w83l785ts_detect, + .detach_client = w83l785ts_detach_client, + }; + +@@ -107,7 +109,7 @@ + struct w83l785ts_data { + struct i2c_client client; + struct class_device *class_dev; +- struct semaphore update_lock; ++ struct mutex update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + +@@ -135,13 +137,6 @@ + * Real code + */ + +-static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) +-{ +- if (!(adapter->class & I2C_CLASS_HWMON)) +- return 0; +- return i2c_probe(adapter, &addr_data, w83l785ts_detect); +-} +- + /* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. +@@ -221,7 +216,7 @@ + /* We can fill in the remaining client fields. */ + strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); + data->valid = 0; +- init_MUTEX(&data->update_lock); ++ mutex_init(&data->update_lock); + + /* Default values in case the first read fails (unlikely). */ + data->temp[1] = data->temp[0] = 0; +@@ -299,7 +294,7 @@ + struct i2c_client *client = to_i2c_client(dev); + struct w83l785ts_data *data = i2c_get_clientdata(client); + +- down(&data->update_lock); ++ mutex_lock(&data->update_lock); + + if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { + dev_dbg(&client->dev, "Updating w83l785ts data.\n"); +@@ -312,7 +307,7 @@ + data->valid = 1; + } + +- up(&data->update_lock); ++ mutex_unlock(&data->update_lock); + + return data; + } +--- linux-2.6.16.orig/Documentation/hwmon/w83627hf 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/Documentation/hwmon/w83627hf 2006-03-22 17:06:15.000000000 +0100 +@@ -18,6 +18,10 @@ + Prefix: 'w83637hf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf ++ * Winbond W83687THF ++ Prefix: 'w83687thf' ++ Addresses scanned: ISA address retrieved from Super I/O registers ++ Datasheet: Provided by Winbond on request + + Authors: + Frodo Looijaard <frodol@dds.nl>, +--- linux-2.6.16.orig/drivers/hwmon/Kconfig 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/Kconfig 2006-03-22 17:06:16.000000000 +0100 +@@ -236,11 +236,11 @@ + will be called lm80. + + config SENSORS_LM83 +- tristate "National Semiconductor LM83" ++ tristate "National Semiconductor LM83 and compatibles" + depends on HWMON && I2C + help + If you say yes here you get support for National Semiconductor +- LM83 sensor chips. ++ LM82 and LM83 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm83. +@@ -333,11 +333,32 @@ + 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. ++ LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and ++ LPC47M997 chips. ++ ++ The temperature and voltage sensor features of the LPC47M192 ++ and LPC47M997 are supported by another driver, select also ++ "SMSC LPC47M192 and compatibles" below for those. + + This driver can also be built as a module. If so, the module + will be called smsc47m1. + ++config SENSORS_SMSC47M192 ++ tristate "SMSC LPC47M192 and compatibles" ++ depends on HWMON && I2C && EXPERIMENTAL ++ select HWMON_VID ++ help ++ If you say yes here you get support for the temperature and ++ voltage sensors of the SMSC LPC47M192 and LPC47M997 chips. ++ ++ The fan monitoring and control capabilities of these chips ++ are supported by another driver, select ++ "SMSC LPC47M10x and compatibles" above. You need both drivers ++ if you want fan control and voltage/temperature sensor support. ++ ++ This driver can also be built as a module. If so, the module ++ will be called smsc47m192. ++ + config SENSORS_SMSC47B397 + tristate "SMSC LPC47B397-NC" + depends on HWMON && I2C && EXPERIMENTAL +@@ -406,13 +427,14 @@ + will be called w83l785ts. + + config SENSORS_W83627HF +- tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF" +- depends on HWMON && I2C && EXPERIMENTAL ++ tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" ++ depends on HWMON && I2C + select I2C_ISA + select HWMON_VID + help + If you say yes here you get support for the Winbond W836X7 series +- of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF ++ of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and ++ W83697HF. + + This driver can also be built as a module. If so, the module + will be called w83627hf. +--- linux-2.6.16.orig/drivers/hwmon/hwmon-vid.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/hwmon-vid.c 2006-03-22 17:06:15.000000000 +0100 +@@ -54,6 +54,10 @@ + (IMVP-II). You can find more information in the datasheet of Max1718 + http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452 + ++ The 13 specification corresponds to the Intel Pentium M series. There ++ doesn't seem to be any named specification for these. The conversion ++ tables are detailed directly in the various Pentium M datasheets: ++ http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm + */ + + /* vrm is the VRM/VRD document version multiplied by 10. +@@ -100,6 +104,8 @@ + case 17: /* Intel IMVP-II */ + return(val & 0x10 ? 975 - (val & 0xF) * 25 : + 1750 - val * 50); ++ case 13: ++ return(1708 - (val & 0x3f) * 16); + default: /* report 0 for unknown */ + printk(KERN_INFO "hwmon-vid: requested unknown VRM version\n"); + return 0; +@@ -129,8 +135,9 @@ + static struct vrm_model vrm_models[] = { + {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ + {X86_VENDOR_AMD, 0xF, ANY, ANY, 24}, /* Athlon 64, Opteron and above VRM 24 */ +- {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 85}, /* 0.13um too */ ++ {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ + {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ ++ {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ + {X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */ + {X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */ + {X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */ +--- linux-2.6.16.orig/Documentation/hwmon/w83781d 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/Documentation/hwmon/w83781d 2006-03-22 17:06:15.000000000 +0100 +@@ -36,6 +36,11 @@ + Use 'init=0' to bypass initializing the chip. + Try this if your computer crashes when you load the module. + ++* reset int ++ (default 0) ++ The driver used to reset the chip on load, but does no more. Use ++ 'reset=1' to restore the old behavior. Report if you need to do this. ++ + force_subclients=bus,caddr,saddr,saddr + This is used to force the i2c addresses for subclients of + a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' +@@ -123,6 +128,25 @@ + your computer speaker. It is possible to enable all beeping globally, + or only the beeping for some alarms. + ++Individual alarm and beep bits: ++ ++0x000001: in0 ++0x000002: in1 ++0x000004: in2 ++0x000008: in3 ++0x000010: temp1 ++0x000020: temp2 (+temp3 on W83781D) ++0x000040: fan1 ++0x000080: fan2 ++0x000100: in4 ++0x000200: in5 ++0x000400: in6 ++0x000800: fan3 ++0x001000: chassis ++0x002000: temp3 (W83782D and W83627HF only) ++0x010000: in7 (W83782D and W83627HF only) ++0x020000: in8 (W83782D and W83627HF only) ++ + If an alarm triggers, it will remain triggered until the hardware register + is read at least once. This means that the cause for the alarm may + already have disappeared! Note that in the current implementation, all +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-frodo.c 2006-03-22 17:06:09.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,85 +0,0 @@ +- +-/* +- * linux/drivers/i2c/i2c-frodo.c +- * +- * Author: Abraham van der Merwe <abraham@2d3d.co.za> +- * +- * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110 +- * Development board (Frodo). +- * +- * This source code is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License +- * version 2 as published by the Free Software Foundation. +- */ +- +-#include <linux/module.h> +-#include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/delay.h> +-#include <linux/i2c.h> +-#include <linux/i2c-algo-bit.h> +-#include <asm/hardware.h> +- +- +-static void frodo_setsda (void *data,int state) +-{ +- if (state) +- FRODO_CPLD_I2C |= FRODO_I2C_SDA_OUT; +- else +- FRODO_CPLD_I2C &= ~FRODO_I2C_SDA_OUT; +-} +- +-static void frodo_setscl (void *data,int state) +-{ +- if (state) +- FRODO_CPLD_I2C |= FRODO_I2C_SCL_OUT; +- else +- FRODO_CPLD_I2C &= ~FRODO_I2C_SCL_OUT; +-} +- +-static int frodo_getsda (void *data) +-{ +- return ((FRODO_CPLD_I2C & FRODO_I2C_SDA_IN) != 0); +-} +- +-static int frodo_getscl (void *data) +-{ +- return ((FRODO_CPLD_I2C & FRODO_I2C_SCL_IN) != 0); +-} +- +-static struct i2c_algo_bit_data bit_frodo_data = { +- .setsda = frodo_setsda, +- .setscl = frodo_setscl, +- .getsda = frodo_getsda, +- .getscl = frodo_getscl, +- .udelay = 80, +- .mdelay = 80, +- .timeout = HZ +-}; +- +-static struct i2c_adapter frodo_ops = { +- .owner = THIS_MODULE, +- .id = I2C_HW_B_FRODO, +- .algo_data = &bit_frodo_data, +- .dev = { +- .name = "Frodo adapter driver", +- }, +-}; +- +-static int __init i2c_frodo_init (void) +-{ +- return i2c_bit_add_bus(&frodo_ops); +-} +- +-static void __exit i2c_frodo_exit (void) +-{ +- i2c_bit_del_bus(&frodo_ops); +-} +- +-MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>"); +-MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo"); +-MODULE_LICENSE ("GPL"); +- +-module_init (i2c_frodo_init); +-module_exit (i2c_frodo_exit); +- +--- linux-2.6.16.orig/include/linux/i2c-id.h 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/include/linux/i2c-id.h 2006-03-22 17:06:15.000000000 +0100 +@@ -172,7 +172,6 @@ + #define I2C_HW_B_RIVA 0x010010 /* Riva based graphics cards */ + #define I2C_HW_B_IOC 0x010011 /* IOC bit-wiggling */ + #define I2C_HW_B_TSUNA 0x010012 /* DEC Tsunami chipset */ +-#define I2C_HW_B_FRODO 0x010013 /* 2d3D SA-1110 Development Board */ + #define I2C_HW_B_OMAHA 0x010014 /* Omaha I2C interface (ARM) */ + #define I2C_HW_B_GUIDE 0x010015 /* Guide bit-basher */ + #define I2C_HW_B_IXP2000 0x010016 /* GPIO on IXP2000 systems */ +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ite.c 2006-03-22 17:06:09.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ite.c 2006-03-22 17:06:15.000000000 +0100 +@@ -200,9 +200,7 @@ + .owner = THIS_MODULE, + .id = I2C_HW_I_IIC, + .algo_data = &iic_ite_data, +- .dev = { +- .name = "ITE IIC adapter", +- }, ++ .name = "ITE IIC adapter", + }; + + /* Called when the module is loaded. This function starts the +--- linux-2.6.16.orig/drivers/i2c/chips/isp1301_omap.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/chips/isp1301_omap.c 2006-03-22 17:06:15.000000000 +0100 +@@ -1635,8 +1635,6 @@ + .driver = { + .name = "isp1301_omap", + }, +- .id = 1301, /* FIXME "official", i2c-ids.h */ +- .class = I2C_CLASS_HWMON, + .attach_adapter = isp1301_scan_bus, + .detach_client = isp1301_detach_client, + }; +--- linux-2.6.16.orig/Documentation/i2c/busses/i2c-piix4 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/Documentation/i2c/busses/i2c-piix4 2006-03-22 17:06:16.000000000 +0100 +@@ -4,8 +4,10 @@ + * Intel 82371AB PIIX4 and PIIX4E + * Intel 82443MX (440MX) + Datasheet: Publicly available at the Intel website +- * ServerWorks OSB4, CSB5 and CSB6 southbridges ++ * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges + Datasheet: Only available via NDA from ServerWorks ++ * ATI IXP southbridges IXP200, IXP300, IXP400 ++ Datasheet: Not publicly available + * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge + Datasheet: Publicly available at the SMSC website http://www.smsc.com + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-piix4.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-piix4.c 2006-03-22 17:06:16.000000000 +0100 +@@ -22,7 +22,7 @@ + /* + Supports: + Intel PIIX4, 440MX +- Serverworks OSB4, CSB5, CSB6 ++ Serverworks OSB4, CSB5, CSB6, HT-1000 + SMSC Victory66 + + Note: we assume there can only be one device, with one SMBus interface. +@@ -406,19 +406,27 @@ + + static struct i2c_adapter piix4_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + + static struct pci_device_id piix4_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), + .driver_data = 3 }, ++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS), ++ .driver_data = 0 }, ++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS), ++ .driver_data = 0 }, ++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), ++ .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), + .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), + .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6), + .driver_data = 0 }, ++ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB), ++ .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3), + .driver_data = 3 }, + { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3), +--- linux-2.6.16.orig/include/linux/pci_ids.h 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/include/linux/pci_ids.h 2006-03-22 17:06:16.000000000 +0100 +@@ -351,8 +351,11 @@ + #define PCI_DEVICE_ID_ATI_RS480 0x5950 + /* ATI IXP Chipset */ + #define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 ++#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 ++#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 + #define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 + #define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e ++#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 + #define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 + #define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 + +@@ -1369,6 +1372,7 @@ + #define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 + #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 + #define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 ++#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205 + #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 + #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 + #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ixp4xx.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ixp4xx.c 2006-03-22 17:06:16.000000000 +0100 +@@ -125,7 +125,9 @@ + drv_data->algo_data.mdelay = 10; + drv_data->algo_data.timeout = 100; + ++ drv_data->adapter.owner = THIS_MODULE; + drv_data->adapter.id = I2C_HW_B_IXP4XX; ++ drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DATA; + strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, + I2C_NAME_SIZE); + drv_data->adapter.algo_data = &drv_data->algo_data; +--- linux-2.6.16.orig/drivers/media/video/adv7170.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adv7170.c 2006-03-22 17:06:15.000000000 +0100 +@@ -53,7 +53,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(x) (x)->name + +@@ -125,24 +124,21 @@ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + struct adv7170 *encoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = ++ block_data[block_len++] = + encoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +--- linux-2.6.16.orig/drivers/media/video/adv7175.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/adv7175.c 2006-03-22 17:06:16.000000000 +0100 +@@ -49,7 +49,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -68,8 +67,6 @@ + /* ----------------------------------------------------------------------- */ + + struct adv7175 { +- unsigned char reg[128]; +- + int norm; + int input; + int enable; +@@ -95,9 +92,6 @@ + u8 reg, + u8 value) + { +- struct adv7175 *encoder = i2c_get_clientdata(client); +- +- encoder->reg[reg] = value; + return i2c_smbus_write_byte_data(client, reg, value); + } + +@@ -120,25 +114,21 @@ + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ +- struct adv7175 *encoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = +- encoder->reg[reg++] = data[1]; ++ block_data[block_len++] = data[1]; ++ reg++; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +@@ -171,24 +161,6 @@ + adv7175_write(client, 0x05, 0x25); + } + +-#ifdef ENCODER_DUMP +-static void +-dump (struct i2c_client *client) +-{ +- struct adv7175 *encoder = i2c_get_clientdata(client); +- int i, j; +- +- printk(KERN_INFO "%s: registry dump\n", I2C_NAME(client)); +- for (i = 0; i < 182 / 8; i++) { +- printk("%s: 0x%02x -", I2C_NAME(client), i * 8); +- for (j = 0; j < 8; j++) { +- printk(" 0x%02x", encoder->reg[i * 8 + j]); +- } +- printk("\n"); +- } +-} +-#endif +- + /* ----------------------------------------------------------------------- */ + // Output filter: S-Video Composite + +@@ -407,14 +379,6 @@ + } + break; + +-#ifdef ENCODER_DUMP +- case ENCODER_DUMP: +- { +- dump(client); +- } +- break; +-#endif +- + default: + return -EINVAL; + } +@@ -424,24 +388,6 @@ + + /* ----------------------------------------------------------------------- */ + +-/* +- * Generic i2c probe +- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' +- */ +-static unsigned short normal_i2c[] = +- { I2C_ADV7175 >> 1, (I2C_ADV7175 >> 1) + 1, +- I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1, +- I2C_CLIENT_END +-}; +- +-static unsigned short ignore = I2C_CLIENT_END; +- +-static struct i2c_client_address_data addr_data = { +- .normal_i2c = normal_i2c, +- .probe = &ignore, +- .ignore = &ignore, +-}; +- + static struct i2c_driver i2c_driver_adv7175; + + static int +@@ -516,16 +462,6 @@ + } + + static int +-adv7175_attach_adapter (struct i2c_adapter *adapter) +-{ +- dprintk(1, +- KERN_INFO +- "adv7175.c: starting probe for adapter %s (0x%x)\n", +- I2C_NAME(adapter), adapter->id); +- return i2c_probe(adapter, &addr_data, &adv7175_detect_client); +-} +- +-static int + adv7175_detach_client (struct i2c_client *client) + { + struct adv7175 *encoder = i2c_get_clientdata(client); +@@ -551,7 +487,7 @@ + + .id = I2C_DRIVERID_ADV7175, + +- .attach_adapter = adv7175_attach_adapter, ++ .detect_client = adv7175_detect_client, + .detach_client = adv7175_detach_client, + .command = adv7175_command, + }; +--- linux-2.6.16.orig/drivers/media/video/bt819.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/bt819.c 2006-03-22 17:06:15.000000000 +0100 +@@ -53,7 +53,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -141,24 +140,21 @@ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + struct bt819 *decoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = ++ block_data[block_len++] = + decoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +--- linux-2.6.16.orig/drivers/media/video/bt856.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/bt856.c 2006-03-22 17:06:15.000000000 +0100 +@@ -53,7 +53,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -71,17 +70,14 @@ + + /* ----------------------------------------------------------------------- */ + +-#define REG_OFFSET 0xCE ++#define REG_OFFSET 0xDA ++#define BT856_NR_REG 6 + + struct bt856 { +- unsigned char reg[32]; ++ unsigned char reg[BT856_NR_REG]; + + int norm; + int enable; +- int bright; +- int contrast; +- int hue; +- int sat; + }; + + #define I2C_BT856 0x88 +@@ -120,8 +116,8 @@ + struct bt856 *encoder = i2c_get_clientdata(client); + + printk(KERN_INFO "%s: register dump:", I2C_NAME(client)); +- for (i = 0xd6; i <= 0xde; i += 2) +- printk(" %02x", encoder->reg[i - REG_OFFSET]); ++ for (i = 0; i < BT856_NR_REG; i += 2) ++ printk(" %02x", encoder->reg[i]); + printk("\n"); + } + +--- linux-2.6.16.orig/drivers/media/video/saa7110.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa7110.c 2006-03-22 17:06:16.000000000 +0100 +@@ -39,7 +39,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -59,8 +58,6 @@ + #define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ + #define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ + +-#define I2C_SAA7110 0x9C /* or 0x9E */ +- + #define SAA7110_NR_REG 0x35 + + struct saa7110 { +@@ -108,13 +105,8 @@ + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + struct saa7110 *decoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + +- msg.len = len; +- msg.buf = (char *) data; +- msg.addr = client->addr; +- msg.flags = 0; +- ret = i2c_transfer(client->adapter, &msg, 1); ++ ret = i2c_master_send(client, data, len); + + /* Cache the written data */ + memcpy(decoder->reg + reg, data + 1, len - 1); +@@ -432,15 +424,13 @@ + break; + + case DECODER_DUMP: +- for (v = 0; v < 0x34; v += 16) { ++ for (v = 0; v < SAA7110_NR_REG; v += 16) { + int j; +- dprintk(1, KERN_INFO "%s: %03x\n", I2C_NAME(client), ++ dprintk(1, KERN_DEBUG "%s: %02x:", I2C_NAME(client), + v); +- for (j = 0; j < 16; j++) { +- dprintk(1, KERN_INFO " %02x", +- decoder->reg[v + j]); +- } +- dprintk(1, KERN_INFO "\n"); ++ for (j = 0; j < 16 && v + j < SAA7110_NR_REG; j++) ++ dprintk(1, " %02x", decoder->reg[v + j]); ++ dprintk(1, "\n"); + } + break; + +@@ -454,24 +444,6 @@ + + /* ----------------------------------------------------------------------- */ + +-/* +- * Generic i2c probe +- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' +- */ +-static unsigned short normal_i2c[] = { +- I2C_SAA7110 >> 1, +- (I2C_SAA7110 >> 1) + 1, +- I2C_CLIENT_END +-}; +- +-static unsigned short ignore = I2C_CLIENT_END; +- +-static struct i2c_client_address_data addr_data = { +- .normal_i2c = normal_i2c, +- .probe = &ignore, +- .ignore = &ignore, +-}; +- + static struct i2c_driver i2c_driver_saa7110; + + static int +@@ -555,16 +527,6 @@ + } + + static int +-saa7110_attach_adapter (struct i2c_adapter *adapter) +-{ +- dprintk(1, +- KERN_INFO +- "saa7110.c: starting probe for adapter %s (0x%x)\n", +- I2C_NAME(adapter), adapter->id); +- return i2c_probe(adapter, &addr_data, &saa7110_detect_client); +-} +- +-static int + saa7110_detach_client (struct i2c_client *client) + { + struct saa7110 *decoder = i2c_get_clientdata(client); +@@ -590,7 +552,7 @@ + + .id = I2C_DRIVERID_SAA7110, + +- .attach_adapter = saa7110_attach_adapter, ++ .detect_client = saa7110_detect_client, + .detach_client = saa7110_detach_client, + .command = saa7110_command, + }; +--- linux-2.6.16.orig/drivers/media/video/saa7111.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa7111.c 2006-03-22 17:06:15.000000000 +0100 +@@ -52,7 +52,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -70,8 +69,10 @@ + + /* ----------------------------------------------------------------------- */ + ++#define SAA7111_NR_REG 0x18 ++ + struct saa7111 { +- unsigned char reg[32]; ++ unsigned char reg[SAA7111_NR_REG]; + + int norm; + int input; +@@ -110,24 +111,21 @@ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + struct saa7111 *decoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = ++ block_data[block_len++] = + decoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +@@ -227,11 +225,11 @@ + { + int i; + +- for (i = 0; i < 32; i += 16) { ++ for (i = 0; i < SAA7111_NR_REG; i += 16) { + int j; + + printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i); +- for (j = 0; j < 16; ++j) { ++ for (j = 0; j < 16 && i + j < SAA7111_NR_REG; ++j) { + printk(" %02x", + saa7111_read(client, i + j)); + } +--- linux-2.6.16.orig/drivers/media/video/saa7114.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa7114.c 2006-03-22 17:06:15.000000000 +0100 +@@ -55,7 +55,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(x) (x)->name + +@@ -139,9 +138,6 @@ + u8 reg, + u8 value) + { +- /*struct saa7114 *decoder = i2c_get_clientdata(client);*/ +- +- /*decoder->reg[reg] = value;*/ + return i2c_smbus_write_byte_data(client, reg, value); + } + +@@ -157,25 +153,21 @@ + * the adapter understands raw I2C */ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ +- /*struct saa7114 *decoder = i2c_get_clientdata(client);*/ +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = +- /*decoder->reg[reg++] =*/ data[1]; ++ block_data[block_len++] = data[1]; ++ reg++; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +--- linux-2.6.16.orig/drivers/media/video/saa711x.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa711x.c 2006-03-22 17:06:15.000000000 +0100 +@@ -45,7 +45,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +--- linux-2.6.16.orig/drivers/media/video/saa7185.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/saa7185.c 2006-03-22 17:06:15.000000000 +0100 +@@ -49,7 +49,6 @@ + MODULE_LICENSE("GPL"); + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(s) (s)->name + +@@ -113,24 +112,21 @@ + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + /* do raw I2C, not smbus compatible */ + struct saa7185 *encoder = i2c_get_clientdata(client); +- struct i2c_msg msg; + u8 block_data[32]; ++ int block_len; + +- msg.addr = client->addr; +- msg.flags = 0; + while (len >= 2) { +- msg.buf = (char *) block_data; +- msg.len = 0; +- block_data[msg.len++] = reg = data[0]; ++ block_len = 0; ++ block_data[block_len++] = reg = data[0]; + do { +- block_data[msg.len++] = ++ block_data[block_len++] = + encoder->reg[reg++] = data[1]; + len -= 2; + data += 2; + } while (len >= 2 && data[0] == reg && +- msg.len < 32); +- if ((ret = i2c_transfer(client->adapter, +- &msg, 1)) < 0) ++ block_len < 32); ++ if ((ret = i2c_master_send(client, block_data, ++ block_len)) < 0) + break; + } + } else { +--- linux-2.6.16.orig/drivers/media/video/vpx3220.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/vpx3220.c 2006-03-22 17:06:15.000000000 +0100 +@@ -30,7 +30,6 @@ + #include <asm/uaccess.h> + + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + + #define I2C_NAME(x) (x)->name + +--- linux-2.6.16.orig/sound/oss/dmasound/dmasound_awacs.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/sound/oss/dmasound/dmasound_awacs.c 2006-03-22 17:06:15.000000000 +0100 +@@ -88,8 +88,6 @@ + #include <linux/pmu.h> + #endif + +-#include <linux/i2c-dev.h> +- + #include <asm/uaccess.h> + #include <asm/prom.h> + #include <asm/machdep.h> +--- linux-2.6.16.orig/sound/ppc/daca.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/sound/ppc/daca.c 2006-03-22 17:06:15.000000000 +0100 +@@ -22,7 +22,6 @@ + #include <sound/driver.h> + #include <linux/init.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <linux/kmod.h> + #include <linux/slab.h> + #include <sound/core.h> +--- linux-2.6.16.orig/sound/ppc/keywest.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/sound/ppc/keywest.c 2006-03-22 17:06:15.000000000 +0100 +@@ -23,7 +23,6 @@ + #include <linux/init.h> + #include <linux/i2c.h> + #include <linux/delay.h> +-#include <linux/i2c-dev.h> + #include <linux/slab.h> + #include <sound/core.h> + #include "pmac.h" +--- linux-2.6.16.orig/sound/ppc/toonie.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/sound/ppc/toonie.c 2006-03-22 17:06:15.000000000 +0100 +@@ -22,7 +22,6 @@ + #include <linux/init.h> + #include <linux/delay.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <linux/kmod.h> + #include <linux/slab.h> + #include <linux/interrupt.h> +--- linux-2.6.16.orig/sound/ppc/tumbler.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/sound/ppc/tumbler.c 2006-03-22 17:06:15.000000000 +0100 +@@ -28,7 +28,6 @@ + #include <linux/init.h> + #include <linux/delay.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <linux/kmod.h> + #include <linux/slab.h> + #include <linux/interrupt.h> +--- linux-2.6.16.orig/drivers/hwmon/hwmon.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/hwmon.c 2006-03-22 17:06:15.000000000 +0100 +@@ -17,6 +17,7 @@ + #include <linux/idr.h> + #include <linux/hwmon.h> + #include <linux/gfp.h> ++#include <linux/spinlock.h> + + #define HWMON_ID_PREFIX "hwmon" + #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" +@@ -24,6 +25,7 @@ + static struct class *hwmon_class; + + static DEFINE_IDR(hwmon_idr); ++static DEFINE_SPINLOCK(idr_lock); + + /** + * hwmon_device_register - register w/ hwmon sysfs class +@@ -37,20 +39,30 @@ + struct class_device *hwmon_device_register(struct device *dev) + { + struct class_device *cdev; +- int id; ++ int id, err; + +- if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0) ++again: ++ if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)) + return ERR_PTR(-ENOMEM); + +- if (idr_get_new(&hwmon_idr, NULL, &id) < 0) +- return ERR_PTR(-ENOMEM); ++ spin_lock(&idr_lock); ++ err = idr_get_new(&hwmon_idr, NULL, &id); ++ spin_unlock(&idr_lock); ++ ++ if (unlikely(err == -EAGAIN)) ++ goto again; ++ else if (unlikely(err)) ++ return ERR_PTR(err); + + id = id & MAX_ID_MASK; + cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, + HWMON_ID_FORMAT, id); + +- if (IS_ERR(cdev)) ++ if (IS_ERR(cdev)) { ++ spin_lock(&idr_lock); + idr_remove(&hwmon_idr, id); ++ spin_unlock(&idr_lock); ++ } + + return cdev; + } +@@ -64,9 +76,11 @@ + { + int id; + +- if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) { ++ if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) { + class_device_unregister(cdev); ++ spin_lock(&idr_lock); + idr_remove(&hwmon_idr, id); ++ spin_unlock(&idr_lock); + } else + dev_dbg(cdev->dev, + "hwmon_device_unregister() failed: bad class ID!\n"); +--- linux-2.6.16.orig/arch/m68k/bvme6000/rtc.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/arch/m68k/bvme6000/rtc.c 2006-03-22 17:06:15.000000000 +0100 +@@ -18,6 +18,7 @@ + #include <linux/module.h> + #include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */ + #include <linux/smp_lock.h> ++#include <linux/bcd.h> + #include <asm/bvme6000hw.h> + + #include <asm/io.h> +@@ -32,9 +33,6 @@ + * ioctls. + */ + +-#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10) +-#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10) +- + static unsigned char days_in_mo[] = + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +--- linux-2.6.16.orig/drivers/video/matrox/matroxfb_maven.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/video/matrox/matroxfb_maven.c 2006-03-22 17:06:15.000000000 +0100 +@@ -129,7 +129,7 @@ + + struct maven_data { + struct matrox_fb_info* primary_head; +- struct i2c_client* client; ++ struct i2c_client client; + int version; + }; + +@@ -970,7 +970,7 @@ + + static int maven_program_timming(struct maven_data* md, + const struct mavenregs* m) { +- struct i2c_client* c = md->client; ++ struct i2c_client* c = &md->client; + + if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { + LR(0x80); +@@ -1007,7 +1007,7 @@ + } + + static inline int maven_resync(struct maven_data* md) { +- struct i2c_client* c = md->client; ++ struct i2c_client* c = &md->client; + maven_set_reg(c, 0x95, 0x20); /* start whole thing */ + return 0; + } +@@ -1065,48 +1065,48 @@ + maven_compute_bwlevel(md, &blacklevel, &whitelevel); + blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); + whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); +- maven_set_reg_pair(md->client, 0x0e, blacklevel); +- maven_set_reg_pair(md->client, 0x1e, whitelevel); ++ maven_set_reg_pair(&md->client, 0x0e, blacklevel); ++ maven_set_reg_pair(&md->client, 0x1e, whitelevel); + } + break; + case V4L2_CID_SATURATION: + { +- maven_set_reg(md->client, 0x20, p->value); +- maven_set_reg(md->client, 0x22, p->value); ++ maven_set_reg(&md->client, 0x20, p->value); ++ maven_set_reg(&md->client, 0x22, p->value); + } + break; + case V4L2_CID_HUE: + { +- maven_set_reg(md->client, 0x25, p->value); ++ maven_set_reg(&md->client, 0x25, p->value); + } + break; + case V4L2_CID_GAMMA: + { + const struct maven_gamma* g; + g = maven_compute_gamma(md); +- maven_set_reg(md->client, 0x83, g->reg83); +- maven_set_reg(md->client, 0x84, g->reg84); +- maven_set_reg(md->client, 0x85, g->reg85); +- maven_set_reg(md->client, 0x86, g->reg86); +- maven_set_reg(md->client, 0x87, g->reg87); +- maven_set_reg(md->client, 0x88, g->reg88); +- maven_set_reg(md->client, 0x89, g->reg89); +- maven_set_reg(md->client, 0x8a, g->reg8a); +- maven_set_reg(md->client, 0x8b, g->reg8b); ++ maven_set_reg(&md->client, 0x83, g->reg83); ++ maven_set_reg(&md->client, 0x84, g->reg84); ++ maven_set_reg(&md->client, 0x85, g->reg85); ++ maven_set_reg(&md->client, 0x86, g->reg86); ++ maven_set_reg(&md->client, 0x87, g->reg87); ++ maven_set_reg(&md->client, 0x88, g->reg88); ++ maven_set_reg(&md->client, 0x89, g->reg89); ++ maven_set_reg(&md->client, 0x8a, g->reg8a); ++ maven_set_reg(&md->client, 0x8b, g->reg8b); + } + break; + case MATROXFB_CID_TESTOUT: + { + unsigned char val +- = maven_get_reg (md->client,0x8d); ++ = maven_get_reg(&md->client,0x8d); + if (p->value) val |= 0x10; + else val &= ~0x10; +- maven_set_reg (md->client, 0x8d, val); ++ maven_set_reg(&md->client, 0x8d, val); + } + break; + case MATROXFB_CID_DEFLICKER: + { +- maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); ++ maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md)); + } + break; + } +@@ -1185,7 +1185,6 @@ + MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); + + md->primary_head = MINFO; +- md->client = clnt; + down_write(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(outputs[1]).output = &maven_altout; + ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; +@@ -1243,19 +1242,17 @@ + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_PROTOCOL_MANGLING)) + goto ERROR0; +- if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data), +- GFP_KERNEL))) { ++ if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } +- memset(new_client, 0, sizeof(*new_client) + sizeof(*data)); +- data = (struct maven_data*)(new_client + 1); ++ new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &maven_driver; + new_client->flags = 0; +- strcpy(new_client->name, "maven client"); ++ strlcpy(new_client->name, "maven", I2C_NAME_SIZE); + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + err = maven_init_client(new_client); +@@ -1279,12 +1276,10 @@ + static int maven_detach_client(struct i2c_client* client) { + int err; + +- if ((err = i2c_detach_client(client))) { +- printk(KERN_ERR "maven: Cannot deregister client\n"); ++ if ((err = i2c_detach_client(client))) + return err; +- } + maven_shutdown_client(client); +- kfree(client); ++ kfree(i2c_get_clientdata(client)); + return 0; + } + +@@ -1297,20 +1292,13 @@ + .detach_client = maven_detach_client, + }; + +-/* ************************** */ +- +-static int matroxfb_maven_init(void) { +- int err; +- +- err = i2c_add_driver(&maven_driver); +- if (err) { +- printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); +- return err; +- } +- return 0; ++static int __init matroxfb_maven_init(void) ++{ ++ return i2c_add_driver(&maven_driver); + } + +-static void matroxfb_maven_exit(void) { ++static void __exit matroxfb_maven_exit(void) ++{ + i2c_del_driver(&maven_driver); + } + +--- linux-2.6.16.orig/drivers/macintosh/therm_pm72.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/macintosh/therm_pm72.c 2006-03-22 17:06:15.000000000 +0100 +@@ -104,7 +104,6 @@ + #include <linux/kernel.h> + #include <linux/delay.h> + #include <linux/sched.h> +-#include <linux/i2c.h> + #include <linux/slab.h> + #include <linux/init.h> + #include <linux/spinlock.h> +@@ -113,7 +112,6 @@ + #include <linux/reboot.h> + #include <linux/kmod.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <asm/prom.h> + #include <asm/machdep.h> + #include <asm/io.h> +--- linux-2.6.16.orig/drivers/macintosh/windfarm_lm75_sensor.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/macintosh/windfarm_lm75_sensor.c 2006-03-22 17:06:15.000000000 +0100 +@@ -15,7 +15,6 @@ + #include <linux/init.h> + #include <linux/wait.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <asm/prom.h> + #include <asm/machdep.h> + #include <asm/io.h> +--- linux-2.6.16.orig/drivers/macintosh/windfarm_max6690_sensor.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/macintosh/windfarm_max6690_sensor.c 2006-03-22 17:06:15.000000000 +0100 +@@ -11,7 +11,6 @@ + #include <linux/init.h> + #include <linux/slab.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <asm/prom.h> + #include <asm/pmac_low_i2c.h> + +--- linux-2.6.16.orig/drivers/macintosh/windfarm_smu_sat.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/drivers/macintosh/windfarm_smu_sat.c 2006-03-22 17:06:15.000000000 +0100 +@@ -13,7 +13,6 @@ + #include <linux/init.h> + #include <linux/wait.h> + #include <linux/i2c.h> +-#include <linux/i2c-dev.h> + #include <asm/semaphore.h> + #include <asm/prom.h> + #include <asm/smu.h> +--- linux-2.6.16.orig/arch/i386/kernel/traps.c 2006-03-22 17:06:08.000000000 +0100 ++++ linux-2.6.16/arch/i386/kernel/traps.c 2006-03-22 17:06:15.000000000 +0100 +@@ -166,8 +166,7 @@ + stack = (unsigned long*)context->previous_esp; + if (!stack) + break; +- printk(log_lvl); +- printk(" =======================\n"); ++ printk("%s =======================\n", log_lvl); + } + } + +@@ -196,14 +195,12 @@ + break; + if (i && ((i % 8) == 0)) { + printk("\n"); +- printk(log_lvl); +- printk(" "); ++ printk("%s ", log_lvl); + } + printk("%08lx ", *stack++); + } + printk("\n"); +- printk(log_lvl); +- printk("Call Trace:\n"); ++ printk("%sCall Trace:\n", log_lvl); + show_trace_log_lvl(task, esp, log_lvl); + } + +--- linux-2.6.16.orig/drivers/media/video/zoran_card.c 2006-03-22 17:06:07.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/zoran_card.c 2006-03-22 17:06:16.000000000 +0100 +@@ -452,6 +452,8 @@ + .device_id = PCI_DEVICE_ID_MIRO_DC10PLUS, + .i2c_decoder = I2C_DRIVERID_SAA7110, + .i2c_encoder = I2C_DRIVERID_ADV7175, ++ .decoder_addr = 0x4e, ++ .encoder_addr = 0x2b, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 3, +@@ -995,10 +997,7 @@ + static int __devinit + zr36057_init (struct zoran *zr) + { +- u32 *mem; +- void *vdev; +- unsigned mem_needed; +- int j; ++ int j, err; + int two = 2; + int zero = 0; + +@@ -1049,19 +1048,16 @@ + + /* allocate memory *before* doing anything to the hardware + * in case allocation fails */ +- mem_needed = BUZ_NUM_STAT_COM * 4; +- mem = kzalloc(mem_needed, GFP_KERNEL); +- vdev = (void *) kmalloc(sizeof(struct video_device), GFP_KERNEL); +- if (!mem || !vdev) { ++ zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL); ++ zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL); ++ if (!zr->stat_com || !zr->video_dev) { + dprintk(1, + KERN_ERR + "%s: zr36057_init() - kmalloc (STAT_COM) failed\n", + ZR_DEVNAME(zr)); +- kfree(vdev); +- kfree(mem); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto exit_free; + } +- zr->stat_com = mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } +@@ -1069,16 +1065,11 @@ + /* + * Now add the template and register the device unit. + */ +- zr->video_dev = vdev; + memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template)); + strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); +- if (video_register_device(zr->video_dev, VFL_TYPE_GRABBER, +- video_nr) < 0) { +- zoran_unregister_i2c(zr); +- kfree((void *) zr->stat_com); +- kfree(vdev); +- return -1; +- } ++ err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr); ++ if (err < 0) ++ goto exit_unregister; + + zoran_init_hardware(zr); + if (*zr_debug > 2) +@@ -1092,6 +1083,13 @@ + zr->zoran_proc = NULL; + zr->initialized = 1; + return 0; ++ ++exit_unregister: ++ zoran_unregister_i2c(zr); ++exit_free: ++ kfree(zr->stat_com); ++ kfree(zr->video_dev); ++ return err; + } + + static void +@@ -1121,7 +1119,7 @@ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + /* unmap and free memory */ +- kfree((void *) zr->stat_com); ++ kfree(zr->stat_com); + zoran_proc_cleanup(zr); + iounmap(zr->zr36057_mem); + pci_disable_device(zr->pci_dev); +@@ -1349,6 +1347,14 @@ + i2c_dec_name = NULL; + } + ++ if (zoran_register_i2c(zr) < 0) { ++ dprintk(1, ++ KERN_ERR ++ "%s: find_zr36057() - can't initialize i2c bus\n", ++ ZR_DEVNAME(zr)); ++ goto zr_free_irq; ++ } ++ + if (i2c_dec_name) { + if ((result = request_module(i2c_dec_name)) < 0) { + dprintk(1, +@@ -1356,6 +1362,10 @@ + "%s: failed to load module %s: %d\n", + ZR_DEVNAME(zr), i2c_dec_name, result); + } ++ ++ i2c_probe_device(&zr->i2c_adapter, ++ zr->card.i2c_decoder, ++ zr->card.decoder_addr, 0); + } + + /* i2c encoder */ +@@ -1376,14 +1386,10 @@ + "%s: failed to load module %s: %d\n", + ZR_DEVNAME(zr), i2c_enc_name, result); + } +- } + +- if (zoran_register_i2c(zr) < 0) { +- dprintk(1, +- KERN_ERR +- "%s: find_zr36057() - can't initialize i2c bus\n", +- ZR_DEVNAME(zr)); +- goto zr_free_irq; ++ i2c_probe_device(&zr->i2c_adapter, ++ zr->card.i2c_encoder, ++ zr->card.encoder_addr, 0); + } + + dprintk(2, +--- linux-2.6.16.orig/Documentation/hwmon/lm83 2006-03-22 17:06:07.000000000 +0100 ++++ linux-2.6.16/Documentation/hwmon/lm83 2006-03-22 17:06:16.000000000 +0100 +@@ -7,6 +7,10 @@ + Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM83.html ++ * National Semiconductor LM82 ++ Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e ++ Datasheet: Publicly available at the National Semiconductor website ++ http://www.national.com/pf/LM/LM82.html + + + Author: Jean Delvare <khali@linux-fr.org> +@@ -15,10 +19,11 @@ + ----------- + + The LM83 is a digital temperature sensor. It senses its own temperature as +-well as the temperature of up to three external diodes. It is compatible +-with many other devices such as the LM84 and all other ADM1021 clones. +-The main difference between the LM83 and the LM84 in that the later can +-only sense the temperature of one external diode. ++well as the temperature of up to three external diodes. The LM82 is ++a stripped down version of the LM83 that only supports one external diode. ++Both are compatible with many other devices such as the LM84 and all ++other ADM1021 clones. The main difference between the LM83 and the LM84 ++in that the later can only sense the temperature of one external diode. + + Using the adm1021 driver for a LM83 should work, but only two temperatures + will be reported instead of four. +@@ -36,6 +41,9 @@ + Iwill MPX2 + Soltek SL-75DRV5 + ++The LM82 is confirmed to have been found on most AMD Geode reference ++designs and test platforms. ++ + The driver has been successfully tested by Magnus Forsström, who I'd + like to thank here. More testers will be of course welcome. + +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.16/Documentation/hwmon/smsc47m192 2006-03-22 17:06:16.000000000 +0100 +@@ -0,0 +1,102 @@ ++Kernel driver smsc47m192 ++======================== ++ ++Supported chips: ++ * SMSC LPC47M192 and LPC47M997 ++ Prefix: 'smsc47m192' ++ Addresses scanned: I2C 0x2c - 0x2d ++ Datasheet: The datasheet for LPC47M192 is publicly available from ++ http://www.smsc.com/ ++ The LPC47M997 is compatible for hardware monitoring. ++ ++Author: Hartmut Rick <linux@rick.claranet.de> ++ Special thanks to Jean Delvare for careful checking ++ of the code and many helpful comments and suggestions. ++ ++ ++Description ++----------- ++ ++This driver implements support for the hardware sensor capabilities ++of the SMSC LPC47M192 and LPC47M997 Super-I/O chips. ++ ++These chips support 3 temperature channels and 8 voltage inputs ++as well as CPU voltage VID input. ++ ++They do also have fan monitoring and control capabilities, but the ++these features are accessed via ISA bus and are not supported by this ++driver. Use the 'smsc47m1' driver for fan monitoring and control. ++ ++Voltages and temperatures are measured by an 8-bit ADC, the resolution ++of the temperatures is 1 bit per degree C. ++Voltages are scaled such that the nominal voltage corresponds to ++192 counts, i.e. 3/4 of the full range. Thus the available range for ++each voltage channel is 0V ... 255/192*(nominal voltage), the resolution ++is 1 bit per (nominal voltage)/192. ++Both voltage and temperature values are scaled by 1000, the sys files ++show voltages in mV and temperatures in units of 0.001 degC. ++ ++The +12V analog voltage input channel (in4_input) is multiplexed with ++bit 4 of the encoded CPU voltage. This means that you either get ++a +12V voltage measurement or a 5 bit CPU VID, but not both. ++The default setting is to use the pin as 12V input, and use only 4 bit VID. ++This driver assumes that the information in the configuration register ++is correct, i.e. that the BIOS has updated the configuration if ++the motherboard has this input wired to VID4. ++ ++The temperature and voltage readings are updated once every 1.5 seconds. ++Reading them more often repeats the same values. ++ ++ ++sysfs interface ++--------------- ++ ++in0_input - +2.5V voltage input ++in1_input - CPU voltage input (nominal 2.25V) ++in2_input - +3.3V voltage input ++in3_input - +5V voltage input ++in4_input - +12V voltage input (may be missing if used as VID4) ++in5_input - Vcc voltage input (nominal 3.3V) ++ This is the supply voltage of the sensor chip itself. ++in6_input - +1.5V voltage input ++in7_input - +1.8V voltage input ++ ++in[0-7]_min, ++in[0-7]_max - lower and upper alarm thresholds for in[0-7]_input reading ++ ++ All voltages are read and written in mV. ++ ++in[0-7]_alarm - alarm flags for voltage inputs ++ These files read '1' in case of alarm, '0' otherwise. ++ ++temp1_input - chip temperature measured by on-chip diode ++temp[2-3]_input - temperature measured by external diodes (one of these would ++ typically be wired to the diode inside the CPU) ++ ++temp[1-3]_min, ++temp[1-3]_max - lower and upper alarm thresholds for temperatures ++ ++temp[1-3]_offset - temperature offset registers ++ The chip adds the offsets stored in these registers to ++ the corresponding temperature readings. ++ Note that temp1 and temp2 offsets share the same register, ++ they cannot both be different from zero at the same time. ++ Writing a non-zero number to one of them will reset the other ++ offset to zero. ++ ++ All temperatures and offsets are read and written in ++ units of 0.001 degC. ++ ++temp[1-3]_alarm - alarm flags for temperature inputs, '1' in case of alarm, ++ '0' otherwise. ++temp[2-3]_input_fault - diode fault flags for temperature inputs 2 and 3. ++ A fault is detected if the two pins for the corresponding ++ sensor are open or shorted, or any of the two is shorted ++ to ground or Vcc. '1' indicates a diode fault. ++ ++cpu0_vid - CPU voltage as received from the CPU ++ ++vrm - CPU VID standard used for decoding CPU voltage ++ ++ The *_min, *_max, *_offset and vrm files can be read and ++ written, all others are read-only. +--- linux-2.6.16.orig/Documentation/hwmon/sysfs-interface 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/Documentation/hwmon/sysfs-interface 2006-03-22 17:06:16.000000000 +0100 +@@ -218,6 +218,12 @@ + from the critical value. + Read/Write value. + ++temp[1-4]_offset ++ Temperature offset which is added to the temperature reading ++ by the chip. ++ Unit: millidegree Celsius ++ Read/Write value. ++ + If there are multiple temperature sensors, temp1_* is + generally the sensor inside the chip itself, + reported as "motherboard temperature". temp2_* to +@@ -246,9 +252,68 @@ + Read only. + + +-********* +-* Other * +-********* ++********** ++* Alarms * ++********** ++ ++Each channel or limit may have an associated alarm file, containing a ++boolean value. 1 means than an alarm condition exists, 0 means no alarm. ++ ++Usually a given chip will either use channel-related alarms, or ++limit-related alarms, not both. The driver should just reflect the hardware ++implementation. ++ ++in[0-n]_alarm ++fan[1-n]_alarm ++temp[1-n]_alarm ++ Channel alarm ++ Boolean ++ Read-only ++ ++OR ++ ++in[0-n]_min_alarm ++in[0-n]_max_alarm ++fan[1-n]_min_alarm ++temp[1-n]_min_alarm ++temp[1-n]_max_alarm ++temp[1-n]_crit_alarm ++ Limit alarm ++ Boolean ++ Read-only ++ ++In theory, a chip could provide per-limit beep masking, but no such chip ++was seen so far. ++ ++Each input channel may have an associated fault file. This can be used ++to notify open diodes, unconnected fans etc. where the hardware ++supports it. When this boolean has value 1, the measurement for that ++channel should not be trusted. ++ ++fan[1-n]_input_fault ++temp[1-n]_input_fault ++ Input fault condition ++ Boolean ++ Read-only ++ ++Some chips also offer the possibility to get beeped when an alarm occurs: ++ ++beep_enable Master beep enable ++ 0 to disable. ++ 1 to enable. ++ Read/Write ++ ++in[0-n]_beep ++fan[1-n]_beep ++temp[1-n]_beep ++ Channel beep ++ 0 to disable. ++ 1 to enable. ++ Read/write ++ ++Old drivers provided a different, non-standard interface to alarms and ++beeps. These interface files are deprecated, but will be kept around ++for compatibility reasons: + + alarms Alarm bitmask. + Read only. +@@ -259,33 +324,22 @@ + if it is still valid. + Generally a direct representation of a chip's internal + alarm registers; there is no standard for the position +- of individual bits. ++ of individual bits. For this reason, the use of this ++ interface file for new drivers is discouraged. Use ++ individual *_alarm and *_fault files instead. + Bits are defined in kernel/include/sensors.h. + +-alarms_in Alarm bitmask relative to in (voltage) channels +- Read only +- A '1' bit means an alarm, LSB corresponds to in0 and so on +- Prefered to 'alarms' for newer chips +- +-alarms_fan Alarm bitmask relative to fan channels +- Read only +- A '1' bit means an alarm, LSB corresponds to fan1 and so on +- Prefered to 'alarms' for newer chips +- +-alarms_temp Alarm bitmask relative to temp (temperature) channels +- Read only +- A '1' bit means an alarm, LSB corresponds to temp1 and so on +- Prefered to 'alarms' for newer chips +- +-beep_enable Beep/interrupt enable +- 0 to disable. +- 1 to enable. +- Read/Write +- + beep_mask Bitmask for beep. +- Same format as 'alarms' with the same bit locations. ++ Same format as 'alarms' with the same bit locations, ++ use discouraged for the same reason. Use individual ++ *_beep files instead. + Read/Write + ++ ++********* ++* Other * ++********* ++ + eeprom Raw EEPROM data in binary form. + Read only. + +--- linux-2.6.16.orig/drivers/hwmon/Makefile 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/drivers/hwmon/Makefile 2006-03-22 17:06:16.000000000 +0100 +@@ -40,6 +40,7 @@ + obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o + obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o + obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o ++obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o + obj-$(CONFIG_SENSORS_VIA686A) += via686a.o + obj-$(CONFIG_SENSORS_VT8231) += vt8231.o + obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.16/drivers/hwmon/smsc47m192.c 2006-03-22 17:06:16.000000000 +0100 +@@ -0,0 +1,638 @@ ++/* ++ smsc47m192.c - Support for hardware monitoring block of ++ SMSC LPC47M192 and LPC47M997 Super I/O chips ++ ++ Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de> ++ ++ Derived from lm78.c and other chip drivers. ++ ++ 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/jiffies.h> ++#include <linux/i2c.h> ++#include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> ++#include <linux/hwmon-vid.h> ++#include <linux/err.h> ++ ++/* Addresses to scan */ ++static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; ++ ++/* Insmod parameters */ ++I2C_CLIENT_INSMOD_1(smsc47m192); ++ ++/* SMSC47M192 registers */ ++#define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \ ++ (0x50 + (nr) - 6)) ++#define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \ ++ (0x54 + (((nr) - 6) * 2))) ++#define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \ ++ (0x55 + (((nr) - 6) * 2))) ++static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 }; ++static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 }; ++static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 }; ++#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f) ++#define SMSC47M192_REG_ALARM1 0x41 ++#define SMSC47M192_REG_ALARM2 0x42 ++#define SMSC47M192_REG_VID 0x47 ++#define SMSC47M192_REG_VID4 0x49 ++#define SMSC47M192_REG_CONFIG 0x40 ++#define SMSC47M192_REG_SFR 0x4f ++#define SMSC47M192_REG_COMPANY_ID 0x3e ++#define SMSC47M192_REG_VERSION 0x3f ++ ++/* 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; ++} ++ ++/* Conversions */ ++ ++/* smsc47m192 internally scales voltage measurements */ ++static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 }; ++ ++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); ++} ++ ++/* TEMP: 0.001 degC units (-128C to +127C) ++ REG: 1C/bit, two's complement */ ++static inline s8 TEMP_TO_REG(int val) ++{ ++ return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000); ++} ++ ++static inline int TEMP_FROM_REG(s8 val) ++{ ++ return val * 1000; ++} ++ ++struct smsc47m192_data { ++ struct i2c_client client; ++ struct class_device *class_dev; ++ struct semaphore update_lock; ++ char valid; /* !=0 if following fields are valid */ ++ unsigned long last_updated; /* 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_max[3]; /* Register value */ ++ s8 temp_min[3]; /* Register value */ ++ s8 temp_offset[3]; /* Register value */ ++ u16 alarms; /* Register encoding, combined */ ++ u8 vid; /* Register encoding, combined */ ++ u8 vrm; ++}; ++ ++static int smsc47m192_detect(struct i2c_adapter *adapter, int address, ++ int kind); ++static int smsc47m192_detach_client(struct i2c_client *client); ++static struct smsc47m192_data *smsc47m192_update_device(struct device *dev); ++ ++static struct i2c_driver smsc47m192_driver = { ++ .driver = { ++ .name = "smsc47m192", ++ }, ++ .class = I2C_CLASS_HWMON, ++ .address_data = &addr_data, ++ .detect_client = smsc47m192_detect, ++ .detach_client = smsc47m192_detach_client, ++}; ++ ++/* Voltages */ ++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 smsc47m192_data *data = smsc47m192_update_device(dev); ++ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], 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 smsc47m192_data *data = smsc47m192_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, struct device_attribute *attr, ++ char *buf) ++{ ++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); ++ int nr = sensor_attr->index; ++ struct smsc47m192_data *data = smsc47m192_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, 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 smsc47m192_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); ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_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 smsc47m192_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); ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_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); \ ++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) ++show_in_offset(1) ++show_in_offset(2) ++show_in_offset(3) ++show_in_offset(4) ++show_in_offset(5) ++show_in_offset(6) ++show_in_offset(7) ++ ++/* 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 smsc47m192_data *data = smsc47m192_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 smsc47m192_data *data = smsc47m192_update_device(dev); ++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[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 smsc47m192_data *data = smsc47m192_update_device(dev); ++ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[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 smsc47m192_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); ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr], ++ data->temp_min[nr]); ++ up(&data->update_lock); ++ return count; ++} ++ ++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 smsc47m192_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); ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr], ++ data->temp_max[nr]); ++ up(&data->update_lock); ++ return count; ++} ++ ++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 smsc47m192_data *data = smsc47m192_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 smsc47m192_data *data = i2c_get_clientdata(client); ++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); ++ long val = simple_strtol(buf, NULL, 10); ++ ++ down(&data->update_lock); ++ data->temp_offset[nr] = TEMP_TO_REG(val); ++ if (nr>1) ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); ++ else if (data->temp_offset[nr] != 0) { ++ /* offset[0] and offset[1] share the same register, ++ SFR bit 4 activates offset[0] */ ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR, ++ (sfr & 0xef) | (nr==0 ? 0x10 : 0)); ++ data->temp_offset[1-nr] = 0; ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); ++ } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0)) ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_TEMP_OFFSET(nr), 0); ++ up(&data->update_lock); ++ return count; ++} ++ ++#define show_temp_index(index) \ ++static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, \ ++ show_temp, NULL, index-1); \ ++static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR, \ ++ show_temp_min, set_temp_min, index-1); \ ++static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR, \ ++ show_temp_max, set_temp_max, index-1); \ ++static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR, \ ++ show_temp_offset, set_temp_offset, index-1); ++ ++show_temp_index(1) ++show_temp_index(2) ++show_temp_index(3) ++ ++/* VID */ ++static ssize_t show_vid(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct smsc47m192_data *data = smsc47m192_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 smsc47m192_data *data = smsc47m192_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 smsc47m192_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); ++ ++/* Alarms */ ++static ssize_t show_alarm(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 smsc47m192_data *data = smsc47m192_update_device(dev); ++ return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0); ++} ++ ++static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010); ++static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020); ++static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040); ++static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000); ++static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000); ++static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001); ++static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002); ++static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004); ++static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008); ++static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100); ++static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200); ++static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400); ++static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800); ++ ++static void smsc47m192_init_client(struct i2c_client *client) ++{ ++ int i; ++ u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); ++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); ++ ++ /* select cycle mode (pause 1 sec between updates) */ ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR, ++ (sfr & 0xfd) | 0x02); ++ if (!(config & 0x01)) { ++ /* initialize alarm limits */ ++ for (i=0; i<8; i++) { ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_IN_MIN(i), 0); ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_IN_MAX(i), 0xff); ++ } ++ for (i=0; i<3; i++) { ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_TEMP_MIN[i], 0x80); ++ i2c_smbus_write_byte_data(client, ++ SMSC47M192_REG_TEMP_MAX[i], 0x7f); ++ } ++ ++ /* start monitoring */ ++ i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG, ++ (config & 0xf7) | 0x01); ++ } ++} ++ ++/* This function is called by i2c_probe */ ++static int smsc47m192_detect(struct i2c_adapter *adapter, int address, ++ int kind) ++{ ++ struct i2c_client *client; ++ struct smsc47m192_data *data; ++ int err = 0; ++ int version, config; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ goto exit; ++ ++ if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ client = &data->client; ++ i2c_set_clientdata(client, data); ++ client->addr = address; ++ client->adapter = adapter; ++ client->driver = &smsc47m192_driver; ++ ++ if (kind == 0) ++ kind = smsc47m192; ++ ++ /* Detection criteria from sensors_detect script */ ++ if (kind < 0) { ++ if (i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_COMPANY_ID) == 0x55 ++ && ((version = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_VERSION)) & 0xf0) == 0x20 ++ && (i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_VID) & 0x70) == 0x00 ++ && (i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_VID4) & 0xfe) == 0x80) { ++ dev_info(&adapter->dev, ++ "found SMSC47M192 or SMSC47M997, " ++ "version 2, stepping A%d\n", version & 0x0f); ++ } else { ++ dev_dbg(&adapter->dev, ++ "SMSC47M192 detection failed at 0x%02x\n", ++ address); ++ goto exit_free; ++ } ++ } ++ ++ /* Fill in the remaining client fields and put into the global list */ ++ strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE); ++ data->vrm = vid_which_vrm(); ++ 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 SMSC47M192 chip */ ++ smsc47m192_init_client(client); ++ ++ /* Register sysfs hooks */ ++ data->class_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->class_dev)) { ++ err = PTR_ERR(data->class_dev); ++ goto exit_detach; ++ } ++ ++ device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr); ++ ++ /* Pin 110 is either in4 (+12V) or VID4 */ ++ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); ++ if (!(config & 0x20)) { ++ device_create_file(&client->dev, ++ &sensor_dev_attr_in4_input.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_in4_min.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_in4_max.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_in4_alarm.dev_attr); ++ } ++ device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_temp1_offset.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_temp2_offset.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_temp2_input_fault.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_temp3_offset.dev_attr); ++ device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr); ++ device_create_file(&client->dev, ++ &sensor_dev_attr_temp3_input_fault.dev_attr); ++ device_create_file(&client->dev, &dev_attr_cpu0_vid); ++ device_create_file(&client->dev, &dev_attr_vrm); ++ ++ return 0; ++ ++exit_detach: ++ i2c_detach_client(client); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int smsc47m192_detach_client(struct i2c_client *client) ++{ ++ struct smsc47m192_data *data = i2c_get_clientdata(client); ++ int err; ++ ++ hwmon_device_unregister(data->class_dev); ++ ++ if ((err = i2c_detach_client(client))) ++ return err; ++ ++ kfree(data); ++ ++ return 0; ++} ++ ++static struct smsc47m192_data *smsc47m192_update_device(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct smsc47m192_data *data = i2c_get_clientdata(client); ++ int i, config; ++ ++ down(&data->update_lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ++ || !data->valid) { ++ u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); ++ ++ dev_dbg(&client->dev, "Starting smsc47m192 update\n"); ++ ++ for (i = 0; i <= 7; i++) { ++ data->in[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_IN(i)); ++ data->in_min[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_IN_MIN(i)); ++ data->in_max[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_IN_MAX(i)); ++ } ++ for (i = 0; i < 3; i++) { ++ data->temp[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_TEMP[i]); ++ data->temp_max[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_TEMP_MAX[i]); ++ data->temp_min[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_TEMP_MIN[i]); ++ } ++ for (i = 1; i < 3; i++) ++ data->temp_offset[i] = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_TEMP_OFFSET(i)); ++ /* first offset is temp_offset[0] if SFR bit 4 is set, ++ temp_offset[1] otherwise */ ++ if (sfr & 0x10) { ++ data->temp_offset[0] = data->temp_offset[1]; ++ data->temp_offset[1] = 0; ++ } else ++ data->temp_offset[0] = 0; ++ ++ data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID) ++ & 0x0f; ++ config = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_CONFIG); ++ if (config & 0x20) ++ data->vid |= (i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_VID4) & 0x01) << 4; ++ data->alarms = i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_ALARM1) | ++ (i2c_smbus_read_byte_data(client, ++ SMSC47M192_REG_ALARM2) << 8); ++ ++ data->last_updated = jiffies; ++ data->valid = 1; ++ } ++ ++ up(&data->update_lock); ++ ++ return data; ++} ++ ++static int __init smsc47m192_init(void) ++{ ++ return i2c_add_driver(&smsc47m192_driver); ++} ++ ++static void __exit smsc47m192_exit(void) ++{ ++ i2c_del_driver(&smsc47m192_driver); ++} ++ ++MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>"); ++MODULE_DESCRIPTION("SMSC47M192 driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(smsc47m192_init); ++module_exit(smsc47m192_exit); +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-sis96x.c 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-sis96x.c 2006-03-22 17:06:16.000000000 +0100 +@@ -43,13 +43,6 @@ + #include <linux/init.h> + #include <asm/io.h> + +-/* +- HISTORY: +- 2003-05-11 1.0.0 Updated from lm_sensors project for kernel 2.5 +- (was i2c-sis645.c from lm_sensors 2.7.0) +-*/ +-#define SIS96x_VERSION "1.0.0" +- + /* base address register in PCI config space */ + #define SIS96x_BAR 0x04 + +@@ -256,7 +249,7 @@ + + static struct i2c_adapter sis96x_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +@@ -337,7 +330,6 @@ + + static int __init i2c_sis96x_init(void) + { +- printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION); + return pci_register_driver(&sis96x_driver); + } + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-parport-light.c 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-parport-light.c 2006-03-22 17:06:16.000000000 +0100 +@@ -111,7 +111,7 @@ + + static struct i2c_adapter parport_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .id = I2C_HW_B_LP, + .algo_data = &parport_algo_data, + .name = "Parallel port adapter (light)", +@@ -121,9 +121,14 @@ + + static int __init i2c_parport_init(void) + { +- if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { ++ if (type < 0) { ++ printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); ++ return -ENODEV; ++ } ++ ++ if (type >= ARRAY_SIZE(adapter_parm)) { + printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); +- type = 0; ++ return -ENODEV; + } + + if (base == 0) { +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-parport.h 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-parport.h 2006-03-22 17:06:16.000000000 +0100 +@@ -90,7 +90,7 @@ + }, + }; + +-static int type; ++static int type = -1; + module_param(type, int, 0); + MODULE_PARM_DESC(type, + "Type of adapter:\n" +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-parport.c 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-parport.c 2006-03-22 17:06:16.000000000 +0100 +@@ -146,7 +146,7 @@ + + static struct i2c_adapter parport_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .id = I2C_HW_B_LP, + .name = "Parallel port adapter", + }; +@@ -241,9 +241,14 @@ + + static int __init i2c_parport_init(void) + { +- if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { ++ if (type < 0) { ++ printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); ++ return -ENODEV; ++ } ++ ++ if (type >= ARRAY_SIZE(adapter_parm)) { + printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); +- type = 0; ++ return -ENODEV; + } + + return parport_register_driver(&i2c_parport_driver); +--- linux-2.6.16.orig/Documentation/i2c/busses/i2c-parport 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/Documentation/i2c/busses/i2c-parport 2006-03-22 17:06:16.000000000 +0100 +@@ -12,18 +12,22 @@ + teletext adapters) + + It currently supports the following devices: +- * Philips adapter +- * home brew teletext adapter +- * Velleman K8000 adapter +- * ELV adapter +- * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032) +- * Barco LPT->DVI (K5800236) adapter ++ * (type=0) Philips adapter ++ * (type=1) home brew teletext adapter ++ * (type=2) Velleman K8000 adapter ++ * (type=3) ELV adapter ++ * (type=4) Analog Devices ADM1032 evaluation board ++ * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 ++ * (type=6) Barco LPT->DVI (K5800236) adapter + + These devices use different pinout configurations, so you have to tell + the driver what you have, using the type module parameter. There is no + way to autodetect the devices. Support for different pinout configurations + can be easily added when needed. + ++Earlier kernels defaulted to type=0 (Philips). But now, if the type ++parameter is missing, the driver will simply fail to initialize. ++ + + Building your own adapter + ------------------------- +--- linux-2.6.16.orig/Documentation/i2c/writing-clients 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/Documentation/i2c/writing-clients 2006-03-22 17:06:16.000000000 +0100 +@@ -28,7 +28,9 @@ + .driver = { + .name = "foo", + }, +- .attach_adapter = &foo_attach_adapter, ++ .class = I2C_CLASS_SOMETHING, ++ .address_data = &addr_data, ++ .detect_client = &foo_detect_client, + .detach_client = &foo_detach_client, + .command = &foo_command /* may be NULL */ + } +@@ -141,8 +143,8 @@ + are defined in i2c.h to help you support them, as well as a generic + detection algorithm. + +-You do not have to use this parameter interface; but don't try to use +-function i2c_probe() if you don't. ++You do not have to use this parameter interface; but then the i2c core won't ++be able to probe for devices for you. + + NOTE: If you want to write a `sensors' driver, the interface is slightly + different! See below. +@@ -201,35 +203,49 @@ + ----------------------- + + Whenever a new adapter is inserted, or for all adapters if the driver is +-being registered, the callback attach_adapter() is called. Now is the +-time to determine what devices are present on the adapter, and to register +-a client for each of them. +- +-The attach_adapter callback is really easy: we just call the generic +-detection function. This function will scan the bus for us, using the +-information as defined in the lists explained above. If a device is +-detected at a specific address, another callback is called. ++being registered, your driver may be notified through one of two ++callbacks, depending on the degree of control you need to exercise over ++the probing process. This is the time to determine what devices are ++present on the adapter and to register a client for each device your ++driver supports. ++ ++The easiest way to handle the probing process is to simply set the `class', ++`address_data', and `detect_client' fields in the i2c_driver structure. ++The `class' field is a bitmask of all the adapter classes which should be ++probed for devices supported by this driver. You should set it to one of ++the I2C_CLASS_* constants defined in i2c.h. The `address_data' field ++should be set to `&addr_data', which is defined by the macros explained ++above, so you do not have to define it yourself. When a new adapter is ++attached, the bus is scanned for the addresses defined in the lists above, ++and the detect_client callback gets called when a device is detected at a ++specific address. ++ ++If you prefer, you can omit the `class', `address_data', and ++`detect_client' fields from your i2c_driver structure, and instead set ++`attach_adapter'. The `attach_adapter' callback gets called every time a ++new adapter is attached and the bus needs to be scanned, so if you need to ++perform any special checks or configuration before you scan a bus for ++devices, you should use attach_adapter. If the bus is suitable, you can ++then call the generic i2c_probe function to scan for the addresses in the ++lists explained above, and the callback passed in the third parameter will ++get called for each device detected. + + int foo_attach_adapter(struct i2c_adapter *adapter) + { + return i2c_probe(adapter,&addr_data,&foo_detect_client); + } + +-Remember, structure `addr_data' is defined by the macros explained above, +-so you do not have to define it yourself. +- +-The i2c_probe function will call the foo_detect_client +-function only for those i2c addresses that actually have a device on +-them (unless a `force' parameter was used). In addition, addresses that +-are already in use (by some other registered client) are skipped. ++With either mechanism, addresses that are already in use (by some other ++registered client) are skipped. + + + The detect client function + -------------------------- + +-The detect client function is called by i2c_probe. The `kind' parameter +-contains -1 for a probed detection, 0 for a forced detection, or a positive +-number for a forced detection with a chip type forced. ++The detect client function is called by the address probing mechanism. ++The `kind' parameter contains -1 for a probed detection, 0 for a forced ++detection, or a positive number for a forced detection with a chip type ++forced. + + Below, some things are only needed if this is a `sensors' driver. Those + parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ +--- linux-2.6.16.orig/Documentation/i2c/porting-clients 2006-03-22 17:06:00.000000000 +0100 ++++ linux-2.6.16/Documentation/i2c/porting-clients 2006-03-22 17:06:16.000000000 +0100 +@@ -100,6 +100,9 @@ + Drop any 24RF08 corruption prevention you find, as this is now done + at the i2c-core level, and doing it twice voids it. + Don't add I2C_CLIENT_ALLOW_USE to client->flags, it's the default now. ++ If you want auto probing of your driver, use driver->addr_data ++ (this is strongly encouraged if your attach_adapter is a one-liner ++ which calls i2c_probe). + + * [Init] Limits must not be set by the driver (can be done later in + user-space). Chip should not be reset default (although a module +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ali1563.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ali1563.c 2006-03-22 17:06:16.000000000 +0100 +@@ -374,7 +374,7 @@ + + static struct i2c_adapter ali1563_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &ali1563_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ali15x3.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ali15x3.c 2006-03-22 17:06:16.000000000 +0100 +@@ -470,7 +470,7 @@ + + static struct i2c_adapter ali15x3_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-amd756.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-amd756.c 2006-03-22 17:06:16.000000000 +0100 +@@ -301,7 +301,7 @@ + + struct i2c_adapter amd756_smbus = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-amd8111.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-amd8111.c 2006-03-22 17:06:16.000000000 +0100 +@@ -351,7 +351,7 @@ + smbus->adapter.owner = THIS_MODULE; + snprintf(smbus->adapter.name, I2C_NAME_SIZE, + "SMBus2 AMD8111 adapter at %04x", smbus->base); +- smbus->adapter.class = I2C_CLASS_HWMON; ++ smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DATA; + smbus->adapter.algo = &smbus_algorithm; + smbus->adapter.algo_data = smbus; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-elektor.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-elektor.c 2006-03-22 17:06:16.000000000 +0100 +@@ -202,7 +202,7 @@ + + static struct i2c_adapter pcf_isa_ops = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .id = I2C_HW_P_ELEK, + .algo_data = &pcf_isa_data, + .name = "i2c-elektor", +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-i801.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-i801.c 2006-03-22 17:06:16.000000000 +0100 +@@ -513,7 +513,7 @@ + + static struct i2c_adapter i801_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-i810.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-i810.c 2006-03-22 17:06:16.000000000 +0100 +@@ -188,6 +188,7 @@ + + static struct i2c_adapter i810_ddc_adapter = { + .owner = THIS_MODULE, ++ .class = I2C_CLASS_DATA, + .name = "I810/I815 DDC Adapter", + .algo_data = &i810_ddc_bit_data, + }; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ibm_iic.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ibm_iic.c 2006-03-22 17:06:16.000000000 +0100 +@@ -724,8 +724,9 @@ + adap = &dev->adap; + strcpy(adap->name, "IBM IIC"); + i2c_set_adapdata(adap, dev); ++ adap->owner = THIS_MODULE; + adap->id = I2C_HW_OCP; +- adap->class = I2C_CLASS_HWMON; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DATA; + adap->algo = &iic_algo; + adap->client_register = NULL; + adap->client_unregister = NULL; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-ixp2000.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-ixp2000.c 2006-03-22 17:06:16.000000000 +0100 +@@ -117,7 +117,9 @@ + drv_data->algo_data.mdelay = 6; + drv_data->algo_data.timeout = 100; + +- drv_data->adapter.id = I2C_HW_B_IXP2000, ++ drv_data->adapter.owner = THIS_MODULE; ++ drv_data->adapter.class = I2C_CLASS_DATA; ++ drv_data->adapter.id = I2C_HW_B_IXP2000; + strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, + I2C_NAME_SIZE); + drv_data->adapter.algo_data = &drv_data->algo_data, +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-mpc.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-mpc.c 2006-03-22 17:06:16.000000000 +0100 +@@ -283,7 +283,7 @@ + .name = "MPC adapter", + .id = I2C_HW_MPC107, + .algo = &mpc_algo, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .timeout = 1, + .retries = 1 + }; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-mv64xxx.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-mv64xxx.c 2006-03-22 17:06:16.000000000 +0100 +@@ -519,7 +519,7 @@ + drv_data->adapter.id = I2C_HW_MV64XXX; + drv_data->adapter.algo = &mv64xxx_i2c_algo; + drv_data->adapter.owner = THIS_MODULE; +- drv_data->adapter.class = I2C_CLASS_HWMON; ++ drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DATA; + drv_data->adapter.timeout = pdata->timeout; + drv_data->adapter.retries = pdata->retries; + platform_set_drvdata(pd, drv_data); +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-nforce2.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-nforce2.c 2006-03-22 17:06:16.000000000 +0100 +@@ -113,7 +113,7 @@ + + static struct i2c_adapter nforce2_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-prosavage.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-prosavage.c 2006-03-22 17:06:16.000000000 +0100 +@@ -172,6 +172,7 @@ + { + int ret; + p->adap.owner = THIS_MODULE; ++ p->adap.class = I2C_CLASS_DATA; + p->adap.id = I2C_HW_B_S3VIA; + p->adap.algo_data = &p->algo; + p->adap.dev.parent = &dev->dev; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-s3c2410.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-s3c2410.c 2006-03-22 17:06:16.000000000 +0100 +@@ -580,7 +580,7 @@ + .owner = THIS_MODULE, + .algo = &s3c24xx_i2c_algorithm, + .retries = 2, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + }, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-savage4.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-savage4.c 2006-03-22 17:06:16.000000000 +0100 +@@ -146,6 +146,7 @@ + + static struct i2c_adapter savage4_i2c_adapter = { + .owner = THIS_MODULE, ++ .class = I2C_CLASS_DATA, + .name = "I2C Savage4 adapter", + .algo_data = &sav_i2c_bit_data, + }; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-sibyte.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-sibyte.c 2006-03-22 17:06:16.000000000 +0100 +@@ -31,7 +31,7 @@ + { + .owner = THIS_MODULE, + .id = I2C_HW_SIBYTE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = NULL, + .algo_data = &sibyte_board_data[0], + .name = "SiByte SMBus 0", +@@ -39,7 +39,7 @@ + { + .owner = THIS_MODULE, + .id = I2C_HW_SIBYTE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = NULL, + .algo_data = &sibyte_board_data[1], + .name = "SiByte SMBus 1", +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-sis5595.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-sis5595.c 2006-03-22 17:06:16.000000000 +0100 +@@ -365,7 +365,7 @@ + + static struct i2c_adapter sis5595_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-sis630.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-sis630.c 2006-03-22 17:06:16.000000000 +0100 +@@ -457,7 +457,7 @@ + + static struct i2c_adapter sis630_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-stub.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-stub.c 2006-03-22 17:06:16.000000000 +0100 +@@ -115,7 +115,7 @@ + + static struct i2c_adapter stub_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_ALL, + .algo = &smbus_algorithm, + .name = "SMBus stub driver", + }; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-via.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-via.c 2006-03-22 17:06:16.000000000 +0100 +@@ -87,7 +87,7 @@ + + static struct i2c_adapter vt586b_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .name = "VIA i2c", + .algo_data = &bit_data, + }; +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-viapro.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-viapro.c 2006-03-22 17:06:16.000000000 +0100 +@@ -304,7 +304,7 @@ + + static struct i2c_adapter vt596_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_HWMON, ++ .class = I2C_CLASS_HWMON | I2C_CLASS_DATA, + .algo = &smbus_algorithm, + }; + +--- linux-2.6.16.orig/drivers/i2c/busses/i2c-voodoo3.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/i2c/busses/i2c-voodoo3.c 2006-03-22 17:06:16.000000000 +0100 +@@ -183,7 +183,7 @@ + + static struct i2c_adapter voodoo3_ddc_adapter = { + .owner = THIS_MODULE, +- .class = I2C_CLASS_DDC, ++ .class = I2C_CLASS_DATA, + .name = "DDC Voodoo3/Banshee adapter", + .algo_data = &voo_ddc_bit_data, + }; +--- linux-2.6.16.orig/drivers/video/aty/radeon_i2c.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/aty/radeon_i2c.c 2006-03-22 17:06:16.000000000 +0100 +@@ -75,6 +75,7 @@ + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; ++ chan->adapter.class = I2C_CLASS_DATA; + chan->adapter.id = I2C_HW_B_RADEON; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->rinfo->pdev->dev; +--- linux-2.6.16.orig/drivers/video/i810/i810-i2c.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/i810/i810-i2c.c 2006-03-22 17:06:16.000000000 +0100 +@@ -85,12 +85,14 @@ + return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0); + } + +-static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name) ++static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, ++ unsigned long i2c_class) + { + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; ++ chan->adapter.class = i2c_class; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->dev->dev; + chan->adapter.id = I2C_HW_B_I810; +@@ -130,11 +132,11 @@ + par->chan[2].par = par; + + par->chan[0].ddc_base = GPIOA; +- i810_setup_i2c_bus(&par->chan[0], "I810-DDC"); ++ i810_setup_i2c_bus(&par->chan[0], "I810-DDC", I2C_CLASS_DATA); + par->chan[1].ddc_base = GPIOB; +- i810_setup_i2c_bus(&par->chan[1], "I810-I2C"); ++ i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 0); + par->chan[2].ddc_base = GPIOC; +- i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC"); ++ i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC", 0); + } + + void i810_delete_i2c_busses(struct i810fb_par *par) +--- linux-2.6.16.orig/drivers/video/matrox/i2c-matroxfb.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/matrox/i2c-matroxfb.c 2006-03-22 17:06:16.000000000 +0100 +@@ -104,13 +104,15 @@ + }; + + static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, +- unsigned int data, unsigned int clock, const char* name) { ++ unsigned int data, unsigned int clock, const char* name, ++ unsigned int i2c_class) { + int err; + + b->minfo = minfo; + b->mask.data = data; + b->mask.clock = clock; + b->adapter = matrox_i2c_adapter_template; ++ b->adapter.class = i2c_class; + snprintf(b->adapter.name, I2C_NAME_SIZE, name, + minfo->fbcon.node); + i2c_set_adapdata(&b->adapter, b); +@@ -160,22 +162,28 @@ + switch (ACCESS_FBINFO(chip)) { + case MGA_2064: + case MGA_2164: +- err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0"); ++ err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, ++ DDC1B_CLK, "DDC:fb%u #0", ++ I2C_CLASS_DATA); + break; + default: +- err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0"); ++ err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, ++ DDC1_CLK, "DDC:fb%u #0", ++ I2C_CLASS_DATA); + break; + } + if (err) + goto fail_ddc1; + if (ACCESS_FBINFO(devflags.dualhead)) { +- err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1"); ++ err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, ++ "DDC:fb%u #1", I2C_CLASS_DATA); + if (err == -ENODEV) { + printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n"); + } else if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n"); + /* Register maven bus even on G450/G550 */ +- err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u"); ++ err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, ++ "MAVEN:fb%u", 0); + if (err) + printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n"); + } +--- linux-2.6.16.orig/drivers/video/nvidia/nv_i2c.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/nvidia/nv_i2c.c 2006-03-22 17:06:16.000000000 +0100 +@@ -96,6 +96,7 @@ + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; ++ chan->adapter.class = I2C_CLASS_DATA; + chan->adapter.id = I2C_HW_B_NVIDIA; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pci_dev->dev; +--- linux-2.6.16.orig/drivers/video/riva/rivafb-i2c.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/riva/rivafb-i2c.c 2006-03-22 17:06:16.000000000 +0100 +@@ -98,6 +98,7 @@ + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; ++ chan->adapter.class = I2C_CLASS_DATA; + chan->adapter.id = I2C_HW_B_RIVA; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pdev->dev; +--- linux-2.6.16.orig/drivers/video/savage/savagefb-i2c.c 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/video/savage/savagefb-i2c.c 2006-03-22 17:06:16.000000000 +0100 +@@ -145,6 +145,7 @@ + if (chan->par) { + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; ++ chan->adapter.class = I2C_CLASS_DATA; + chan->adapter.id = I2C_HW_B_SAVAGE; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->pcidev->dev; +--- linux-2.6.16.orig/drivers/media/video/zoran.h 2006-03-22 17:05:59.000000000 +0100 ++++ linux-2.6.16/drivers/media/video/zoran.h 2006-03-22 17:06:16.000000000 +0100 +@@ -355,6 +355,7 @@ + enum card_type type; + char name[32]; + u16 i2c_decoder, i2c_encoder; /* I2C types */ ++ u16 decoder_addr, encoder_addr; /* I2C chips address */ + u16 video_vfe, video_codec; /* videocodec types */ + u16 audio_chip; /* audio type */ + u16 vendor_id, device_id; /* subsystem vendor/device ID */ diff --git a/packages/linux/ixp4xx-kernel/2.6.16/patch-2.6.16-rc4-ide2 b/packages/linux/ixp4xx-kernel/2.6.16/patch-2.6.16-rc4-ide2 deleted file mode 100644 index ea23ff47d3..0000000000 --- a/packages/linux/ixp4xx-kernel/2.6.16/patch-2.6.16-rc4-ide2 +++ /dev/null @@ -1,18474 +0,0 @@ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/arch/i386/pci/fixup.c linux-2.6.16-rc4/arch/i386/pci/fixup.c ---- linux.vanilla-2.6.16-rc4/arch/i386/pci/fixup.c 2006-02-20 11:22:15.000000000 +0000 -+++ linux-2.6.16-rc4/arch/i386/pci/fixup.c 2006-02-01 14:49:17.000000000 +0000 -@@ -74,52 +74,6 @@ - } - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); - --static void __devinit pci_fixup_ide_bases(struct pci_dev *d) --{ -- int i; -- -- /* -- * PCI IDE controllers use non-standard I/O port decoding, respect it. -- */ -- if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) -- return; -- DBG("PCI: IDE base address fixup for %s\n", pci_name(d)); -- for(i=0; i<4; i++) { -- struct resource *r = &d->resource[i]; -- if ((r->start & ~0x80) == 0x374) { -- r->start |= 2; -- r->end = r->start; -- } -- } --} --DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); -- --static void __devinit pci_fixup_ide_trash(struct pci_dev *d) --{ -- int i; -- -- /* -- * Runs the fixup only for the first IDE controller -- * (Shai Fultheim - shai@ftcon.com) -- */ -- static int called = 0; -- if (called) -- return; -- called = 1; -- -- /* -- * There exist PCI IDE controllers which have utter garbage -- * in first four base registers. Ignore that. -- */ -- DBG("PCI: IDE base address trash cleared for %s\n", pci_name(d)); -- for(i=0; i<4; i++) -- d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; --} --DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash); --DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_trash); --DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_trash); --DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_trash); -- - static void __devinit pci_fixup_latency(struct pci_dev *d) - { - /* -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/pci/probe.c linux-2.6.16-rc4/drivers/pci/probe.c ---- linux.vanilla-2.6.16-rc4/drivers/pci/probe.c 2006-02-20 11:22:17.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/pci/probe.c 2006-02-01 15:56:28.000000000 +0000 -@@ -627,6 +627,7 @@ - static int pci_setup_device(struct pci_dev * dev) - { - u32 class; -+ u16 cmd; - - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); -@@ -654,6 +655,31 @@ - pci_read_bases(dev, 6, PCI_ROM_ADDRESS); - pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); - pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); -+ -+ /* -+ * Do the ugly legacy mode stuff here rather than broken chip -+ * quirk code. Legacy mode ATA controllers have fixed -+ * addresses. These are not always echoed in BAR0-3, and -+ * BAR0-3 in a few cases contain junk! -+ */ -+ if (class == PCI_CLASS_STORAGE_IDE) { -+ u8 progif; -+ pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); -+ if ((progif & 5) != 5) { -+ dev->resource[0].start = 0x1F0; -+ dev->resource[0].end = 0x1F7; -+ dev->resource[0].flags = IORESOURCE_IO; -+ dev->resource[1].start = 0x3F6; -+ dev->resource[1].end = 0x3F6; -+ dev->resource[1].flags = IORESOURCE_IO; -+ dev->resource[2].start = 0x170; -+ dev->resource[2].end = 0x177; -+ dev->resource[2].flags = IORESOURCE_IO; -+ dev->resource[3].start = 0x376; -+ dev->resource[3].end = 0x376; -+ dev->resource[3].flags = IORESOURCE_IO; -+ } -+ } - break; - - case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/ata_generic.c linux-2.6.16-rc4/drivers/scsi/ata_generic.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/ata_generic.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/ata_generic.c 2006-02-16 15:35:41.000000000 +0000 -@@ -0,0 +1,241 @@ -+/* -+ * ata_generic.c - Generic PATA/SATA controller driver. -+ * Copyright 2005 Red Hat Inc <alan@redhat.com>, all rights reserved. -+ * -+ * Elements from ide/pci/generic.c -+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> -+ * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com> -+ * -+ * May be copied or modified under the terms of the GNU General Public License -+ * -+ * Driver for PCI IDE interfaces implementing the standard bus mastering -+ * interface functionality. This assumes the BIOS did the drive set up and -+ * tuning for us. By default we do not grab all IDE class devices as they -+ * may have other drivers or need fixups to avoid problems. Instead we keep -+ * a default list of stuff without documentation/driver that appears to -+ * work. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include "scsi.h" -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "generic" -+#define DRV_VERSION "0.1" -+ -+/* -+ * A generic parallel ATA driver using libata -+ */ -+ -+static void genpata_phy_reset(struct ata_port *ap) -+{ -+ /* We know the BIOS already did the mode work. Don't tempt any -+ one else to "fix" things */ -+ ap->cbl = ATA_CBL_PATA80; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * genpata_set_mode - mode setting -+ * @ap: interface to set up -+ * -+ * Use a non standard set_mode function. We don't want to be tuned. -+ * The BIOS configured everything. Our job is not to fiddle. We -+ * read the dma enabled bits from the PCI configuration of the device -+ * and respect them. -+ */ -+ -+static void genpata_set_mode(struct ata_port *ap) -+{ -+ int dma_enabled; -+ int i; -+ -+ /* Bits 5 and 6 indicate if DMA is active on master/slave */ -+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *dev = &ap->device[i]; -+ if (ata_dev_present(dev)) { -+ /* We don't really care */ -+ dev->pio_mode = XFER_PIO_0; -+ dev->dma_mode = XFER_MW_DMA_0; -+ /* We do need the right mode information for DMA or PIO -+ and this comes from the current configuration flags */ -+ /* FIXME: at some point in the future this should become -+ a library helper which reads the disk modes from the -+ disk as well */ -+ if (dma_enabled & (1 << (5 + i))) { -+ dev->xfer_mode = XFER_MW_DMA_0; -+ dev->xfer_shift = ATA_SHIFT_MWDMA; -+ dev->flags &= ~ATA_DFLAG_PIO; -+ } else { -+ dev->xfer_mode = XFER_PIO_0; -+ dev->xfer_shift = ATA_SHIFT_PIO; -+ dev->flags |= ATA_DFLAG_PIO; -+ } -+ } -+ } -+} -+ -+static struct scsi_host_template genpata_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations genpata_port_ops = { -+ .set_mode = genpata_set_mode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = genpata_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .data_xfer = ata_pio_data_xfer, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int ide_generic_all; /* Set to claim all devices */ -+ -+static int __init ide_generic_all_on(char *unused) -+{ -+ ide_generic_all = 1; -+ printk(KERN_INFO "ATA generic will claim all unknown PCI IDE class storage controllers.\n"); -+ return 1; -+} -+ -+__setup("all-generic-ide", ide_generic_all_on); -+ -+/** -+ * pata_generic_init - attach generic IDE -+ * @dev: PCI device found -+ * @id: match entry -+ * -+ * Called each time a matching IDE interface is found. We check if the -+ * interface is one we wish to claim and if so we perform any chip -+ * specific hacks then let the ATA layer do the heavy lifting. -+ */ -+ -+static int pata_generic_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ u16 command; -+ static struct ata_port_info info = { -+ .sht = &genpata_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_IRQ_MASK, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &genpata_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ /* Don't use the generic entry unless instructed to do so */ -+ if (id->driver_data == 1 && ide_generic_all == 0) -+ return -ENODEV; -+ -+ /* Devices that need care */ -+ if (dev->vendor == PCI_VENDOR_ID_UMC && -+ dev->device == PCI_DEVICE_ID_UMC_UM8886A && -+ (!(PCI_FUNC(dev->devfn) & 1))) -+ return -ENODEV; -+ -+ if (dev->vendor == PCI_VENDOR_ID_OPTI && -+ dev->device == PCI_DEVICE_ID_OPTI_82C558 && -+ (!(PCI_FUNC(dev->devfn) & 1))) -+ return -ENODEV; -+ -+ /* Don't re-enable devices in generic mode or we will break some -+ motherboards with disabled and unused IDE controllers */ -+ pci_read_config_word(dev, PCI_COMMAND, &command); -+ if (!(command & PCI_COMMAND_IO)) -+ return -ENODEV; -+ -+ if (dev->vendor == PCI_VENDOR_ID_AL) -+ ata_pci_clear_simplex(dev); -+ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id pata_generic[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, -+ /* Must come last. If you add entries adjust this table appropriately */ -+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, -+ { 0, }, -+}; -+ -+static struct pci_driver pata_generic_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = pata_generic, -+ .probe = pata_generic_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init pata_generic_init(void) -+{ -+ return pci_module_init(&pata_generic_pci_driver); -+} -+ -+ -+static void __exit pata_generic_exit(void) -+{ -+ pci_unregister_driver(&pata_generic_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for generic ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, pata_generic); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(pata_generic_init); -+module_exit(pata_generic_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/ata_piix.c linux-2.6.16-rc4/drivers/scsi/ata_piix.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/ata_piix.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/ata_piix.c 2006-02-20 20:06:17.000000000 +0000 -@@ -91,9 +91,10 @@ - #include <linux/device.h> - #include <scsi/scsi_host.h> - #include <linux/libata.h> -+#include <linux/ata.h> - - #define DRV_NAME "ata_piix" --#define DRV_VERSION "1.05" -+#define DRV_VERSION "1.05-ac7" - - enum { - PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ -@@ -122,6 +123,17 @@ - piix4_pata = 2, - ich6_sata = 3, - ich6_sata_ahci = 4, -+ ich0_pata = 5, -+ ich2_pata = 6, -+ ich3_pata = 7, -+ ich4_pata = 8, -+ cich_pata = 9, -+ piix3_pata = 10, -+ esb_pata = 11, -+ ich_pata = 12, -+ ich6_pata = 13, -+ ich7_pata = 14, -+ esb2_pata = 15, - - PIIX_AHCI_DEVICE = 6, - }; -@@ -130,20 +142,69 @@ - const struct pci_device_id *ent); - - static void piix_pata_phy_reset(struct ata_port *ap); -+static void ich_pata_phy_reset(struct ata_port *ap); - static void piix_sata_phy_reset(struct ata_port *ap); - static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); - static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); -+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); - - static unsigned int in_module_init = 1; - - static const struct pci_device_id piix_pci_tbl[] = { - #ifdef ATA_ENABLE_PATA -+#if 0 -+ /* Neptune and earlier are simple PIO */ -+ /* 430HX and friends. MWDMA */ -+ { 0x8086, 0x122e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix3_pata }, -+ { 0x8086, 0x1230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix3_pata }, -+ /* Intel PIIX3 */ -+ { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix3_pata }, -+#endif -+ /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ -+ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */ - { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, - { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, - { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, -+ /* Intel PIIX4 */ -+ { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, -+ /* Intel PIIX4 */ -+ { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, -+ /* Intel PIIX */ -+ { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, -+ /* Intel ICH (i810, i815, i840) UDMA 66*/ -+ { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata }, -+ /* Intel ICH0 : UDMA 33*/ -+ { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich0_pata }, -+ /* Intel ICH2M */ -+ { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich2_pata }, -+ /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */ -+ { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich2_pata }, -+ /* Intel ICH3M */ -+ { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich3_pata }, -+ /* Intel ICH3 (E7500/1) UDMA 100 */ -+ { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich3_pata }, -+#if 0 -+ { 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, dunno_pata }, -+#endif -+ /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */ -+ { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich4_pata }, -+ { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich4_pata }, -+ /* Intel ICH5 */ -+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, -+ /* C-ICH (i810E2) */ -+ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, cich_pata }, -+ /* ESB (855GME/875P + 6300ESB) UDMA 100 */ -+ { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_pata }, -+ /* ICH6 (and 6) (i915) UDMA 100 */ -+ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_pata }, -+ /* ICH7/7-R (i945, i975) UDMA 100*/ -+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_pata }, -+ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb2_pata }, - #endif -- -- /* NOTE: The following PCI ids must be kept in sync with the -+ /* -+ * SATA ports -+ * -+ * NOTE: The following PCI ids must be kept in sync with the - * list in drivers/pci/quirks.c. - */ - -@@ -213,6 +274,40 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations ich_pata_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = piix_set_piomode, -+ .set_dmamode = ich_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = ich_pata_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ -+ .data_xfer = ata_pio_data_xfer, - - .eng_timeout = ata_eng_timeout, - -@@ -242,6 +337,8 @@ - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - -+ .data_xfer = ata_pio_data_xfer, -+ - .eng_timeout = ata_eng_timeout, - - .irq_handler = ata_interrupt, -@@ -253,47 +350,39 @@ - }; - - static struct ata_port_info piix_port_info[] = { -- /* ich5_pata */ -+ /* ich5_pata: 0*/ - { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | - PIIX_FLAG_CHECKINTR, - .pio_mask = 0x1f, /* pio0-4 */ --#if 0 - .mwdma_mask = 0x06, /* mwdma1-2 */ --#else -- .mwdma_mask = 0x00, /* mwdma broken */ --#endif -- .udma_mask = 0x3f, /* udma0-5 */ -- .port_ops = &piix_pata_ops, -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &ich_pata_ops, - }, - -- /* ich5_sata */ -+ /* ich5_sata: 1 */ - { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | - PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ -- .udma_mask = 0x7f, /* udma0-6 */ -+ .udma_mask = ATA_UDMA6, - .port_ops = &piix_sata_ops, - }, - -- /* piix4_pata */ -+ /* piix4_pata: 2 */ - { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x1f, /* pio0-4 */ --#if 0 - .mwdma_mask = 0x06, /* mwdma1-2 */ --#else -- .mwdma_mask = 0x00, /* mwdma broken */ --#endif - .udma_mask = ATA_UDMA_MASK_40C, - .port_ops = &piix_pata_ops, - }, - -- /* ich6_sata */ -+ /* ich6_sata: 3 */ - { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | -@@ -301,11 +390,11 @@ - ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ -- .udma_mask = 0x7f, /* udma0-6 */ -+ .udma_mask = ATA_UDMA6, - .port_ops = &piix_sata_ops, - }, - -- /* ich6_sata_ahci */ -+ /* ich6_sata_ahci: 4 */ - { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | -@@ -313,9 +402,119 @@ - ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, - .pio_mask = 0x1f, /* pio0-4 */ - .mwdma_mask = 0x07, /* mwdma0-2 */ -- .udma_mask = 0x7f, /* udma0-6 */ -+ .udma_mask = ATA_UDMA6, - .port_ops = &piix_sata_ops, - }, -+ -+ /* ich0_pata: 5 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ -+ .udma_mask = ATA_UDMA4, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* ich2_pata: 6 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* ich3_pata: 7 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* ich4_pata: 8 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* cich_pata: 9 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* piix3_pata: 10 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma1-2 */ -+ .udma_mask = ATA_UDMA_MASK_40C, -+ .port_ops = &piix_pata_ops, -+ }, -+ -+ /* esb_pata: 11 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &piix_pata_ops, -+ }, -+ -+ /* ich_pata: 12 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA4, /* UDMA66 */ -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* ich6_pata: 13 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA6, /* UDMA133 */ -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* ich7_pata: 14 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &ich_pata_ops, -+ }, -+ -+ /* esb2_pata: 15 */ -+ { -+ .sht = &piix_sht, -+ .host_flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, /* pio 0-4 */ -+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &ich_pata_ops, -+ }, - }; - - static struct pci_bits piix_enable_bits[] = { -@@ -339,7 +538,7 @@ - * LOCKING: - * None (inherited from caller). - */ --static void piix_pata_cbl_detect(struct ata_port *ap) -+static void ich_pata_cbl_detect(struct ata_port *ap) - { - struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - u8 tmp, mask; -@@ -366,8 +565,9 @@ - * piix_pata_phy_reset - Probe specified port on PATA host controller - * @ap: Port to probe - * -- * Probe PATA phy. -- * -+ * Probe PATA phy. Unlike the ICH we have no IOCFG register and -+ * don't do UDMA66+ anyway. -+ - * LOCKING: - * None (inherited from caller). - */ -@@ -381,11 +581,34 @@ - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); - return; - } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} - -- piix_pata_cbl_detect(ap); - -- ata_port_probe(ap); -+/** -+ * ich_pata_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * Probe PATA phy. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void ich_pata_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - -+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ -+ ich_pata_cbl_detect(ap); -+ ata_port_probe(ap); - ata_bus_reset(ap); - } - -@@ -481,6 +704,13 @@ - unsigned int slave_port = 0x44; - u16 master_data; - u8 slave_data; -+ u8 udma_enable; -+ int control = 0; -+ -+ /* -+ * See Intel Document 298600-004 for the timing programing rules -+ * for ICH controllers. -+ */ - - static const /* ISP RTC */ - u8 timings[][2] = { { 0, 0 }, -@@ -489,20 +719,30 @@ - { 2, 1 }, - { 2, 3 }, }; - -+ if (pio > 2) -+ control |= 1; /* TIME1 enable */ -+ if (ata_pio_need_iordy(adev)) -+ control |= 2; /* IE enable */ -+ -+ /* Intel specifies that the PPE functionality is for disk only */ -+ if (adev->class == ATA_DEV_ATA) -+ control |= 4; /* PPE enable */ -+ - pci_read_config_word(dev, master_port, &master_data); - if (is_slave) { -+ /* Enable SITRE (seperate slave timing register) */ - master_data |= 0x4000; -- /* enable PPE, IE and TIME */ -- master_data |= 0x0070; -+ /* enable PPE1, IE1 and TIME1 as needed */ -+ master_data |= (control << 4); - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data &= (ap->hard_port_no ? 0x0f : 0xf0); -- slave_data |= -- (timings[pio][0] << 2) | -- (timings[pio][1] << (ap->hard_port_no ? 4 : 0)); -+ /* Load the timing nibble for this slave */ -+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->hard_port_no ? 4 : 0); - } else { -+ /* Master keeps the bits in a different format */ - master_data &= 0xccf8; -- /* enable PPE, IE and TIME */ -- master_data |= 0x0007; -+ /* Enable PPE, IE and TIME as appropriate */ -+ master_data |= control; - master_data |= - (timings[pio][0] << 12) | - (timings[pio][1] << 8); -@@ -510,84 +750,165 @@ - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); -+ -+ /* Ensure the UDMA bit is off - it will be turned back on if -+ UDMA is selected */ -+ -+ if (ap->udma_mask) { -+ pci_read_config_byte(dev, 0x48, &udma_enable); -+ udma_enable &= ~(1 << (2 * ap->hard_port_no + adev->devno)); -+ pci_write_config_byte(dev, 0x48, udma_enable); -+ } - } - - /** -- * piix_set_dmamode - Initialize host controller PATA PIO timings -+ * do_piix_set_dmamode - Initialize host controller PATA PIO timings - * @ap: Port whose timings we are configuring -- * @adev: um -- * @udma: udma mode, 0 - 6 -+ * @adev: device to configure -+ * @isich: True if the device is an ICH and has IOCFG registers - * -- * Set UDMA mode for device, in host controller PCI config space. -+ * Set MW/UDMA mode for device, in host controller PCI config space. -+ * Note: We know the caller has already set the PIO mode. In doing -+ * so it has correctly set PPE, SITRE, IORDY and TIME1. We rely on that. - * - * LOCKING: - * None (inherited from caller). - */ - --static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, int isich) - { -- unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ - struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -- u8 maslave = ap->hard_port_no ? 0x42 : 0x40; -- u8 speed = udma; -- unsigned int drive_dn = (ap->hard_port_no ? 2 : 0) + adev->devno; -- int a_speed = 3 << (drive_dn * 4); -- int u_flag = 1 << drive_dn; -- int v_flag = 0x01 << drive_dn; -- int w_flag = 0x10 << drive_dn; -- int u_speed = 0; -- int sitre; -- u16 reg4042, reg4a; -- u8 reg48, reg54, reg55; -- -- pci_read_config_word(dev, maslave, ®4042); -- DPRINTK("reg4042 = 0x%04x\n", reg4042); -- sitre = (reg4042 & 0x4000) ? 1 : 0; -- pci_read_config_byte(dev, 0x48, ®48); -- pci_read_config_word(dev, 0x4a, ®4a); -- pci_read_config_byte(dev, 0x54, ®54); -- pci_read_config_byte(dev, 0x55, ®55); -- -- switch(speed) { -- case XFER_UDMA_4: -- case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break; -- case XFER_UDMA_6: -- case XFER_UDMA_5: -- case XFER_UDMA_3: -- case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; -- case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; -- case XFER_MW_DMA_2: -- case XFER_MW_DMA_1: break; -- default: -- BUG(); -- return; -- } -+ u8 master_port = ap->hard_port_no ? 0x42 : 0x40; -+ u16 master_data; -+ u8 speed = adev->dma_mode; -+ int devid = adev->devno + 2 * ap->hard_port_no; -+ u8 udma_enable; -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; - -+ pci_read_config_word(dev, master_port, &master_data); -+ pci_read_config_byte(dev, 0x48, &udma_enable); -+ - if (speed >= XFER_UDMA_0) { -- if (!(reg48 & u_flag)) -- pci_write_config_byte(dev, 0x48, reg48 | u_flag); -- if (speed == XFER_UDMA_5) { -- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); -- } else { -- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); -+ unsigned int udma = adev->dma_mode - XFER_UDMA_0; -+ u16 udma_timing; -+ u16 ideconf; -+ int u_clock, u_speed; -+ -+ /* -+ * UDMA is handled by a combination of clock switching and -+ * selection of dividers -+ * -+ * Handy rule: Odd modes are UDMATIMx 01, even are 02 -+ * except UDMA0 which is 00 -+ */ -+ u_speed = min(2 - (udma & 1), udma); -+ if (udma == 5) -+ u_clock = 0x1000; /* 100Mhz */ -+ else if (udma > 2) -+ u_clock = 1; /* 66Mhz */ -+ else -+ u_clock = 0; /* 33Mhz */ -+ -+ udma_enable |= (1 << devid); -+ -+ /* Load the CT/RP selection */ -+ pci_read_config_word(dev, 0x4A, &udma_timing); -+ udma_timing &= ~(3 << (4 * devid)); -+ udma_timing |= u_speed << (4 * devid); -+ pci_write_config_word(dev, 0x4A, udma_timing); -+ -+ if (isich) { -+ /* Select a 33/66/100Mhz clock */ -+ pci_read_config_word(dev, 0x54, &ideconf); -+ ideconf &= ~(0x1001 << devid); -+ ideconf |= u_clock << devid; -+ /* For ICH or later we should set bit 10 for better -+ performance (WR_PingPong_En) */ -+ pci_write_config_word(dev, 0x54, ideconf); - } -- if ((reg4a & a_speed) != u_speed) -- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); -- if (speed > XFER_UDMA_2) { -- if (!(reg54 & v_flag)) -- pci_write_config_byte(dev, 0x54, reg54 | v_flag); -- } else -- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - } else { -- if (reg48 & u_flag) -- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); -- if (reg4a & a_speed) -- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); -- if (reg54 & v_flag) -- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); -- if (reg55 & w_flag) -- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); -+ /* -+ * MWDMA is driven by the PIO timings. We must also enable -+ * IORDY unconditionally along with TIME1. PPE has already -+ * been set when the PIO timing was set. -+ */ -+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; -+ unsigned int control; -+ u8 slave_data; -+ const unsigned int needed_pio[3] = { -+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 -+ }; -+ int pio = needed_pio[mwdma] - XFER_PIO_0; -+ -+ control = 3; /* IORDY|TIME1 */ -+ -+ /* If the drive MWDMA is faster than it can do PIO then -+ we must force PIO into PIO0 */ -+ -+ if (adev->pio_mode < needed_pio[mwdma]) -+ /* Enable DMA timing only */ -+ control |= 8; /* PIO cycles in PIO0 */ -+ -+ if (adev->devno) { /* Slave */ -+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ -+ master_data |= control << 4; -+ pci_read_config_byte(dev, 0x44, &slave_data); -+ slave_data &= (0x0F + 0xE1 * ap->hard_port_no); -+ /* Load the matching timing */ -+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->hard_port_no ? 4 : 0); -+ pci_write_config_byte(dev, 0x44, slave_data); -+ } else { /* Master */ -+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY -+ and master timing bits */ -+ master_data |= control; -+ master_data |= -+ (timings[pio][0] << 12) | -+ (timings[pio][1] << 8); -+ } -+ udma_enable &= ~(1 << devid); -+ pci_write_config_word(dev, master_port, master_data); - } -+ /* Don't scribble on 0x48 if the controller does not support UDMA */ -+ if (ap->udma_mask) -+ pci_write_config_byte(dev, 0x48, udma_enable); -+} -+ -+/** -+ * piix_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set MW/UDMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ do_pata_set_dmamode(ap, adev, 0); -+} -+ -+/** -+ * ich_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set MW/UDMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ do_pata_set_dmamode(ap, adev, 1); - } - - #define AHCI_PCI_BAR 5 -@@ -646,15 +967,15 @@ - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - pci_read_config_word(pdev, 0x41, &cfg); - /* Only on the original revision: IDE DMA can hang */ -- if(rev == 0x00) -+ if (rev == 0x00) - no_piix_dma = 1; - /* On all revisions below 5 PXB bus lock must be disabled for IDE */ -- else if(cfg & (1<<14) && rev < 5) -+ else if (cfg & (1<<14) && rev < 5) - no_piix_dma = 2; - } -- if(no_piix_dma) -+ if (no_piix_dma) - dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n"); -- if(no_piix_dma == 2) -+ if (no_piix_dma == 2) - dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n"); - return no_piix_dma; - } -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/Kconfig linux-2.6.16-rc4/drivers/scsi/Kconfig ---- linux.vanilla-2.6.16-rc4/drivers/scsi/Kconfig 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/Kconfig 2006-02-20 17:27:24.000000000 +0000 -@@ -599,6 +599,316 @@ - depends on IDE=y && !BLK_DEV_IDE_SATA && (SCSI_SATA_AHCI || SCSI_ATA_PIIX) - default y - -+config SCSI_PATA_ALI -+ tristate "ALi PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the ALi ATA interfaces -+ found on the many ALi chipsets. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_AMD -+ tristate "AMD/NVidia PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the AMD and NVidia PATA -+ interfaces found on the chipsets for Athlon/Athlon64. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_ARTOP -+ tristate "ARTOP 6210/6260 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for ARTOP PATA controllers. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_ATIIXP -+ tristate "ATI PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the ATI ATA interfaces -+ found on the many ATI chipsets. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_CMD64X -+ tristate "CMD64x PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the CMD64x series chips -+ except for the CMD640. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_CS5520 -+ tristate "CS5510/5520 PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the Cyrix 5510/5520 -+ companion chip used with the MediaGX/Geode processor family. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_CS5530 -+ tristate "CS5530 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the Cyrix/NatSemi/AMD CS5530 -+ companion chip used with the MediaGX/Geode processor family. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_CS5535 -+ tristate "CS5535 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && X86 && !X86_64 && EXPERIMENTAL -+ help -+ This option enables support for the NatSemi/AMD CS5535 -+ companion chip used with the Geode processor family. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_CYPRESS -+ tristate "Cypress CY82C693 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the Cypress/Contaq CY82C693 -+ chipset found in some Alpha systems -+ -+ If unsure, say N. -+ -+config SCSI_PATA_EFAR -+ tristate "EFAR SLC90E66 support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the EFAR SLC90E66 -+ IDE controller found on some older machines. -+ -+ If unsure, say N. -+ -+config SCSI_ATA_GENERIC -+ tristate "Generic PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for generic BIOS configured -+ PATA controllers via the new ATA layer -+ -+ If unsure, say N. -+ -+config SCSI_PATA_HPT37X -+ tristate "HPT 370/370A/371/372/374/302 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the majority of the later HPT -+ PATA controllers via the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_HPT3X2N -+ tristate "HPT 372N/302N PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the N variant HPT PATA -+ controllers via the new ATA layer -+ -+ If unsure, say N. -+ -+config SCSI_PATA_HPT3X3 -+ tristate "HPT 343/363 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the HPT 343/363 -+ PATA controllers via the new ATA layer -+ -+ If unsure, say N. -+ -+config SCSI_PATA_ISAPNP -+ tristate "ISA Plug and Play PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && EXPERIMENTAL -+ help -+ This option enables support for ISA plug & play ATA -+ controllers such as those found on old soundcards. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_IT8172 -+ tristate "IT8172 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the ITE 8172 PATA controller -+ via the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_IT821X -+ tristate "IT821x PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the ITE 8211 and 8212 -+ PATA controllers via the new ATA layer, including RAID -+ mode. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_LEGACY -+ tristate "Legacy ISA PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for ISA bus legacy PATA -+ interfaces on ide2-5 and allows them to be accessed via -+ the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_MPIIX -+ tristate "Intel PATA MPIIX support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for MPIIX PATA support. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_NETCELL -+ tristate "NETCELL Revolution RAID support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the Netcell Revolution RAID -+ PATA controller. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_NS87410 -+ tristate "Nat Semi NS87410 PATA support (Experimental)" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the National Semiconductor -+ NS87410 PCI-IDE controller. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_OLDPIIX -+ tristate "Intel PATA old PIIX support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for early PIIX PATA interfaces. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_OPTI -+ tristate "OPTI621/6215 PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables full PIO support for the early Opti ATA -+ controllers found on some old motherboards. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_PCMCIA -+ tristate "PCMCIA PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCMCIA -+ help -+ This option enables support for PCMCIA ATA interfaces, including -+ compact flash card adapters via the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_PDC_OLD -+ tristate "Older Promise PATA controller support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the Promise 20246, 20262, 20263, -+ 20265 and 20267 adapters. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_QDI -+ tristate "QDI VLB PATA support" -+ depends on SCSI_SATA -+ help -+ Support for QDI 6500 and 6580 PATA controllers on VESA local bus. -+ -+config SCSI_PATA_RADISYS -+ tristate "RADISYS 82600 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the RADISYS 82600 -+ PATA controllers via the new ATA layer -+ -+ If unsure, say N. -+ -+config SCSI_PATA_RZ1000 -+ tristate "PC Tech RZ1000 PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables basic support for the PC Tech RZ1000/1 -+ PATA controllers via the new ATA layer -+ -+ If unsure, say N. -+ -+config SCSI_PATA_SC1200 -+ tristate "SC1200 PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the NatSemi/AMD SC1200 SoC -+ companion chip used with the Geode processor family. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_SERVERWORKS -+ tristate "SERVERWORKS OSB4/CSB5/CSB6 PATA support (Experimental)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for the Serverworks OSB4/CSB5 and -+ CSB6 IDE controllers, via the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_SIL680 -+ tristate "CMD / Silicon Image 680 PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for CMD / Silicon Image 680 PATA. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_SIS -+ tristate "SiS PATA support (Experimental)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ This option enables support for SiS PATA controllers -+ -+ If unsure, say N. -+ -+config SCSI_PATA_TRIFLEX -+ tristate "Compaq Triflex PATA support (Raving Lunatic)" -+ depends on SCSI_SATA && PCI && EXPERIMENTAL -+ help -+ Enable support for the Compaq 'Triflex' IDE controller as found -+ on many Compaq Pentium-Pro systems, via the new ATA layer. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_VIA -+ tristate "VIA PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for the VIA PATA interfaces -+ found on the many VIA chipsets. -+ -+ If unsure, say N. -+ -+config SCSI_PATA_WINBOND -+ tristate "Winbond SL82C105 PATA support" -+ depends on SCSI_SATA && PCI -+ help -+ This option enables support for SL82C105 PATA devices found in the -+ Netwinder and some other systems -+ -+ If unsure, say N. -+ -+ - config SCSI_BUSLOGIC - tristate "BusLogic SCSI support" - depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/libata-core.c linux-2.6.16-rc4/drivers/scsi/libata-core.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/libata-core.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/libata-core.c 2006-02-23 13:37:47.358092040 +0000 -@@ -68,9 +68,10 @@ - static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); - static void ata_set_mode(struct ata_port *ap); - static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); --static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift); -+static unsigned int ata_get_mode_mask(const struct ata_port *ap, struct ata_device *adev, int shift); - static int fgb(u32 bitmap); - static int ata_choose_xfer_mode(const struct ata_port *ap, -+ struct ata_device *adev, - u8 *xfer_mode_out, - unsigned int *xfer_shift_out); - static void __ata_qc_complete(struct ata_queued_cmd *qc); -@@ -78,7 +79,7 @@ - static unsigned int ata_unique_id = 1; - static struct workqueue_struct *ata_wq; - --int atapi_enabled = 0; -+int atapi_enabled = 1; - module_param(atapi_enabled, int, 0444); - MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)"); - -@@ -1205,6 +1206,48 @@ - return 0; - } - -+static void ata_dev_check_hpa(struct ata_port *ap, struct ata_device *dev) -+{ -+ struct ata_taskfile tf; -+ unsigned long long true_size; -+ unsigned int err_mask; -+ -+ if (!ata_id_has_hpa(dev->id) || !ata_id_hpa_enabled(dev->id)) -+ return; -+ -+ /* Issue a query for HPA */ -+ ata_dev_select(ap, dev->devno, 1, 1); -+ ata_tf_init(ap, &tf, dev->devno); -+ -+ if (dev->flags & ATA_DFLAG_LBA48) { -+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; -+ tf.device |= 0x40; -+ err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0); -+ if (err_mask) -+ return; -+ /* Ok HPA is live */ -+ true_size = (tf.hob_lbah << 16) | (tf.hob_lbam << 8) | (tf.hob_lbal); -+ true_size <<= 24; -+ true_size |= (tf.lbah << 16) | (tf.lbam << 8) | tf.lbal; -+ } else { -+ tf.command = ATA_CMD_READ_NATIVE_MAX; -+ tf.device |= 0x40; -+ err_mask = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0); -+ if (err_mask) -+ return; -+ /* Ok HPA is live */ -+ true_size = ((tf.device & 0x0F) << 24) | -+ (tf.lbah << 16) | -+ (tf.lbam << 8) | -+ tf.lbal; -+ } -+ dev->flags |= ATA_DFLAG_HPA; -+ /* Should save the HPA value and expose it for dmraid then -+ remove the clipping */ -+ printk(KERN_INFO "HPA present: true size %lld sectors.\n", -+ true_size + 1); -+} -+ - /** - * ata_dev_identify - obtain IDENTIFY x DEVICE page - * @ap: port on which device we wish to probe resides -@@ -1328,7 +1371,7 @@ - - /* ATA-specific feature tests */ - if (dev->class == ATA_DEV_ATA) { -- if (!ata_id_is_ata(dev->id)) /* sanity check */ -+ if (!ata_id_is_ata(dev->id) && !ata_id_is_cfa(dev->id)) /* sanity check */ - goto err_out_nosup; - - /* get major version */ -@@ -1400,6 +1443,13 @@ - } - - ap->host->max_cmd_len = 16; -+ -+ /* -+ * See if we have the HPA misfeature on the drive -+ */ -+#if 0 /* TESTING */ -+ ata_dev_check_hpa(ap, dev); -+#endif - } - - /* ATAPI-specific feature tests */ -@@ -1485,10 +1535,24 @@ - ap->ops->phy_reset(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - goto err_out; -+ -+ /* The reset means we are in PIO 0, but the controller may not -+ yet be correctly set up and may have old BIOS settings, or just -+ no settings at all. Set all the devices to PIO 0 */ -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) -+ ap->device[i].pio_mode = XFER_PIO_0; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *adev = & ap->device[i]; -+ -+ /* Set up the controller on this port for PIO 0. We must not -+ send the drive speed setting commands at this point */ -+ if (ap->ops->set_piomode) -+ ap->ops->set_piomode(ap, adev); -+ - ata_dev_identify(ap, i); -- if (ata_dev_present(&ap->device[i])) { -+ if (ata_dev_present(adev)) { - found = 1; - ata_dev_config(ap,i); - } -@@ -1497,7 +1561,11 @@ - if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - goto err_out_disable; - -- ata_set_mode(ap); -+ if(ap->ops->set_mode) -+ ap->ops->set_mode(ap); -+ else -+ ata_set_mode(ap); -+ - if (ap->flags & ATA_FLAG_PORT_DISABLED) - goto err_out_disable; - -@@ -1612,6 +1680,23 @@ - } - - /** -+ * ata_dev_pair - return other device on cable -+ * @ap: port -+ * @adev: device -+ * -+ * Obtain the other device on the same cable, or if none is -+ * present NULL is returned -+ */ -+ -+struct ata_device *ata_dev_pair(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct ata_device *pair = &ap->device[1 - adev->devno]; -+ if (!ata_dev_present(pair)) -+ return NULL; -+ return pair; -+} -+ -+/** - * ata_port_disable - Disable port. - * @ap: Port to be disabled. - * -@@ -1824,16 +1909,19 @@ - ap->id, dev->devno, xfer_mode_str[idx]); - } - --static int ata_host_set_pio(struct ata_port *ap) -+static int ata_host_set_pio(struct ata_port *ap, struct ata_device *adev) - { - unsigned int mask; -- int x, i; -+ int x; - u8 base, xfer_mode; - -- mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); -+ if (!ata_dev_present(adev)) -+ return 0; -+ -+ mask = ata_get_mode_mask(ap, adev, ATA_SHIFT_PIO); - x = fgb(mask); - if (x < 0) { -- printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); -+ printk(KERN_WARNING "ata%u: no PIO support for device %d.\n", ap->id, adev->devno); - return -1; - } - -@@ -1843,34 +1931,24 @@ - DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", - (int)base, (int)xfer_mode, mask, x); - -- for (i = 0; i < ATA_MAX_DEVICES; i++) { -- struct ata_device *dev = &ap->device[i]; -- if (ata_dev_present(dev)) { -- dev->pio_mode = xfer_mode; -- dev->xfer_mode = xfer_mode; -- dev->xfer_shift = ATA_SHIFT_PIO; -- if (ap->ops->set_piomode) -- ap->ops->set_piomode(ap, dev); -- } -- } -+ adev->pio_mode = xfer_mode; -+ adev->xfer_mode = xfer_mode; -+ adev->xfer_shift = ATA_SHIFT_PIO; -+ if (ap->ops->set_piomode) -+ ap->ops->set_piomode(ap, adev); - - return 0; - } - --static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, -- unsigned int xfer_shift) -+static void ata_host_set_dma(struct ata_port *ap, struct ata_device *adev, -+ u8 xfer_mode, unsigned int xfer_shift) - { -- int i; -- -- for (i = 0; i < ATA_MAX_DEVICES; i++) { -- struct ata_device *dev = &ap->device[i]; -- if (ata_dev_present(dev)) { -- dev->dma_mode = xfer_mode; -- dev->xfer_mode = xfer_mode; -- dev->xfer_shift = xfer_shift; -- if (ap->ops->set_dmamode) -- ap->ops->set_dmamode(ap, dev); -- } -+ if (ata_dev_present(adev)) { -+ adev->dma_mode = xfer_mode; -+ adev->xfer_mode = xfer_mode; -+ adev->xfer_shift = xfer_shift; -+ if (ap->ops->set_dmamode) -+ ap->ops->set_dmamode(ap, adev); - } - } - -@@ -1886,32 +1964,64 @@ - */ - static void ata_set_mode(struct ata_port *ap) - { -- unsigned int xfer_shift; -- u8 xfer_mode; -+ unsigned int xfer_shift[ATA_MAX_DEVICES]; -+ u8 xfer_mode[ATA_MAX_DEVICES]; - int rc; -+ int i; -+ int used_dma = 0; /* Track if DMA was used for this setup */ - -- /* step 1: always set host PIO timings */ -- rc = ata_host_set_pio(ap); -- if (rc) -- goto err_out; -+ /* We need to set timings individually for each device */ - -- /* step 2: choose the best data xfer mode */ -- xfer_mode = xfer_shift = 0; -- rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); -- if (rc) -- goto err_out; -+ /* Compute the timings first so that when we ask the device to do -+ speed configuration it can see all the intended device state in -+ full */ -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *adev = &ap->device[i]; -+ /* Choose the best data xfer mode */ -+ xfer_mode[i] = xfer_shift[i] = 0; -+ rc = ata_choose_xfer_mode(ap, adev, &xfer_mode[i], &xfer_shift[i]); -+ if (rc) -+ goto err_out; -+ -+ } -+ -+ /* Now set the mode tables we have computed */ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *adev = &ap->device[i]; -+ /* step 1: always set host PIO timings */ -+ rc = ata_host_set_pio(ap, adev); -+ if (rc) -+ goto err_out; - -- /* step 3: if that xfer mode isn't PIO, set host DMA timings */ -- if (xfer_shift != ATA_SHIFT_PIO) -- ata_host_set_dma(ap, xfer_mode, xfer_shift); -- -- /* step 4: update devices' xfer mode */ -- ata_dev_set_mode(ap, &ap->device[0]); -- ata_dev_set_mode(ap, &ap->device[1]); -+ /* step 2: if that xfer mode isn't PIO, set host DMA timings */ -+ if (xfer_shift[i] != ATA_SHIFT_PIO) { -+ ata_host_set_dma(ap, adev, xfer_mode[i], xfer_shift[i]); -+ used_dma = 1; -+ } -+ -+ /* In some cases the DMA mode will cause the driver to -+ update the pio mode to match chip limits. */ -+ -+ /* step 3: update devices' xfer mode */ -+ ata_dev_set_mode(ap, adev); -+ } - - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; - -+ /* -+ * Record simplex status. If we selected DMA then the other -+ * host channels are not permitted to do so. -+ */ -+ -+ if (used_dma && (ap->host_set->host_set_flags & ATA_HOST_SIMPLEX)) -+ ap->host_set->simplex_claimed = 1; -+ -+ /* -+ * Chip specific finalisation -+ */ -+ - if (ap->ops->post_set_mode) - ap->ops->post_set_mode(ap); - -@@ -2200,132 +2310,126 @@ - } - - static const char * const ata_dma_blacklist [] = { -- "WDC AC11000H", -- "WDC AC22100H", -- "WDC AC32500H", -- "WDC AC33100H", -- "WDC AC31600H", -- "WDC AC32100H", -- "WDC AC23200L", -- "Compaq CRD-8241B", -- "CRD-8400B", -- "CRD-8480B", -- "CRD-8482B", -- "CRD-84", -- "SanDisk SDP3B", -- "SanDisk SDP3B-64", -- "SANYO CD-ROM CRD", -- "HITACHI CDR-8", -- "HITACHI CDR-8335", -- "HITACHI CDR-8435", -- "Toshiba CD-ROM XM-6202B", -- "TOSHIBA CD-ROM XM-1702BC", -- "CD-532E-A", -- "E-IDE CD-ROM CR-840", -- "CD-ROM Drive/F5A", -- "WPI CDD-820", -- "SAMSUNG CD-ROM SC-148C", -- "SAMSUNG CD-ROM SC", -- "SanDisk SDP3B-64", -- "ATAPI CD-ROM DRIVE 40X MAXIMUM", -- "_NEC DV5800A", -+ "WDC AC11000H", NULL, -+ "WDC AC22100H", NULL, -+ "WDC AC32500H", NULL, -+ "WDC AC33100H", NULL, -+ "WDC AC31600H", NULL, -+ "WDC AC32100H", "24.09P07", -+ "WDC AC23200L", "21.10N21", -+ "Compaq CRD-8241B", NULL, -+ "CRD-8400B", NULL, -+ "CRD-8480B", NULL, -+ "CRD-8482B", NULL, -+ "CRD-84", NULL, -+ "SanDisk SDP3B", NULL, -+ "SanDisk SDP3B-64", NULL, -+ "SANYO CD-ROM CRD", NULL, -+ "HITACHI CDR-8", NULL, -+ "HITACHI CDR-8335", NULL, -+ "HITACHI CDR-8435", NULL, -+ "Toshiba CD-ROM XM-6202B", NULL, -+ "TOSHIBA CD-ROM XM-1702BC", NULL, -+ "CD-532E-A", NULL, -+ "E-IDE CD-ROM CR-840", NULL, -+ "CD-ROM Drive/F5A", NULL, -+ "WPI CDD-820", NULL, -+ "SAMSUNG CD-ROM SC-148C", NULL, -+ "SAMSUNG CD-ROM SC", NULL, -+ "SanDisk SDP3B-64", NULL, -+ "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL, -+ "_NEC DV5800A", NULL, -+ "SAMSUNG CD-ROM SN-124", "N001" - }; - --static int ata_dma_blacklisted(const struct ata_device *dev) -+static int ata_strim(char *s, size_t len) - { -- unsigned char model_num[40]; -- char *s; -- unsigned int len; -- int i; -- -- ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS, -- sizeof(model_num)); -- s = &model_num[0]; -- len = strnlen(s, sizeof(model_num)); -+ len = strnlen(s, len); - - /* ATAPI specifies that empty space is blank-filled; remove blanks */ - while ((len > 0) && (s[len - 1] == ' ')) { - len--; - s[len] = 0; - } -+ return len; -+} - -- for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++) -- if (!strncmp(ata_dma_blacklist[i], s, len)) -- return 1; -+static int ata_dma_blacklisted(const struct ata_device *dev) -+{ -+ unsigned char model_num[40]; -+ unsigned char model_rev[16]; -+ unsigned int nlen, rlen; -+ int i; - -+ ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS, -+ sizeof(model_num)); -+ ata_dev_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS, -+ sizeof(model_rev)); -+ nlen = ata_strim(model_num, sizeof(model_num)); -+ rlen = ata_strim(model_rev, sizeof(model_rev)); -+ -+ for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) { -+ if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) { -+ if (ata_dma_blacklist[i+1] == NULL) -+ return 1; -+ if (!strncmp(ata_dma_blacklist[i], model_rev, rlen)) -+ return 1; -+ } -+ } - return 0; - } - --static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift) -+static unsigned int ata_get_mode_mask(const struct ata_port *ap, struct ata_device *adev, int shift) - { -- const struct ata_device *master, *slave; - unsigned int mask; -+ struct ata_host_set *hs = ap->host_set; -+ -+ if (!ata_dev_present(adev)) -+ return 0xFF; /* Drive isn't limiting anything */ -+ -+ if (shift == ATA_SHIFT_PIO) { -+ u16 tmp_mode = ata_pio_modes(adev); -+ mask = ap->pio_mask; -+ mask &= tmp_mode; -+ } - -- master = &ap->device[0]; -- slave = &ap->device[1]; -+ /* -+ * Enforce simplex rules if host is simplex -+ */ - -- assert (ata_dev_present(master) || ata_dev_present(slave)); -+ if (hs->host_set_flags & ATA_HOST_SIMPLEX) { -+ if (hs->simplex_claimed) { -+ if (shift != ATA_SHIFT_PIO) -+ return 0; -+ } -+ } - - if (shift == ATA_SHIFT_UDMA) { - mask = ap->udma_mask; -- if (ata_dev_present(master)) { -- mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); -- if (ata_dma_blacklisted(master)) { -- mask = 0; -- ata_pr_blacklisted(ap, master); -- } -- } -- if (ata_dev_present(slave)) { -- mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); -- if (ata_dma_blacklisted(slave)) { -- mask = 0; -- ata_pr_blacklisted(ap, slave); -- } -+ mask &= (adev->id[ATA_ID_UDMA_MODES] & 0xff); -+ if (ata_dma_blacklisted(adev)) { -+ mask = 0; -+ ata_pr_blacklisted(ap, adev); - } -+ /* 40 pin cable enforcement */ -+ if (ap->cbl == ATA_CBL_PATA40) -+ mask &= ~ATA_UDMA_MASK_40C; - } - else if (shift == ATA_SHIFT_MWDMA) { - mask = ap->mwdma_mask; -- if (ata_dev_present(master)) { -- mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); -- if (ata_dma_blacklisted(master)) { -- mask = 0; -- ata_pr_blacklisted(ap, master); -- } -- } -- if (ata_dev_present(slave)) { -- mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); -- if (ata_dma_blacklisted(slave)) { -- mask = 0; -- ata_pr_blacklisted(ap, slave); -- } -- } -- } -- else if (shift == ATA_SHIFT_PIO) { -- mask = ap->pio_mask; -- if (ata_dev_present(master)) { -- /* spec doesn't return explicit support for -- * PIO0-2, so we fake it -- */ -- u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; -- tmp_mode <<= 3; -- tmp_mode |= 0x7; -- mask &= tmp_mode; -- } -- if (ata_dev_present(slave)) { -- /* spec doesn't return explicit support for -- * PIO0-2, so we fake it -- */ -- u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; -- tmp_mode <<= 3; -- tmp_mode |= 0x7; -- mask &= tmp_mode; -+ mask &= (adev->id[ATA_ID_MWDMA_MODES] & 0x07); -+ if (ata_dma_blacklisted(adev)) { -+ mask = 0; -+ ata_pr_blacklisted(ap, adev); - } -- } -- else { -- mask = 0xffffffff; /* shut up compiler warning */ -- BUG(); -- } -- -+ } else if (shift != ATA_SHIFT_PIO) -+ panic("gmm:bad shift"); /* BUG confuses the compiler */ -+ /* -+ * Allow the controller to see the proposed mode and -+ * device data to do any custom filtering rules. -+ */ -+ if(ap->ops->mode_filter) -+ mask = ap->ops->mode_filter(ap, adev, mask, shift); - return mask; - } - -@@ -2345,6 +2449,7 @@ - /** - * ata_choose_xfer_mode - attempt to find best transfer mode - * @ap: Port for which an xfer mode will be selected -+ * @adev: ATA device for which xfer mode is being selected - * @xfer_mode_out: (output) SET FEATURES - XFER MODE code - * @xfer_shift_out: (output) bit shift that selects this mode - * -@@ -2359,6 +2464,7 @@ - */ - - static int ata_choose_xfer_mode(const struct ata_port *ap, -+ struct ata_device *adev, - u8 *xfer_mode_out, - unsigned int *xfer_shift_out) - { -@@ -2367,7 +2473,7 @@ - - for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { - shift = xfer_mode_classes[i].shift; -- mask = ata_get_mode_mask(ap, shift); -+ mask = ata_get_mode_mask(ap, adev, shift); - - x = fgb(mask); - if (x >= 0) { -@@ -3000,6 +3106,7 @@ - /** - * ata_mmio_data_xfer - Transfer data by MMIO - * @ap: port to read/write -+ * @adev: device to target - * @buf: data buffer - * @buflen: buffer length - * @write_data: read/write -@@ -3010,8 +3117,8 @@ - * Inherited from caller. - */ - --static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, -- unsigned int buflen, int write_data) -+void ata_mmio_data_xfer(struct ata_port *ap, struct ata_device *adev, -+ unsigned char *buf, unsigned int buflen, int write_data) - { - unsigned int i; - unsigned int words = buflen >> 1; -@@ -3045,6 +3152,7 @@ - /** - * ata_pio_data_xfer - Transfer data by PIO - * @ap: port to read/write -+ * @adev: device to target - * @buf: data buffer - * @buflen: buffer length - * @write_data: read/write -@@ -3055,11 +3163,11 @@ - * Inherited from caller. - */ - --static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, -- unsigned int buflen, int write_data) -+void ata_pio_data_xfer(struct ata_port *ap, struct ata_device *adev, -+ unsigned char *buf, unsigned int buflen, int write_data) - { - unsigned int words = buflen >> 1; -- -+ - /* Transfer multiple of 2 bytes */ - if (write_data) - outsw(ap->ioaddr.data_addr, buf, words); -@@ -3082,36 +3190,55 @@ - } - - /** -- * ata_data_xfer - Transfer data from/to the data register. -+ * ata_pio_data_xfer_noirq - Transfer data from/to the data register. - * @ap: port to read/write -+ * @adev: device to target - * @buf: data buffer - * @buflen: buffer length - * @do_write: read/write - * -- * Transfer data from/to the device data register. -+ * Transfer data from/to the device data register. This variant -+ * ensures local IRQs do not interrupt the data stream and this -+ * is needed for some controllers. - * - * LOCKING: - * Inherited from caller. - */ - --static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, -- unsigned int buflen, int do_write) -+void ata_pio_data_xfer_noirq(struct ata_port *ap, struct ata_device *adev, -+ unsigned char *buf, unsigned int buflen, int do_write) - { - /* Make the crap hardware pay the costs not the good stuff */ -- if (unlikely(ap->flags & ATA_FLAG_IRQ_MASK)) { -- unsigned long flags; -- local_irq_save(flags); -- if (ap->flags & ATA_FLAG_MMIO) -- ata_mmio_data_xfer(ap, buf, buflen, do_write); -- else -- ata_pio_data_xfer(ap, buf, buflen, do_write); -- local_irq_restore(flags); -- } else { -- if (ap->flags & ATA_FLAG_MMIO) -- ata_mmio_data_xfer(ap, buf, buflen, do_write); -- else -- ata_pio_data_xfer(ap, buf, buflen, do_write); -- } -+ unsigned long flags; -+ local_irq_save(flags); -+ ata_pio_data_xfer(ap, adev, buf, buflen, do_write); -+ local_irq_restore(flags); -+} -+ -+/** -+ * ata_mmio_data_xfer_noirq - Transfer data from/to the data register. -+ * @ap: address to read/write -+ * @adev: device to target -+ * @buf: data buffer -+ * @buflen: buffer length -+ * @do_write: read/write -+ * -+ * Transfer data from/to the device data register. This variant -+ * ensures local IRQs do not interrupt the data stream and this -+ * is needed for some controllers. -+ * -+ * LOCKING: -+ * Inherited from caller. -+ */ -+ -+void ata_mmio_data_xfer_noirq(struct ata_port *ap, struct ata_device *adev, -+ unsigned char *buf, unsigned int buflen, int do_write) -+{ -+ /* Make the crap hardware pay the costs not the good stuff */ -+ unsigned long flags; -+ local_irq_save(flags); -+ ata_mmio_data_xfer(ap, adev, buf, buflen, do_write); -+ local_irq_restore(flags); - } - - /** -@@ -3157,7 +3284,7 @@ - - /* do the actual data transfer */ - do_write = (qc->tf.flags & ATA_TFLAG_WRITE); -- ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); -+ ap->ops->data_xfer(ap, qc->dev, buf, ATA_SECT_SIZE, do_write); - - kunmap(page); - } -@@ -3204,7 +3331,7 @@ - ap->id, bytes); - - for (i = 0; i < words; i++) -- ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); -+ ap->ops->data_xfer(ap, qc->dev, (unsigned char*)pad_buf, 2, do_write); - - ap->hsm_task_state = HSM_ST_LAST; - return; -@@ -3239,7 +3366,7 @@ - DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - - /* do the actual data transfer */ -- ata_data_xfer(ap, buf, count, do_write); -+ ap->ops->data_xfer(ap, qc->dev, buf, count, do_write); - - kunmap(page); - -@@ -3948,14 +4075,15 @@ - - void ata_bmdma_irq_clear(struct ata_port *ap) - { -- if (ap->flags & ATA_FLAG_MMIO) { -- void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; -- writeb(readb(mmio), mmio); -- } else { -- unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; -- outb(inb(addr), addr); -- } -- -+ if (ap->ioaddr.bmdma_addr) { -+ if (ap->flags & ATA_FLAG_MMIO) { -+ void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; -+ writeb(readb(mmio), mmio); -+ } else { -+ unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; -+ outb(inb(addr), addr); -+ } -+ } - } - - -@@ -4194,12 +4322,12 @@ - */ - spin_lock_irqsave(&ap->host_set->lock, flags); - ap->flags &= ~ATA_FLAG_NOINTR; -- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); -+ ap->ops->data_xfer(ap, qc->dev, qc->cdb, ap->cdb_len, 1); - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) - ap->ops->bmdma_start(qc); /* initiate bmdma */ - spin_unlock_irqrestore(&ap->host_set->lock, flags); - } else { -- ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); -+ ap->ops->data_xfer(ap, qc->dev, qc->cdb, ap->cdb_len, 1); - - /* PIO commands are handled by polling */ - ap->hsm_task_state = HSM_ST; -@@ -4505,7 +4633,7 @@ - * Number of ports registered. Zero on error (no ports registered). - */ - --int ata_device_add(const struct ata_probe_ent *ent) -+int ata_device_add(struct ata_probe_ent *ent) - { - unsigned int count = 0, i; - struct device *dev = ent->dev; -@@ -4525,6 +4653,9 @@ - host_set->mmio_base = ent->mmio_base; - host_set->private_data = ent->private_data; - host_set->ops = ent->port_ops; -+ host_set->host_set_flags = ent->host_set_flags; -+ -+ ent->host_set = host_set; - - /* register each port bound to this device */ - for (i = 0; i < ent->n_ports; i++) { -@@ -4536,6 +4667,14 @@ - goto err_out; - - host_set->ports[i] = ap; -+ -+ /* Tidy up if we have no bus master base -+ Not sure this is the right spot to do it */ -+ if (ap->ioaddr.bmdma_addr == 0) { -+ ap->udma_mask = 0; -+ ap->mwdma_mask = 0; -+ } -+ - xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | - (ap->mwdma_mask << ATA_SHIFT_MWDMA) | - (ap->pio_mask << ATA_SHIFT_PIO); -@@ -4552,6 +4691,7 @@ - ent->irq); - - ata_chk_status(ap); -+ /* This last call probably should be conditional on bmdma */ - host_set->ops->irq_clear(ap); - count++; - } -@@ -4605,7 +4745,8 @@ - ata_scsi_scan_host(ap); - } - -- dev_set_drvdata(dev, host_set); -+ if(dev) -+ dev_set_drvdata(dev, host_set); - - VPRINTK("EXIT, returning %u\n", ent->n_ports); - return ent->n_ports; /* success */ -@@ -4779,6 +4920,7 @@ - { - struct ata_probe_ent *probe_ent = - ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); -+ unsigned long bmdma; - int p = 0; - - if (!probe_ent) -@@ -4793,7 +4935,13 @@ - probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; -- probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); -+ bmdma = pci_resource_start(pdev, 4); -+ -+ if (bmdma) { -+ if (inb(bmdma + 2) & 0x80) -+ probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; -+ probe_ent->port[p].bmdma_addr = bmdma; -+ } - ata_std_ports(&probe_ent->port[p]); - p++; - } -@@ -4803,7 +4951,14 @@ - probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; -- probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; -+ bmdma = pci_resource_start(pdev, 4); -+ -+ if (bmdma) { -+ bmdma += 8; -+ if(inb(bmdma + 2) & 0x80) -+ probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; -+ probe_ent->port[p].bmdma_addr = bmdma; -+ } - ata_std_ports(&probe_ent->port[p]); - p++; - } -@@ -4815,6 +4970,7 @@ - static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num) - { - struct ata_probe_ent *probe_ent; -+ unsigned long bmdma; - - probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); - if (!probe_ent) -@@ -4840,7 +4996,13 @@ - probe_ent->port[0].ctl_addr = 0x376; - break; - } -- probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num; -+ bmdma = pci_resource_start(pdev, 4); -+ if(bmdma != 0) { -+ bmdma += 8 * port_num; -+ probe_ent->port[0].bmdma_addr = bmdma; -+ if (inb(bmdma + 2) & 0x80) -+ probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; -+ } - ata_std_ports(&probe_ent->port[0]); - return probe_ent; - } -@@ -5081,6 +5243,33 @@ - pci_set_master(pdev); - return 0; - } -+ -+/** -+ * ata_pci_clear_simplex - attempt to kick device out of simplex -+ * @pdev: PCI device -+ * -+ * Some PCI ATA devices report simplex mode but in fact can be told to -+ * enter non simplex mode. This implements the neccessary logic to -+ * perform the task on such devices. Calling it on other devices will -+ * have -undefined- behaviour. -+ */ -+ -+int ata_pci_clear_simplex(struct pci_dev *pdev) -+{ -+ unsigned long bmdma = pci_resource_start(pdev, 4); -+ u8 simplex; -+ -+ if (bmdma == 0) -+ return -ENOENT; -+ -+ simplex = inb(bmdma + 0x02); -+ outb(simplex & 0x60, bmdma + 0x02); -+ simplex = inb(bmdma + 0x02); -+ if (simplex & 0x80) -+ return -EOPNOTSUPP; -+ return 0; -+} -+ - #endif /* CONFIG_PCI */ - - -@@ -5158,6 +5347,10 @@ - EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); - EXPORT_SYMBOL_GPL(ata_bmdma_status); - EXPORT_SYMBOL_GPL(ata_bmdma_stop); -+EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); -+EXPORT_SYMBOL_GPL(ata_pio_data_xfer); -+EXPORT_SYMBOL_GPL(ata_mmio_data_xfer_noirq); -+EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq); - EXPORT_SYMBOL_GPL(ata_port_probe); - EXPORT_SYMBOL_GPL(sata_phy_reset); - EXPORT_SYMBOL_GPL(__sata_phy_reset); -@@ -5175,6 +5368,7 @@ - EXPORT_SYMBOL_GPL(ata_dev_config); - EXPORT_SYMBOL_GPL(ata_scsi_simulate); - -+EXPORT_SYMBOL_GPL(ata_dev_pair); - EXPORT_SYMBOL_GPL(ata_pio_need_iordy); - EXPORT_SYMBOL_GPL(ata_timing_compute); - EXPORT_SYMBOL_GPL(ata_timing_merge); -@@ -5187,6 +5381,8 @@ - EXPORT_SYMBOL_GPL(ata_pci_remove_one); - EXPORT_SYMBOL_GPL(ata_pci_device_suspend); - EXPORT_SYMBOL_GPL(ata_pci_device_resume); -+EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); -+ - #endif /* CONFIG_PCI */ - - EXPORT_SYMBOL_GPL(ata_device_suspend); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/Makefile linux-2.6.16-rc4/drivers/scsi/Makefile ---- linux.vanilla-2.6.16-rc4/drivers/scsi/Makefile 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/Makefile 2006-02-17 18:20:44.000000000 +0000 -@@ -139,6 +139,42 @@ - obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o - obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o - -+obj-$(CONFIG_SCSI_PATA_ALI) += libata.o pata_ali.o -+obj-$(CONFIG_SCSI_PATA_AMD) += libata.o pata_amd.o -+obj-$(CONFIG_SCSI_PATA_ARTOP) += libata.o pata_artop.o -+obj-$(CONFIG_SCSI_PATA_ATIIXP) += libata.o pata_atiixp.o -+obj-$(CONFIG_SCSI_PATA_CMD64X) += libata.o pata_cmd64x.o -+obj-$(CONFIG_SCSI_PATA_CS5520) += libata.o pata_cs5520.o -+obj-$(CONFIG_SCSI_PATA_CS5530) += libata.o pata_cs5530.o -+obj-$(CONFIG_SCSI_PATA_CS5535) += libata.o pata_cs5535.o -+obj-$(CONFIG_SCSI_PATA_CYPRESS) += libata.o pata_cypress.o -+obj-$(CONFIG_SCSI_PATA_EFAR) += libata.o pata_efar.o -+obj-$(CONFIG_SCSI_PATA_ISAPNP) += libata.o pata_isapnp.o -+obj-$(CONFIG_SCSI_PATA_HPT37X) += libata.o pata_hpt37x.o -+obj-$(CONFIG_SCSI_PATA_HPT3X2N) += libata.o pata_hpt3x2n.o -+obj-$(CONFIG_SCSI_PATA_HPT3X3) += libata.o pata_hpt34x.o -+obj-$(CONFIG_SCSI_PATA_IT8172) += libata.o pata_it8172.o -+obj-$(CONFIG_SCSI_PATA_IT821X) += libata.o pata_it821x.o -+obj-$(CONFIG_SCSI_PATA_MPIIX) += libata.o pata_mpiix.o -+obj-$(CONFIG_SCSI_PATA_NETCELL) += libata.o pata_netcell.o -+obj-$(CONFIG_SCSI_PATA_NS87410) += libata.o pata_ns87410.o -+obj-$(CONFIG_SCSI_PATA_OLDPIIX) += libata.o pata_oldpiix.o -+obj-$(CONFIG_SCSI_PATA_OPTI) += libata.o pata_opti.o -+obj-$(CONFIG_SCSI_PATA_PCMCIA) += libata.o pata_pcmcia.o -+obj-$(CONFIG_SCSI_PATA_PDC_OLD) += libata.o pata_pdc202xx_old.o -+obj-$(CONFIG_SCSI_PATA_QDI) += libata.o pata_qdi.o -+obj-$(CONFIG_SCSI_PATA_RADISYS) += libata.o pata_radisys.o -+obj-$(CONFIG_SCSI_PATA_RZ1000) += libata.o pata_rz1000.o -+obj-$(CONFIG_SCSI_PATA_SERVERWORKS) += libata.o pata_serverworks.o -+obj-$(CONFIG_SCSI_PATA_SC1200) += libata.o pata_sc1200.o -+obj-$(CONFIG_SCSI_PATA_SIL680) += libata.o pata_sil680.o -+obj-$(CONFIG_SCSI_PATA_SIS) += libata.o pata_sis.o -+obj-$(CONFIG_SCSI_PATA_TRIFLEX) += libata.o pata_triflex.o -+obj-$(CONFIG_SCSI_PATA_VIA) += libata.o pata_via.o -+obj-$(CONFIG_SCSI_PATA_WINBOND) += libata.o pata_sl82c105.o -+obj-$(CONFIG_SCSI_ATA_GENERIC) += libata.o ata_generic.o -+obj-$(CONFIG_SCSI_PATA_LEGACY) += libata.o pata_legacy.o -+ - obj-$(CONFIG_ARM) += arm/ - - obj-$(CONFIG_CHR_DEV_ST) += st.o -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_ali.c linux-2.6.16-rc4/drivers/scsi/pata_ali.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_ali.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_ali.c 2006-02-20 12:28:04.000000000 +0000 -@@ -0,0 +1,606 @@ -+/* -+ * ata-ali.c - ALI 15x3 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * TODO -+ * MWDMA timings -+ * -+ * based in part upon -+ * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02 -+ * -+ * Copyright (C) 1998-2000 Michel Aubry, Maintainer -+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer -+ * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer -+ * -+ * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) -+ * May be copied or modified under the terms of the GNU General Public License -+ * Copyright (C) 2002 Alan Cox <alan@redhat.com> -+ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw> -+ * -+ * Documentation -+ * Chipset documentation available under NDA only -+ * -+ * TODO -+ * Cannot have ATAPI on both master & slave for rev < c2 but -+ * otherwise should do atapi DMA. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "ali" -+#define DRV_VERSION "0.2.2" -+ -+/** -+ * ali_c2_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection for C2 and later revisions -+ */ -+ -+static int ali_c2_cable_detect(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 ata66; -+ -+ /* Certain laptops use short but suitable cables and don't -+ implement the detect logic */ -+ -+ /* Fujitsu P2000 */ -+ if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF) -+ return ATA_CBL_PATA80; -+ -+ /* Host view cable detect 0x4A bit 0 primary bit 1 secondary -+ Bit set for 40 pin */ -+ pci_read_config_byte(pdev, 0x4A, &ata66); -+ if (ata66 & (1 << ap->hard_port_no)) -+ return ATA_CBL_PATA40; -+ else -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * ali_early_phy_reset - reset for eary chip -+ * @ap: ATA port -+ * -+ * Handle the reset callback for the later chips with cable detect -+ */ -+ -+static void ali_c2_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ali_c2_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * ali_early_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection for older chipsets. This turns out to be -+ * rather easy to implement -+ */ -+ -+static int ali_early_cable_detect(struct ata_port *ap) { -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * ali_early_phy_reset - reset for eary chip -+ * @ap: ATA port -+ * -+ * Handle the reset callback for the early (pre cable detect) chips. -+ */ -+ -+static void ali_early_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ali_early_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * ali_20_filter - filter for earlier ALI DMA -+ * @ap: ALi ATA port -+ * @adev: attached device -+ * -+ * Ensure that we do not do DMA on CD devices. We may be able to -+ * fix that later on. Also ensure we do not do UDMA on WDC drives -+ */ -+ -+static unsigned int ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ char model_num[40]; -+ /* No DMA on CD for now */ -+ if (adev->class != ATA_DEV_ATA && shift != ATA_SHIFT_PIO) -+ return 0; -+ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ -+ ata_dev_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); -+ if (strstr(model_num, "WDC")) -+ return 0; -+ return mask; -+} -+ -+/** -+ * ali_fifo_control - FIFO manager -+ * @ap: ALi channel to control -+ * @adev: device for FIFO control -+ * @on: 0 for off 1 for on -+ * -+ * Enable or disable the FIFO on a given device. Because of the way the -+ * ALi FIFO works it provides a boost on ATA disk but can be confused by -+ * ATAPI and we must therefore manage it. -+ */ -+ -+static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int on) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int pio_fifo = 0x54 + ap->hard_port_no; -+ u8 fifo; -+ int shift = 4 * adev->devno; -+ -+ /* Bits 3:2 (7:6 for slave) control the PIO. 00 is off 01 -+ is on. The FIFO must not be used for ATAPI. We preserve -+ BIOS set thresholds */ -+ pci_read_config_byte(pdev, pio_fifo, &fifo); -+ fifo &= ~(0x0C << shift); -+ if (on) -+ fifo |= (0x04 << shift); -+ pci_write_config_byte(pdev, pio_fifo, fifo); -+} -+ -+/** -+ * ali_program_modes - load mode registers -+ * @ap: ALi channel to load -+ * @adev: Device the timing is for -+ * @cmd: Command timing -+ * @data: Data timing -+ * @udma: UDMA timing or zero for off -+ * -+ * Loads the timing registers for cmd/data and disable UDMA if -+ * udma is zero. If udma is set then load and enable the UDMA -+ * timing but do not touch the command/data timing. -+ */ -+ -+static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, u8 cmd, u8 data, u8 ultra) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int cbt = 0x59 + 4 * ap->hard_port_no; /* Command timing */ -+ int drwt = 0x5A + 4 * ap->hard_port_no + adev->devno; /* R/W timing */ -+ int udmat = 0x56 + ap->hard_port_no; /* UDMA timing */ -+ int shift = 4 * adev->devno; -+ u8 udma; -+ -+ if (ultra == 0) { -+ /* FIXME: We ought to set up pcas not rely on the BIOS */ -+ /* Load the command block timing register */ -+ pci_write_config_byte(pdev, cbt, cmd); -+ -+ /* Load the data transfer timing register */ -+ pci_write_config_byte(pdev, drwt, data); -+ } -+ -+ /* Set up the UDMA enable */ -+ pci_read_config_byte(pdev, udmat, &udma); -+ udma &= ~(0x0F << shift); -+ udma |= ultra << shift; -+ pci_write_config_byte(pdev, udmat, udma); -+} -+ -+/** -+ * ali_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the ALi registers for PIO mode. FIXME: add timings for -+ * PIO5. -+ */ -+ -+static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ int pio = adev->pio_mode - XFER_PIO_0; -+ int cmdpio = pio; -+ -+ /* These values are from the BIOS programming guide */ -+ static u8 cmd_block_timing[5] = { 0x0A, 0x03, 0x01, 0x33, 0x31 }; -+ static u8 data_block_timing[5] = { 0x88, 0x58, 0x44, 0x33, 0x31 }; -+ -+ if (adev->class != ATA_DEV_ATA) -+ ali_fifo_control(ap, adev, 0); -+ -+ /* Command timing is shared, so pick the best we can use */ -+ if (pair) -+ cmdpio = min(pair->pio_mode, adev->pio_mode) - XFER_PIO_0; -+ -+ ali_program_modes(ap, adev, cmd_block_timing[cmdpio], -+ data_block_timing[pio], 0); -+ -+ if (adev->class == ATA_DEV_ATA) -+ ali_fifo_control(ap, adev, 1); -+ -+} -+ -+/** -+ * ali_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * FIXME: MWDMA timings -+ */ -+ -+static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD }; -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ ali_program_modes(ap, adev, 0, 0, udma_timing[adev->dma_mode - XFER_UDMA_0]); -+ } else { -+ /* MWDMA is not yet supported */ -+ /* ali_program_modes(ap, adev, cmd, data, 0); */ -+ } -+} -+ -+/** -+ * ali_lock_sectors - Keep older devices to 255 sector mode -+ * @ap: ATA port -+ * @adev: Device -+ * -+ * Called during the bus probe for each device that is found. We use -+ * this call to lock the sector count of the device to 255 or less on -+ * older ALi controllers. If we didn't do this then large I/O's would -+ * require LBA48 commands which the older ALi requires are issued by -+ * slower PIO methods -+ */ -+ -+static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev) -+{ -+ if(ap->host->max_sectors > 255) { -+ ap->host->max_sectors = 255; -+ ap->host->hostt->max_sectors = 255; -+ } -+ adev->flags |= ATA_DFLAG_LOCK_SECTORS; -+} -+ -+static struct scsi_host_template ali_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO -+ with older controllers. Not locked so will grow on C5 or later */ -+ .max_sectors = 255, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+/* -+ * Port operations for PIO only ALi -+ */ -+ -+static struct ata_port_operations ali_early_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = ali_set_piomode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = ali_early_phy_reset, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Port operations for DMA capable ALi without cable -+ * detect -+ */ -+static struct ata_port_operations ali_20_port_ops = { -+ .port_disable = ata_port_disable, -+ -+ .set_piomode = ali_set_piomode, -+ .set_dmamode = ali_set_dmamode, -+ .mode_filter = ali_20_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ .dev_config = ali_lock_sectors, -+ -+ .phy_reset = ali_early_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Port operations for DMA capable ALi with cable detect -+ */ -+static struct ata_port_operations ali_c2_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = ali_set_piomode, -+ .set_dmamode = ali_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ .dev_config = ali_lock_sectors, -+ -+ .phy_reset = ali_c2_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Port operations for DMA capable ALi with cable detect and LBA48 -+ */ -+static struct ata_port_operations ali_c5_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = ali_set_piomode, -+ .set_dmamode = ali_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = ali_c2_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * ali_init_one - discovery callback -+ * @pdev: PCI device ID -+ * @id: PCI table info -+ * -+ * An ALi IDE interface has been discovered. Figure out what revision -+ * and perform configuration work before handing it to the ATA layer -+ */ -+ -+static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info_early = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .port_ops = &ali_early_port_ops -+ }; -+ /* Revision 0x20 added DMA */ -+ static struct ata_port_info info_20 = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &ali_20_port_ops -+ }; -+ /* Revision 0x20 with support logic added UDMA */ -+ static struct ata_port_info info_20_udma = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x07, /* UDMA33 */ -+ .port_ops = &ali_20_port_ops -+ }; -+ /* Revision 0xC2 adds UDMA66 */ -+ static struct ata_port_info info_c2 = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, -+ .port_ops = &ali_c2_port_ops -+ }; -+ /* Revision 0xC3 is UDMA100 */ -+ static struct ata_port_info info_c3 = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &ali_c2_port_ops -+ }; -+ /* Revision 0xC4 is UDMA133 */ -+ static struct ata_port_info info_c4 = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &ali_c2_port_ops -+ }; -+ /* Revision 0xC5 is UDMA133 with LBA48 DMA */ -+ static struct ata_port_info info_c5 = { -+ .sht = &ali_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &ali_c5_port_ops -+ }; -+ -+ static struct ata_port_info *port_info[2]; -+ u8 rev, tmp; -+ struct pci_dev *north, *isa_bridge; -+ -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); -+ -+ /* -+ * The chipset revision selects the driver operations and -+ * mode data. -+ */ -+ -+ if (rev < 0x20) { -+ port_info[0] = port_info[1] = &info_early; -+ } else if (rev < 0xC2) { -+ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ -+ pci_read_config_byte(pdev, 0x4B, &tmp); -+ /* Clear CD-ROM DMA write bit */ -+ tmp &= 0x7F; -+ pci_write_config_byte(pdev, 0x4B, tmp); -+ port_info[0] = port_info[1] = &info_20; -+ } else if (rev == 0xC2) { -+ port_info[0] = port_info[1] = &info_c2; -+ } else if (rev == 0xC3) { -+ port_info[0] = port_info[1] = &info_c3; -+ } else if (rev == 0xC4) { -+ port_info[0] = port_info[1] = &info_c4; -+ } else -+ port_info[0] = port_info[1] = &info_c5; -+ -+ if (rev >= 0xC2) { -+ /* Enable cable detection logic */ -+ pci_read_config_byte(pdev, 0x4B, &tmp); -+ pci_write_config_byte(pdev, 0x4B, tmp | 0x08); -+ } -+ -+ north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); -+ isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); -+ -+ if (north && north->vendor == PCI_VENDOR_ID_AL) { -+ /* Configure the ALi bridge logic. For non ALi rely on BIOS. -+ Set the south bridge enable bit */ -+ pci_read_config_byte(isa_bridge, 0x79, &tmp); -+ if (rev == 0xC2) -+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); -+ else if (rev > 0xC2) -+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); -+ } -+ -+ if (rev >= 0x20) { -+ if (rev < 0xC2) { -+ /* Are we paired with a UDMA capable chip */ -+ pci_read_config_byte(isa_bridge, 0x5E, &tmp); -+ if ((tmp & 0x1E) == 0x12) -+ port_info[0] = port_info[1] = &info_20_udma; -+ } -+ /* -+ * CD_ROM DMA on (0x53 bit 0). Enable this even if we want -+ * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control -+ * via 0x54/55. -+ */ -+ pci_read_config_byte(pdev, 0x53, &tmp); -+ if (rev == 0x20) -+ tmp &= ~0x02; -+ tmp |= 0x01; -+ pci_write_config_byte(pdev, 0x53, tmp); -+ } -+ -+ pci_dev_put(isa_bridge); -+ pci_dev_put(north); -+ -+ ata_pci_clear_simplex(pdev); -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static struct pci_device_id ali[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), }, -+ { 0, }, -+}; -+ -+static struct pci_driver ali_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = ali, -+ .probe = ali_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init ali_init(void) -+{ -+ return pci_register_driver(&ali_pci_driver); -+} -+ -+ -+static void __exit ali_exit(void) -+{ -+ pci_unregister_driver(&ali_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for ALi PATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, ali); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(ali_init); -+module_exit(ali_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_amd.c linux-2.6.16-rc4/drivers/scsi/pata_amd.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_amd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_amd.c 2006-02-16 15:37:39.000000000 +0000 -@@ -0,0 +1,650 @@ -+/* -+ * pata_amd.c - AMD PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based on pata-sil680. Errata information is taken from data sheets -+ * and the amd74xx.c driver by Vojtech Pavlik. Nvidia SATA devices are -+ * claimed by sata-nv.c. -+ * -+ * TODO: -+ * Nvidia support here or seperated ? -+ * Debug cable detect -+ * Variable system clock when/if it makes sense -+ * Power management on ports -+ * -+ * -+ * Documentation publically available. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_amd" -+#define DRV_VERSION "0.1.3" -+ -+/** -+ * timing_setup - shared timing computation and load -+ * @ap: ATA port being set up -+ * @adev: drive being configured -+ * @offset: port offset -+ * @speed: target speed -+ * @clock: clock multiplier (number of times 33MHz for this part) -+ * -+ * Perform the actual timing set up for Nvidia or AMD PATA devices. -+ * The actual devices vary so they all call into this helper function -+ * providing the clock multipler and offset (because AMD and Nvidia put -+ * the ports at different locations). -+ */ -+ -+static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offset, int speed, int clock) -+{ -+ static const unsigned char amd_cyc2udma[] = { -+ 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 -+ }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct ata_device *peer = ata_dev_pair(ap, adev); -+ int dn = ap->hard_port_no * 2 + adev->devno; -+ struct ata_timing at, apeer; -+ int T, UT; -+ const int amd_clock = 33333; /* KHz. */ -+ u8 t; -+ -+ T = 1000000000 / amd_clock; -+ UT = T / min_t(int, max_t(int, clock, 1), 2); -+ -+ if (ata_timing_compute(adev, speed, &at, T, UT) < 0) { -+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed); -+ return; -+ } -+ -+ if (peer) { -+ /* This may be over conservative */ -+ if (peer->dma_mode) { -+ ata_timing_compute(peer, peer->dma_mode, &apeer, T, UT); -+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT); -+ } -+ ata_timing_compute(peer, peer->pio_mode, &apeer, T, UT); -+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT); -+ } -+ -+ if (speed == XFER_UDMA_5 && amd_clock <= 33333) at.udma = 1; -+ if (speed == XFER_UDMA_6 && amd_clock <= 33333) at.udma = 15; -+ -+ /* -+ * Now do the setup work -+ */ -+ -+ /* Configure the address set up timing */ -+ pci_read_config_byte(pdev, offset + 0x0C, &t); -+ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1)); -+ pci_write_config_byte(pdev, offset + 0x0C , t); -+ -+ /* Configure the 8bit I/O timing */ -+ pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)), -+ ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1)); -+ -+ /* Drive timing */ -+ pci_write_config_byte(pdev, offset + 0x08 + (3 - dn), -+ ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1)); -+ -+ switch (clock) { -+ case 1: -+ t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03; -+ break; -+ -+ case 2: -+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03; -+ break; -+ -+ case 3: -+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03; -+ break; -+ -+ case 4: -+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03; -+ break; -+ -+ default: -+ return; -+ } -+ -+ /* UDMA timing */ -+ pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t); -+} -+ -+/** -+ * amd_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection. The BIOS stores this in PCI config -+ * space for us. -+ */ -+ -+static int amd_cable_detect(struct ata_port *ap) { -+ static u32 bitmask[2] = {0x00030000, 0x00C00000}; -+ u32 ata66; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_dword(pdev, 0x42, &ata66); -+ if (ata66 & bitmask[ap->hard_port_no]) -+ return ATA_CBL_PATA80; -+ else -+ return ATA_CBL_PATA40; -+ -+} -+ -+static void amd_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits amd_enable_bits[] = { -+ { 0x40, 1, 0x02, 0x02 }, -+ { 0x40, 1, 0x01, 0x01 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = amd_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * amd33_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the AMD registers for PIO mode. -+ */ -+ -+static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->pio_mode, 1); -+} -+ -+static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->pio_mode, 2); -+} -+ -+static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->pio_mode, 3); -+} -+ -+static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->pio_mode, 4); -+} -+ -+/** -+ * amd33_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the MWDMA/UDMA modes for the AMD and Nvidia -+ * chipset. -+ */ -+ -+static void amd33_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->dma_mode, 1); -+} -+ -+static void amd66_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->dma_mode, 2); -+} -+ -+static void amd100_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->dma_mode, 3); -+} -+ -+static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x40, adev->dma_mode, 4); -+} -+ -+ -+/** -+ * nv_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection. The BIOS stores this in PCI config -+ * space for us. -+ */ -+ -+static int nv_cable_detect(struct ata_port *ap) { -+ static u32 bitmask[2] = {0x00030000, 0x00C00000}; -+ u32 ata66; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_dword(pdev, 0x52, &ata66); -+ if (ata66 & bitmask[ap->hard_port_no]) -+ return ATA_CBL_PATA80; -+ else -+ return ATA_CBL_PATA40; -+ -+} -+ -+static void nv_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = nv_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * nv100_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the AMD registers for PIO mode. -+ */ -+ -+static void nv100_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x50, adev->pio_mode, 3); -+} -+ -+static void nv133_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x50, adev->pio_mode, 4); -+} -+ -+/** -+ * nv100_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the MWDMA/UDMA modes for the AMD and Nvidia -+ * chipset. -+ */ -+ -+static void nv100_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x50, adev->dma_mode, 3); -+} -+ -+static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ timing_setup(ap, adev, 0x50, adev->dma_mode, 4); -+} -+ -+static struct scsi_host_template amd_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations amd33_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = amd33_set_piomode, -+ .set_dmamode = amd33_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = amd_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations amd66_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = amd66_set_piomode, -+ .set_dmamode = amd66_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = amd_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations amd100_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = amd100_set_piomode, -+ .set_dmamode = amd100_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = amd_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations amd133_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = amd133_set_piomode, -+ .set_dmamode = amd133_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = amd_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations nv100_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = nv100_set_piomode, -+ .set_dmamode = nv100_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = nv_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations nv133_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = nv133_set_piomode, -+ .set_dmamode = nv133_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = nv_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info[10] = { -+ { /* 0: AMD 7401 */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, /* No SWDMA */ -+ .udma_mask = 0x07, /* UDMA 33 */ -+ .port_ops = &amd33_port_ops -+ }, -+ { /* 1: Early AMD7409 - no swdma */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, /* UDMA 66 */ -+ .port_ops = &amd66_port_ops -+ }, -+ { /* 2: AMD 7409, no swdma errata */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, /* UDMA 66 */ -+ .port_ops = &amd66_port_ops -+ }, -+ { /* 3: AMD 7411 */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* UDMA 100 */ -+ .port_ops = &amd100_port_ops -+ }, -+ { /* 4: AMD 7441 */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* UDMA 100 */ -+ .port_ops = &amd100_port_ops -+ }, -+ { /* 5: AMD 8111*/ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, /* UDMA 133, no swdma */ -+ .port_ops = &amd133_port_ops -+ }, -+ { /* 6: AMD 8111 UDMA 100 (Serenade) */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* UDMA 100, no swdma */ -+ .port_ops = &amd133_port_ops -+ }, -+ { /* 7: Nvidia Nforce */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* UDMA 100 */ -+ .port_ops = &nv100_port_ops -+ }, -+ { /* 8: Nvidia Nforce2 and later */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, /* UDMA 133, no swdma */ -+ .port_ops = &nv133_port_ops -+ }, -+ { /* 9: AMD CS5536 (Geode companion) */ -+ .sht = &amd_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* UDMA 100 */ -+ .port_ops = &amd100_port_ops -+ } -+ }; -+ static struct ata_port_info *port_info[2]; -+ static int printed_version; -+ int type = id->driver_data; -+ u8 rev; -+ u8 fifo; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); -+ -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); -+ pci_read_config_byte(pdev, 0x41, &fifo); -+ -+ /* Check for AMD7409 without swdma errata and if found adjust type */ -+ if (type == 1 && rev > 0x7) -+ type = 2; -+ -+ /* Check for AMD7411 */ -+ if (type == 3) -+ /* FIFO is broken */ -+ pci_write_config_byte(pdev, 0x41, fifo & 0x0F); -+ else -+ pci_write_config_byte(pdev, 0x41, fifo | 0xF0); -+ -+ /* Serenade ? */ -+ if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD && -+ pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) -+ type = 6; /* UDMA 100 only */ -+ -+ if (type < 3) -+ ata_pci_clear_simplex(pdev); -+ -+ /* And fire it up */ -+ -+ port_info[0] = port_info[1] = &info[type]; -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id amd[] = { -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, -+ { 0, }, -+}; -+ -+static struct pci_driver amd_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = amd, -+ .probe = amd_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init amd_init(void) -+{ -+ return pci_register_driver(&amd_pci_driver); -+} -+ -+static void __exit amd_exit(void) -+{ -+ pci_unregister_driver(&amd_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for AMD PATA IDE"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, amd); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(amd_init); -+module_exit(amd_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_artop.c linux-2.6.16-rc4/drivers/scsi/pata_artop.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_artop.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_artop.c 2006-02-07 13:41:48.000000000 +0000 -@@ -0,0 +1,497 @@ -+/* -+ * pata_artop.c - ARTOP ATA controller driver -+ * -+ * (C) 2006 Red Hat <alan@redhat.com> -+ * -+ * Based in part on drivers/ide/pci/aec62xx.c -+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> -+ * 865/865R fixes for Macintosh card version from a patch to the old -+ * driver by Thibaut VARENE <varenet@parisc-linux.org> -+ * -+ * TODO -+ * 850 serialization once the core supports it -+ * Investigate no_dsc on 850R -+ * Clock detect -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_artop" -+#define DRV_VERSION "0.2" -+ -+/* -+ * The ARTOP has 33 Mhz and "over clocked" timing tables. Until we -+ * get PCI bus speed functionality we leave this as 0. Its a variable -+ * for when we get the functionality and also for folks wanting to -+ * test stuff. -+ */ -+ -+static int clock = 0; -+ -+/** -+ * artop6210_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6210_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ const struct pci_bits artop_enable_bits[] = { -+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ -+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * artop6260_cable_detect - check for 40/80 pin -+ * @ap: Port -+ * -+ * The ARTOP hardware reports the cable detect bits in register 0x49. -+ * Nothing complicated needed here. -+ */ -+ -+static int artop6260_cable_detect(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 tmp; -+ -+ pci_read_config_byte(pdev, 0x49, &tmp); -+ if (tmp & (1 >> ap->hard_port_no)) -+ return ATA_CBL_PATA40; -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * artop6260_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6260_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ const struct pci_bits artop_enable_bits[] = { -+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */ -+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */ -+ }; -+ -+ /* Odd numbered device ids are the units with enable bits (the -R cards) */ -+ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = artop6260_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * artop6210_load_piomode - Load a set of PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device -+ * @pio: PIO mode -+ * -+ * Set PIO mode for device, in host controller PCI config space. This -+ * is used both to set PIO timings in PIO mode and also to set the -+ * matching PIO clocking for UDMA, as well as the MWDMA timings. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6210_load_piomode(struct ata_port *ap, struct ata_device *adev, unsigned int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = adev->devno + 2 * ap->hard_port_no; -+ const u16 timing[2][5] = { -+ { 0x0000, 0x000A, 0x0008, 0x0303, 0x0301 }, -+ { 0x0700, 0x070A, 0x0708, 0x0403, 0x0401 } -+ -+ }; -+ /* Load the PIO timing active/recovery bits */ -+ pci_write_config_word(pdev, 0x40 + 2 * dn, timing[clock][pio]); -+} -+ -+/** -+ * artop6210_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring -+ * -+ * Set PIO mode for device, in host controller PCI config space. For -+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In -+ * the event UDMA is used the later call to set_dmamode will set the -+ * bits as required. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6210_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = adev->devno + 2 * ap->hard_port_no; -+ u8 ultra; -+ -+ artop6210_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); -+ -+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */ -+ pci_read_config_byte(pdev, 0x54, &ultra); -+ ultra &= ~(3 << (2 * dn)); -+ pci_write_config_byte(pdev, 0x54, ultra); -+} -+ -+/** -+ * artop6260_load_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring -+ * @pio: PIO mode -+ * -+ * Set PIO mode for device, in host controller PCI config space. The -+ * ARTOP6260 and relatives store the timing data differently. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6260_load_piomode (struct ata_port *ap, struct ata_device *adev, unsigned int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = adev->devno + 2 * ap->hard_port_no; -+ const u8 timing[2][5] = { -+ { 0x00, 0x0A, 0x08, 0x33, 0x31 }, -+ { 0x70, 0x7A, 0x78, 0x43, 0x41 } -+ -+ }; -+ /* Load the PIO timing active/recovery bits */ -+ pci_write_config_byte(pdev, 0x40 + dn, timing[clock][pio]); -+} -+ -+/** -+ * artop6260_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring -+ * -+ * Set PIO mode for device, in host controller PCI config space. For -+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In -+ * the event UDMA is used the later call to set_dmamode will set the -+ * bits as required. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 ultra; -+ -+ artop6260_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); -+ -+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */ -+ pci_read_config_byte(pdev, 0x44 + ap->hard_port_no, &ultra); -+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */ -+ pci_write_config_byte(pdev, 0x44 + ap->hard_port_no, ultra); -+} -+ -+/** -+ * artop6210_set_dmamode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set DMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6210_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = adev->devno + 2 * ap->hard_port_no; -+ u8 ultra; -+ -+ if (adev->dma_mode == XFER_MW_DMA_0) -+ pio = 1; -+ else -+ pio = 4; -+ -+ /* Load the PIO timing active/recovery bits */ -+ artop6210_load_piomode(ap, adev, pio); -+ -+ pci_read_config_byte(pdev, 0x54, &ultra); -+ ultra &= ~(3 << (2 * dn)); -+ -+ /* Add ultra DMA bits if in UDMA mode */ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ u8 mode = (adev->dma_mode - XFER_UDMA_0) + 1 - clock; -+ if (mode == 0) -+ mode = 1; -+ ultra |= (mode << (2 * dn)); -+ } -+ pci_write_config_byte(pdev, 0x54, ultra); -+} -+ -+/** -+ * artop6260_set_dmamode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring -+ * -+ * Set DMA mode for device, in host controller PCI config space. The -+ * ARTOP6260 and relatives store the timing data differently. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio = adev->pio_mode - XFER_PIO_0; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 ultra; -+ -+ if (adev->dma_mode == XFER_MW_DMA_0) -+ pio = 1; -+ else -+ pio = 4; -+ -+ /* Load the PIO timing active/recovery bits */ -+ artop6260_load_piomode(ap, adev, pio); -+ -+ /* Add ultra DMA bits if in UDMA mode */ -+ pci_read_config_byte(pdev, 0x44 + ap->hard_port_no, &ultra); -+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ u8 mode = adev->dma_mode - XFER_UDMA_0 + 1 - clock; -+ if (mode == 0) -+ mode = 1; -+ ultra |= (mode << (4 * adev->devno)); -+ } -+ pci_write_config_byte(pdev, 0x44 + ap->hard_port_no, ultra); -+} -+ -+static struct scsi_host_template artop_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations artop6210_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = artop6210_set_piomode, -+ .set_dmamode = artop6210_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = artop6210_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations artop6260_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = artop6260_set_piomode, -+ .set_dmamode = artop6260_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = artop6260_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+ -+/** -+ * artop_init_one - Register ARTOP ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in artop_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ static int printed_version; -+ static struct ata_port_info info_6210 = { -+ .sht = &artop_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = ATA_UDMA2, -+ .port_ops = &artop6210_ops, -+ }; -+ static struct ata_port_info info_626x = { -+ .sht = &artop_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = ATA_UDMA4, -+ .port_ops = &artop6260_ops, -+ }; -+ static struct ata_port_info info_626x_fast = { -+ .sht = &artop_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &artop6260_ops, -+ }; -+ struct ata_port_info *port_info[2]; -+ struct ata_port_info *info; -+ int ports = 2; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ if (id->driver_data == 0) { /* 6210 variant */ -+ info = &info_6210; -+ /* BIOS may have left us in UDMA, clear it before libata probe */ -+ pci_write_config_byte(pdev, 0x54, 0); -+ /* For the moment (also lacks dsc) */ -+ printk(KERN_WARNING "ARTOP 6210 requires serialize functionality not yet supported by libata.\n"); -+ printk(KERN_WARNING "Secondary ATA ports will not be activated.\n"); -+ ports = 1; -+ } -+ else if (id->driver_data == 1) /* 6260 */ -+ info = &info_626x; -+ else if (id->driver_data == 2) { /* 6260 or 6260 + fast */ -+ unsigned long io = pci_resource_start(pdev, 4); -+ u8 reg; -+ -+ info = &info_626x; -+ if (inb(io) & 0x10) -+ info = &info_626x_fast; -+ /* Mac systems come up with some registers not set as we -+ will need them */ -+ -+ /* Clear reset & test bits */ -+ pci_read_config_byte(pdev, 0x49, ®); -+ pci_write_config_byte(pdev, 0x49, reg & ~ 0x30); -+ -+ /* Enable IRQ output and burst mode */ -+ pci_read_config_byte(pdev, 0x4a, ®); -+ pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80); -+ -+ } -+ port_info[0] = port_info[1] = info; -+ return ata_pci_init_one(pdev, port_info, ports); -+} -+ -+static const struct pci_device_id artop_pci_tbl[] = { -+ { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver artop_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = artop_pci_tbl, -+ .probe = artop_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init artop_init(void) -+{ -+ return pci_register_driver(&artop_pci_driver); -+} -+ -+static void __exit artop_exit(void) -+{ -+ pci_unregister_driver(&artop_pci_driver); -+} -+ -+ -+module_init(artop_init); -+module_exit(artop_exit); -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("SCSI low-level driver for ARTOP PATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, artop_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_atiixp.c linux-2.6.16-rc4/drivers/scsi/pata_atiixp.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_atiixp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_atiixp.c 2006-02-07 13:42:02.000000000 +0000 -@@ -0,0 +1,299 @@ -+/* -+ * pata_atiixp.c - ATI PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based on -+ * -+ * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004 -+ * -+ * Copyright (C) 2003 ATI Inc. <hyu@ati.com> -+ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_atiixp" -+#define DRV_VERSION "0.1.1" -+ -+enum { -+ ATIIXP_IDE_PIO_TIMING = 0x40, -+ ATIIXP_IDE_MWDMA_TIMING = 0x44, -+ ATIIXP_IDE_PIO_CONTROL = 0x48, -+ ATIIXP_IDE_PIO_MODE = 0x4a, -+ ATIIXP_IDE_UDMA_CONTROL = 0x54, -+ ATIIXP_IDE_UDMA_MODE = 0x56 -+}; -+ -+static void atiixp_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits atiixp_enable_bits[] = { -+ { 0x48, 1, 0x01, 0x00 }, -+ { 0x48, 1, 0x08, 0x00 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA80; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * atiixp_set_pio_timing - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called by both the pio and dma setup functions to set the controller -+ * timings for PIO transfers. We must load both the mode number and -+ * timing values into the controller. -+ */ -+ -+static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio) -+{ -+ static u8 pio_timings[5] = { 0x5D, 0x47, 0x34, 0x22, 0x20 }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = 2 * ap->hard_port_no + adev->devno; -+ -+ /* Check this is correct - the order is odd in both drivers */ -+ int timing_shift = (16 * ap->hard_port_no) + 8 * (adev->devno ^ 1); -+ u16 pio_mode_data, pio_timing_data; -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); -+ pio_mode_data &= ~(0x7 << (4 * dn)); -+ pio_mode_data |= pio << (4 * dn); -+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); -+ pio_mode_data &= ~(0xFF << timing_shift); -+ pio_mode_data |= (pio_timings[pio] << timing_shift); -+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); -+} -+ -+/** -+ * atiixp_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. We use a shared helper for this -+ * as the DMA setup must also adjust the PIO timing information. -+ */ -+ -+static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0); -+} -+ -+/** -+ * atiixp_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the DMA mode setup. We use timing tables for most -+ * modes but must tune an appropriate PIO mode to match. -+ */ -+ -+static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u8 mwdma_timings[5] = { 0x77, 0x21, 0x20 }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dma = adev->dma_mode; -+ int dn = 2 * ap->hard_port_no + adev->devno; -+ int wanted_pio; -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ u16 udma_mode_data; -+ -+ dma -= XFER_UDMA_0; -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_MODE, &udma_mode_data); -+ udma_mode_data &= ~(0x7 << (4 * dn)); -+ udma_mode_data |= dma << (4 * dn); -+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data); -+ } else { -+ u16 mwdma_timing_data; -+ /* Check this is correct - the order is odd in both drivers */ -+ int timing_shift = (16 * ap->hard_port_no) + 8 * (adev->devno ^ 1); -+ -+ dma -= XFER_MW_DMA_0; -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data); -+ mwdma_timing_data &= ~(0xFF << timing_shift); -+ mwdma_timing_data |= (mwdma_timings[dma] << timing_shift); -+ pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data); -+ } -+ /* -+ * We must now look at the PIO mode situation. We may need to -+ * adjust the PIO mode to keep the timings acceptable -+ */ -+ if (adev->dma_mode >= XFER_MW_DMA_2) -+ wanted_pio = 4; -+ else if (adev->dma_mode == XFER_MW_DMA_1) -+ wanted_pio = 3; -+ else if (adev->dma_mode == XFER_MW_DMA_0) -+ wanted_pio = 0; -+ else BUG(); -+ -+ if (adev->pio_mode != wanted_pio) -+ atiixp_set_pio_timing(ap, adev, wanted_pio); -+} -+ -+/** -+ * atiixp_bmdma_start - DMA start callback -+ * @qc: Command in progress -+ * -+ * When DMA begins we need to ensure that the UDMA control -+ * register for the channel is correctly set. -+ */ -+ -+static void atiixp_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = (2 * ap->hard_port_no) + adev->devno; -+ u16 tmp16; -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); -+ if (adev->dma_mode >= XFER_UDMA_0) -+ tmp16 |= (1 << dn); -+ else -+ tmp16 &= ~(1 << dn); -+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16); -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * atiixp_dma_stop - DMA stop callback -+ * @qc: Command in progress -+ * -+ * DMA has completed. Clear the UDMA flag as the next operations will -+ * be PIO ones not UDMA data transfer. -+ */ -+ -+static void atiixp_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = (2 * ap->hard_port_no) + qc->dev->devno; -+ u16 tmp16; -+ -+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); -+ tmp16 &= ~(1 << dn); -+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16); -+ ata_bmdma_stop(qc); -+} -+ -+static struct scsi_host_template atiixp_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations atiixp_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = atiixp_set_piomode, -+ .set_dmamode = atiixp_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = atiixp_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = atiixp_bmdma_start, -+ .bmdma_stop = atiixp_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &atiixp_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x06, /* No MWDMA0 support */ -+ .udma_mask = 0x3F, -+ .port_ops = &atiixp_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id atiixp[] = { -+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, }, -+}; -+ -+static struct pci_driver atiixp_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = atiixp, -+ .probe = atiixp_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init atiixp_init(void) -+{ -+ return pci_register_driver(&atiixp_pci_driver); -+} -+ -+ -+static void __exit atiixp_exit(void) -+{ -+ pci_unregister_driver(&atiixp_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, atiixp); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(atiixp_init); -+module_exit(atiixp_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cmd64x.c linux-2.6.16-rc4/drivers/scsi/pata_cmd64x.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cmd64x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_cmd64x.c 2006-02-16 15:34:39.000000000 +0000 -@@ -0,0 +1,486 @@ -+/* -+ * pata_cmd64x.c - ATI PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based upon -+ * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002 -+ * -+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. -+ * Note, this driver is not used at all on other systems because -+ * there the "BIOS" has done all of the following already. -+ * Due to massive hardware bugs, UltraDMA is only supported -+ * on the 646U2 and not on the 646U. -+ * -+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) -+ * Copyright (C) 1998 David S. Miller (davem@redhat.com) -+ * -+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> -+ * -+ * TODO -+ * Testing work -+ * Non x86 needs PIO 0 loading before we commence ident -+ * - but this belongs in libata-core -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_cmd64x" -+#define DRV_VERSION "0.1.1" -+ -+/* -+ * CMD64x specific registers definition. -+ */ -+ -+enum { -+ CFR = 0x50, -+ CFR_INTR_CH0 = 0x02, -+ CNTRL = 0x51, -+ CNTRL_DIS_RA0 = 0x40, -+ CNTRL_DIS_RA1 = 0x80, -+ CNTRL_ENA_2ND = 0x08, -+ CMDTIM = 0x52, -+ ARTTIM0 = 0x53, -+ DRWTIM0 = 0x54, -+ ARTTIM1 = 0x55, -+ DRWTIM1 = 0x56, -+ ARTTIM23 = 0x57, -+ ARTTIM23_DIS_RA2 = 0x04, -+ ARTTIM23_DIS_RA3 = 0x08, -+ ARTTIM23_INTR_CH1 = 0x10, -+ ARTTIM2 = 0x57, -+ ARTTIM3 = 0x57, -+ DRWTIM23 = 0x58, -+ DRWTIM2 = 0x58, -+ BRST = 0x59, -+ DRWTIM3 = 0x5b, -+ BMIDECR0 = 0x70, -+ MRDMODE = 0x71, -+ MRDMODE_INTR_CH0 = 0x04, -+ MRDMODE_INTR_CH1 = 0x08, -+ MRDMODE_BLK_CH0 = 0x10, -+ MRDMODE_BLK_CH1 = 0x20, -+ BMIDESR0 = 0x72, -+ UDIDETCR0 = 0x73, -+ DTPR0 = 0x74, -+ BMIDECR1 = 0x78, -+ BMIDECSR = 0x79, -+ BMIDESR1 = 0x7A, -+ UDIDETCR1 = 0x7B, -+ DTPR1 = 0x7C -+}; -+ -+/* Phee Phy Pho Phum */ -+ -+static void cmd64x_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+static void cmd648_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 r; -+ -+ /* Check cable detect bits */ -+ pci_read_config_byte(pdev, BMIDECSR, &r); -+ if (r & (1 << ap->hard_port_no)) -+ ap->cbl = ATA_CBL_PATA80; -+ else -+ ap->cbl = ATA_CBL_PATA40; -+ -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * cmd64x_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. -+ */ -+ -+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct ata_timing t; -+ const unsigned long T = 1000000 / 33; -+ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 }; -+ -+ u8 reg; -+ -+ /* Port layout is not logical so use a table */ -+ const u8 arttim_port[2][2] = { -+ { ARTTIM0, ARTTIM1 }, -+ { ARTTIM23, ARTTIM23 } -+ }; -+ const u8 drwtim_port[2][2] = { -+ { DRWTIM0, DRWTIM1 }, -+ { DRWTIM2, DRWTIM3 } -+ }; -+ -+ int arttim = arttim_port[ap->hard_port_no][adev->devno]; -+ int drwtim = drwtim_port[ap->hard_port_no][adev->devno]; -+ -+ -+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) { -+ printk(KERN_ERR DRV_NAME ": mome computation failed.\n"); -+ return; -+ } -+ if (ap->hard_port_no) { -+ /* Slave has shared address setup */ -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ -+ if (pair) { -+ struct ata_timing tp; -+ ata_timing_compute(pair, pair->pio_mode, &tp, T, 0); -+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); -+ } -+ } -+ -+ printk(KERN_DEBUG DRV_NAME ": active %d recovery %d setup %d.\n", -+ t.active, t.recover, t.setup); -+ if (t.recover > 16) { -+ t.active += t.recover - 16; -+ t.recover = 16; -+ } -+ if (t.active > 16) -+ t.active = 16; -+ -+ /* Now convert the clocks into values we can actually stuff into -+ the chip */ -+ -+ if (t.recover > 1) -+ t.recover--; -+ else -+ t.recover = 15; -+ -+ if (t.setup > 4) -+ t.setup = 0xC0; -+ else -+ t.setup = setup_data[t.setup]; -+ -+ t.active &= 0x0F; /* 0 = 16 */ -+ -+ /* Load setup timing */ -+ pci_read_config_byte(pdev, arttim, ®); -+ reg &= 0x3F; -+ reg |= t.setup; -+ pci_write_config_byte(pdev, arttim, reg); -+ -+ /* Load active/recovery */ -+ pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover); -+} -+ -+/** -+ * cmd64x_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the DMA mode setup. -+ */ -+ -+static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 regU, regD; -+ -+ int pciU = UDIDETCR0 + 8 * ap->hard_port_no; -+ int pciD = BMIDESR0 + 8 * ap->hard_port_no; -+ int shift = 2 * adev->devno; -+ const u8 udma_data[] = { 0x31, 0x21, 0x11, 0x25, 0x15, 0x05 }; -+ const u8 mwdma_data[] = { 0x30, 0x20, 0x10 }; -+ -+ pci_read_config_byte(pdev, pciD, ®D); -+ pci_read_config_byte(pdev, pciU, ®U); -+ -+ regD &= ~(0x20 << shift); -+ regU &= ~(0x35 << shift); -+ -+ if (adev->dma_mode >= XFER_UDMA_0) -+ regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift; -+ else -+ regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift; -+ -+ regD |= 0x20 << adev->devno; -+ -+ pci_write_config_byte(pdev, pciU, regU); -+ pci_write_config_byte(pdev, pciD, regD); -+} -+ -+/** -+ * cmd648_dma_stop - DMA stop callback -+ * @qc: Command in progress -+ * -+ * DMA has completed. -+ */ -+ -+static void cmd648_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 dma_intr; -+ int dma_reg = ap->hard_port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; -+ int dma_mask = ap->hard_port_no ? ARTTIM2 : CFR; -+ -+ ata_bmdma_stop(qc); -+ -+ pci_read_config_byte(pdev, dma_reg, &dma_intr); -+ pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask); -+} -+ -+/** -+ * cmd646r1_dma_stop - DMA stop callback -+ * @qc: Command in progress -+ * -+ * Stub for now while investigating the r1 quirk in the old driver. -+ */ -+ -+static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ ata_bmdma_stop(qc); -+} -+ -+static struct scsi_host_template cmd64x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations cmd64x_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cmd64x_set_piomode, -+ .set_dmamode = cmd64x_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = cmd64x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations cmd646r1_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cmd64x_set_piomode, -+ .set_dmamode = cmd64x_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = cmd64x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = cmd646r1_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations cmd648_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cmd64x_set_piomode, -+ .set_dmamode = cmd64x_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = cmd648_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = cmd648_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ u32 class_rev; -+ -+ static struct ata_port_info cmd_info[6] = { -+ { /* CMD 643 - no UDMA */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &cmd64x_port_ops -+ }, -+ { /* CMD 646 with broken UDMA */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &cmd64x_port_ops -+ }, -+ { /* CMD 646 with working UDMA */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA1, -+ .port_ops = &cmd64x_port_ops -+ }, -+ { /* CMD 646 rev 1 */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &cmd646r1_port_ops -+ }, -+ { /* CMD 648 */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA2, -+ .port_ops = &cmd648_port_ops -+ }, -+ { /* CMD 649 */ -+ .sht = &cmd64x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA3, -+ .port_ops = &cmd648_port_ops -+ } -+ }; -+ static struct ata_port_info *port_info[2], *info; -+ u8 mrdmode; -+ -+ info = &cmd_info[id->driver_data]; -+ -+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); -+ class_rev &= 0xFF; -+ -+ if (id->driver_data == 0) /* 643 */ -+ ata_pci_clear_simplex(pdev); -+ -+ if (pdev->device == PCI_DEVICE_ID_CMD_646) { -+ /* Does UDMA work ? */ -+ if (class_rev > 4) -+ info = &cmd_info[2]; -+ /* Early rev with other problems ? */ -+ else if (class_rev == 1) -+ info = &cmd_info[3]; -+ } -+ -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); -+ pci_read_config_byte(pdev, MRDMODE, &mrdmode); -+ mrdmode &= ~ 0x30; /* IRQ set up */ -+ mrdmode |= 0x02; /* Memory read line enable */ -+ pci_write_config_byte(pdev, MRDMODE, mrdmode); -+ -+ /* Force PIO 0 here.. */ -+ -+ /* PPC specific fixup copied from old driver */ -+#ifdef CONFIG_PPC -+ pci_write_config_byte(pdev, UDIDETCR0, 0xF0); -+#endif -+ -+ port_info[0] = port_info[1] = info; -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static struct pci_device_id cmd64x[] = { -+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, -+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, -+ { 0, }, -+}; -+ -+static struct pci_driver cmd64x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = cmd64x, -+ .probe = cmd64x_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init cmd64x_init(void) -+{ -+ return pci_register_driver(&cmd64x_pci_driver); -+} -+ -+ -+static void __exit cmd64x_exit(void) -+{ -+ pci_unregister_driver(&cmd64x_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, cmd64x); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(cmd64x_init); -+module_exit(cmd64x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5520.c linux-2.6.16-rc4/drivers/scsi/pata_cs5520.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5520.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_cs5520.c 2006-02-20 13:17:11.000000000 +0000 -@@ -0,0 +1,322 @@ -+/* -+ * IDE tuning and bus mastering support for the CS5510/CS5520 -+ * chipsets -+ * -+ * The CS5510/CS5520 are slightly unusual devices. Unlike the -+ * typical IDE controllers they do bus mastering with the drive in -+ * PIO mode and smarter silicon. -+ * -+ * The practical upshot of this is that we must always tune the -+ * drive for the right PIO mode. We must also ignore all the blacklists -+ * and the drive bus mastering DMA information. Also to confuse matters -+ * further we can do DMA on PIO only drives. -+ * -+ * DMA on the 5510 also requires we disable_hlt() during DMA on early -+ * revisions. -+ * -+ * *** This driver is strictly experimental *** -+ * -+ * (c) Copyright Red Hat Inc 2002 -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2, or (at your option) any -+ * later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * Documentation: -+ * Not publically available. -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "cs5520" -+#define DRV_VERSION "0.4" -+ -+struct pio_clocks -+{ -+ int address; -+ int assert; -+ int recovery; -+}; -+ -+static struct pio_clocks cs5520_pio_clocks[]={ -+ {3, 6, 11}, -+ {2, 5, 6}, -+ {1, 4, 3}, -+ {1, 3, 2}, -+ {1, 2, 1} -+}; -+ -+/** -+ * cs5520_set_timings - program PIO timings -+ * @ap: ATA port -+ * @adev: ATA device -+ * -+ * Program the PIO mode timings for the controller according to the pio -+ * clocking table. -+ */ -+ -+static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int slave = adev->devno; -+ -+ pio -= XFER_PIO_0; -+ -+ /* Channel command timing */ -+ pci_write_config_byte(pdev, 0x62 + ap->hard_port_no, -+ (cs5520_pio_clocks[pio].recovery << 4) | -+ (cs5520_pio_clocks[pio].assert)); -+ /* FIXME: should these use address ? */ -+ /* Read command timing */ -+ pci_write_config_byte(pdev, 0x64 + 4*ap->hard_port_no + slave, -+ (cs5520_pio_clocks[pio].recovery << 4) | -+ (cs5520_pio_clocks[pio].assert)); -+ /* Write command timing */ -+ pci_write_config_byte(pdev, 0x66 + 4*ap->hard_port_no + slave, -+ (cs5520_pio_clocks[pio].recovery << 4) | -+ (cs5520_pio_clocks[pio].assert)); -+} -+ -+/** -+ * cs5520_enable_dma - turn on DMA bits -+ * -+ * Turn on the DMA bits for this disk. Needed because the BIOS probably -+ * has not done the work for us. Belongs in the core SATA code. -+ */ -+ -+static int cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev) -+{ -+ /* Set the DMA enable/disable flag */ -+ u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02); -+ reg |= 1<<(adev->devno + 5); -+ outb(reg, ap->ioaddr.bmdma_addr + 0x02); -+} -+ -+/** -+ * cs5520_set_dmamode - program DMA timings -+ * @ap: ATA port -+ * @adev: ATA device -+ * -+ * Program the DMA mode timings for the controller according to the pio -+ * clocking table. Note that this device sets the DMA timings to PIO -+ * mode values. This may seem bizarre but the 5520 architecture talks -+ * PIO mode to the disk and DMA mode to the controller so the underlying -+ * transfers are PIO timed. -+ */ -+ -+static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 }; -+ cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]); -+ cs5520_enable_dma(ap, adev); -+} -+ -+/** -+ * cs5520_set_piomode - program PIO timings -+ * @ap: ATA port -+ * @adev: ATA device -+ * -+ * Program the PIO mode timings for the controller according to the pio -+ * clocking table. We know pio_mode will equal dma_mode because of the -+ * CS5520 architecture. At least once we turned DMA on and wrote a -+ * mode setter. -+ */ -+ -+static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ cs5520_set_timings(ap, adev, adev->pio_mode); -+} -+ -+static struct scsi_host_template cs5520_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations cs5520_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cs5520_set_piomode, -+ .set_dmamode = cs5520_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ u8 pcicfg; -+ static struct ata_probe_ent probe[2]; -+ int ports = 0; -+ -+ pci_read_config_byte(dev, 0x60, &pcicfg); -+ -+ /* Check if the ATA ports are enabled */ -+ if ((pcicfg & 3) == 0) -+ return -ENODEV; -+ -+ if ((pcicfg & 0x40) == 0) { -+ printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n"); -+ pci_write_config_byte(dev, 0x60, pcicfg | 0x40); -+ } -+ -+ /* Perform set up for DMA */ -+ if (pci_enable_device_bars(dev, 1<<2)) { -+ printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n"); -+ return -ENODEV; -+ } -+ pci_set_master(dev); -+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { -+ printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n"); -+ return -ENODEV; -+ } -+ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) { -+ printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n"); -+ return -ENODEV; -+ } -+ -+ /* We have to do our own plumbing as the PCI setup for this -+ chipset is non-standard so we can't punt to the libata code */ -+ -+ INIT_LIST_HEAD(&probe[0].node); -+ probe[0].dev = pci_dev_to_dev(dev); -+ probe[0].port_ops = &cs5520_port_ops; -+ probe[0].sht = &cs5520_sht; -+ probe[0].pio_mask = 0x1F; -+ probe[0].mwdma_mask = id->driver_data; -+ probe[0].irq = 14; -+ probe[0].irq_flags = SA_SHIRQ; -+ probe[0].host_flags = ATA_FLAG_SLAVE_POSS; -+ probe[0].legacy_mode = 1; -+ probe[0].n_ports = 1; -+ probe[0].port[0].cmd_addr = 0x1F0; -+ probe[0].port[0].ctl_addr = 0x3F6; -+ probe[0].port[0].altstatus_addr = 0x3F6; -+ probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2); -+ -+ /* The secondary lurks at different addresses but is otherwise -+ the same beastie */ -+ -+ probe[1] = probe[0]; -+ INIT_LIST_HEAD(&probe[1].node); -+ probe[1].irq = 15; -+ probe[1].hard_port_no = 1; -+ probe[1].port[0].cmd_addr = 0x170; -+ probe[1].port[0].ctl_addr = 0x376; -+ probe[1].port[0].altstatus_addr = 0x376; -+ probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8; -+ -+ /* Let libata fill in the port details */ -+ ata_std_ports(&probe[0].port[0]); -+ ata_std_ports(&probe[1].port[0]); -+ -+ /* Now add the ports that are active */ -+ if (pcicfg & 1) -+ ports += ata_device_add(&probe[0]); -+ if (pcicfg & 2) -+ ports += ata_device_add(&probe[1]); -+ if (ports) -+ return 0; -+ return -ENODEV; -+} -+ -+/** -+ * cs5520_remove_one - device unload -+ * @pdev: PCI device being removed -+ * -+ * Handle an unplug/unload event for a PCI device. Unload the -+ * PCI driver but do not use the default handler as we manage -+ * resources ourself and *MUST NOT* disable the device as it has -+ * other functions. -+ */ -+ -+static void __devexit cs5520_remove_one(struct pci_dev *pdev) -+{ -+ struct device *dev = pci_dev_to_dev(pdev); -+ struct ata_host_set *host_set = dev_get_drvdata(dev); -+ -+ ata_host_set_remove(host_set); -+ dev_set_drvdata(dev, NULL); -+} -+ -+/* For now keep DMA off. We can set it for all but A rev CS5510 once the -+ core ATA code can handle it */ -+ -+static struct pci_device_id pata_cs5520[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, -+ { 0, }, -+}; -+ -+static struct pci_driver cs5520_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = pata_cs5520, -+ .probe = cs5520_init_one, -+ .remove = cs5520_remove_one -+}; -+ -+ -+static int __init cs5520_init(void) -+{ -+ return pci_register_driver(&cs5520_pci_driver); -+} -+ -+static void __exit cs5520_exit(void) -+{ -+ pci_unregister_driver(&cs5520_pci_driver); -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, pata_cs5520); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(cs5520_init); -+module_exit(cs5520_exit); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5530.c linux-2.6.16-rc4/drivers/scsi/pata_cs5530.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5530.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_cs5530.c 2006-02-21 16:44:52.000000000 +0000 -@@ -0,0 +1,371 @@ -+/* -+ * pata-cs5530.c - CS5530 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon cs5530.c by Mark Lord. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Loosely based on the piix & svwks drivers. -+ * -+ * Documentation: -+ * Available from AMD web site. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/dmi.h> -+ -+#define DRV_NAME "cs5530" -+#define DRV_VERSION "0.4" -+ -+/** -+ * cs5530_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Set our PIO requirements. This is fairly simple on the CS5530 -+ * chips. -+ */ -+ -+static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static unsigned int cs5530_pio_timings[2][5] = { -+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, -+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} -+ }; -+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->hard_port_no; -+ u32 tuning; -+ int format; -+ -+ /* Find out which table to use */ -+ tuning = inl(base + 0x04); -+ format = (tuning & 0x80000000UL) ? 1 : 0; -+ -+ /* Now load the right timing register */ -+ if (adev->devno) -+ base += 0x08; -+ -+ outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); -+} -+ -+/** -+ * cs5530_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * We cannot mix MWDMA and UDMA without reloading timings each switch -+ * master to slave. We track the last DMA setup in order to minimise -+ * reloads. -+ */ -+ -+static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->hard_port_no; -+ u32 tuning, timing = 0; -+ u8 reg; -+ -+ /* Find out which table to use */ -+ tuning = inl(base + 0x04); -+ -+ switch(adev->dma_mode) { -+ case XFER_UDMA_0: -+ timing = 0x00921250;break; -+ case XFER_UDMA_1: -+ timing = 0x00911140;break; -+ case XFER_UDMA_2: -+ timing = 0x00911030;break; -+ case XFER_MW_DMA_0: -+ timing = 0x00077771;break; -+ case XFER_MW_DMA_1: -+ timing = 0x00012121;break; -+ case XFER_MW_DMA_2: -+ timing = 0x00002020;break; -+ default: -+ BUG(); -+ } -+ /* Merge in the PIO format bit */ -+ timing |= (tuning & 0x80000000UL); -+ if (adev->devno == 0) /* Master */ -+ outl(timing, base + 0x04); -+ else { -+ if (timing & 0x00100000) -+ tuning |= 0x00100000; /* UDMA for both */ -+ else -+ tuning &= ~0x00100000; /* MWDMA for both */ -+ outl(tuning, base + 0x04); -+ outl(timing, base + 0x0C); -+ } -+ -+ /* Set the DMA capable bit in the BMDMA area */ -+ reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); -+ reg |= (1 << (5 + adev->devno)); -+ outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); -+ -+ /* Remember the last DMA setup we did */ -+ -+ ap->private_data = adev; -+} -+ -+/** -+ * cs5530_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Specifically we have a problem that there is only -+ * one MWDMA/UDMA bit. -+ */ -+ -+static int cs5530_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ struct ata_device *prev = ap->private_data; -+ -+ /* See if the DMA settings could be wrong */ -+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) { -+ /* Maybe, but do the channels match MWDMA/UDMA ? */ -+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) || -+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0)) -+ /* Switch the mode bits */ -+ cs5530_set_dmamode(ap, adev); -+ } -+ -+ return ata_qc_issue_prot(qc); -+} -+ -+static struct scsi_host_template cs5530_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations cs5530_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cs5530_set_piomode, -+ .set_dmamode = cs5530_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = cs5530_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct dmi_system_id __initdata palmax_dmi_table[] = { -+ { -+ .ident = "Palmax PD1100", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Cyrix"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Caddis"), -+ }, -+ }, -+ { } -+}; -+ -+static int cs5530_is_palmax(void) -+{ -+ if (dmi_check_system(palmax_dmi_table)) { -+ printk(KERN_INFO "Palmax PD1100: Disabling DMA on docking port.\n"); -+ return 1; -+ } -+ return 0; -+} -+ -+/** -+ * cs5530_init_one - Initialise a CS5530 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Install a driver for the newly found CS5530 companion chip. Most of -+ * this is just housekeeping. We have to set the chip up correctly and -+ * turn off various bits of emulation magic. -+ */ -+ -+static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ int compiler_warning_pointless_fix; -+ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; -+ static struct ata_port_info info = { -+ .sht = &cs5530_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x07, -+ .port_ops = &cs5530_port_ops -+ }; -+ /* The docking connector doesn't do UDMA, and it seems not MWDMA */ -+ static struct ata_port_info info_palmax_secondary = { -+ .sht = &cs5530_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .port_ops = &cs5530_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ dev = NULL; -+ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { -+ switch (dev->device) { -+ case PCI_DEVICE_ID_CYRIX_PCI_MASTER: -+ master_0 = pci_dev_get(dev); -+ break; -+ case PCI_DEVICE_ID_CYRIX_5530_LEGACY: -+ cs5530_0 = pci_dev_get(dev); -+ break; -+ } -+ } -+ if (!master_0) { -+ printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n"); -+ goto fail_put; -+ } -+ if (!cs5530_0) { -+ printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n"); -+ goto fail_put; -+ } -+ -+ pci_set_master(cs5530_0); -+ compiler_warning_pointless_fix = pci_set_mwi(cs5530_0); -+ -+ /* -+ * Set PCI CacheLineSize to 16-bytes: -+ * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 -+ * -+ * Note: This value is constant because the 5530 is only a Geode companion -+ */ -+ -+ pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); -+ -+ /* -+ * Disable trapping of UDMA register accesses (Win98 hack): -+ * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 -+ */ -+ -+ pci_write_config_word(cs5530_0, 0xd0, 0x5006); -+ -+ /* -+ * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: -+ * The other settings are what is necessary to get the register -+ * into a sane state for IDE DMA operation. -+ */ -+ -+ pci_write_config_byte(master_0, 0x40, 0x1e); -+ -+ /* -+ * Set max PCI burst size (16-bytes seems to work best): -+ * 16bytes: set bit-1 at 0x41 (reg value of 0x16) -+ * all others: clear bit-1 at 0x41, and do: -+ * 128bytes: OR 0x00 at 0x41 -+ * 256bytes: OR 0x04 at 0x41 -+ * 512bytes: OR 0x08 at 0x41 -+ * 1024bytes: OR 0x0c at 0x41 -+ */ -+ -+ pci_write_config_byte(master_0, 0x41, 0x14); -+ -+ /* -+ * These settings are necessary to get the chip -+ * into a sane state for IDE DMA operation. -+ */ -+ -+ pci_write_config_byte(master_0, 0x42, 0x00); -+ pci_write_config_byte(master_0, 0x43, 0xc1); -+ -+ pci_dev_put(master_0); -+ pci_dev_put(cs5530_0); -+ -+ if (cs5530_is_palmax()) -+ port_info[1] = &info_palmax_secondary; -+ -+ /* Now kick off ATA set up */ -+ return ata_pci_init_one(dev, port_info, 2); -+ -+fail_put: -+ if (master_0) -+ pci_dev_put(master_0); -+ if (cs5530_0) -+ pci_dev_put(cs5530_0); -+ return -ENODEV; -+} -+ -+static struct pci_device_id cs5530[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, -+ { 0, }, -+}; -+ -+static struct pci_driver cs5530_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = cs5530, -+ .probe = cs5530_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init cs5530_init(void) -+{ -+ return pci_register_driver(&cs5530_pci_driver); -+} -+ -+ -+static void __exit cs5530_exit(void) -+{ -+ pci_unregister_driver(&cs5530_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, cs5530); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(cs5530_init); -+module_exit(cs5530_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5535.c linux-2.6.16-rc4/drivers/scsi/pata_cs5535.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cs5535.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_cs5535.c 2006-02-16 15:37:21.000000000 +0000 -@@ -0,0 +1,286 @@ -+/* -+ * pata-cs5535.c - CS5535 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and -+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de -+ * and Alexander Kiausch <alex.kiausch@t-online.de> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Loosely based on the piix & svwks drivers. -+ * -+ * Documentation: -+ * Available from AMD web site. -+ * TODO -+ * Review errata to see if serializing is neccessary -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <asm/msr.h> -+ -+#define DRV_NAME "cs5535" -+#define DRV_VERSION "0.2.1" -+ -+/* -+ * The Geode (Aka Athlon GX now) uses an internal MSR based -+ * bus system for control. Demented but there you go. -+ */ -+ -+#define MSR_ATAC_BASE 0x51300000 -+#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0) -+#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01) -+#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02) -+#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03) -+#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04) -+#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05) -+#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08) -+#define ATAC_RESET (MSR_ATAC_BASE+0x10) -+#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20) -+#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21) -+#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22) -+#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23) -+#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24) -+ -+#define ATAC_BM0_CMD_PRIM 0x00 -+#define ATAC_BM0_STS_PRIM 0x02 -+#define ATAC_BM0_PRD 0x04 -+ -+#define CS5535_CABLE_DETECT 0x48 -+ -+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 ) -+ -+/** -+ * cs5535_cable_detect - detect cable type -+ * @ap: Port to detect on -+ * -+ * Perform cable detection for ATA66 capable cable. Return a libata -+ * cable type. -+ */ -+ -+static int cs5535_cable_detect(struct ata_port *ap) -+{ -+ u8 cable; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable); -+ if (cable & 1) -+ return ATA_CBL_PATA80; -+ else -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * cs5535_phy_reset - reset/probe -+ * @ap: Port to reset -+ * -+ * Reset and configure a port -+ */ -+ -+static void cs5535_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = cs5535_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * cs5535_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Set our PIO requirements. The CS5535 is pretty clean about all this -+ */ -+ -+static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u16 pio_timings[5] = { -+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 -+ }; -+ static u16 pio_cmd_timings[5] = { -+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 -+ }; -+ u32 reg, dummy; -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ -+ int mode = adev->pio_mode - XFER_PIO_0; -+ int cmdmode = mode; -+ -+ /* Command timing has to be for the lowest of the pair of devices */ -+ if (pair) { -+ int pairmode = pair->pio_mode - XFER_PIO_0; -+ cmdmode = min(mode, pairmode); -+ /* Write the other drive timing register if it changed */ -+ if (cmdmode < pairmode) -+ wrmsr(ATAC_CH0D0_PIO + 2 * pair->devno, -+ pio_cmd_timings[cmdmode] << 16 | pio_timings[pairmode], 0); -+ } -+ /* Write the drive timing register */ -+ wrmsr(ATAC_CH0D0_PIO + 2 * adev->devno, -+ pio_cmd_timings[cmdmode] << 16 | pio_timings[mode], 0); -+ -+ /* Set the PIO "format 1" bit in the DMA timing register */ -+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy); -+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg | 0x80000000UL, 0); -+} -+ -+/** -+ * cs5535_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ */ -+ -+static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u32 udma_timings[5] = { 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 }; -+ static u32 mwdma_timings[3] = { 0x7F0FFFF3, 0x7F035352, 0x7F024241 }; -+ u32 reg, dummy; -+ int mode = adev->dma_mode; -+ -+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy); -+ reg &= 0x80000000UL; -+ if (mode >= XFER_UDMA_0) -+ reg |= udma_timings[mode - XFER_UDMA_0]; -+ else -+ reg |= mwdma_timings[mode - XFER_MW_DMA_0]; -+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, 0); -+} -+ -+static struct scsi_host_template cs5535_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations cs5535_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cs5535_set_piomode, -+ .set_dmamode = cs5535_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = cs5535_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * cs5535_init_one - Initialise a CS5530 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Install a driver for the newly found CS5530 companion chip. Most of -+ * this is just housekeeping. We have to set the chip up correctly and -+ * turn off various bits of emulation magic. -+ */ -+ -+static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &cs5535_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, -+ .port_ops = &cs5535_port_ops -+ }; -+ struct ata_port_info *ports[1] = { &info }; -+ -+ u32 timings, dummy; -+ -+ /* Check the BIOS set the initial timing clock. If not set the -+ timings for PIO0 */ -+ rdmsr(ATAC_CH0D0_PIO, timings, dummy); -+ if (CS5535_BAD_PIO(timings)) -+ wrmsr(ATAC_CH0D0_PIO, 0xF7F4F7F4UL, 0); -+ rdmsr(ATAC_CH0D1_PIO, timings, dummy); -+ if (CS5535_BAD_PIO(timings)) -+ wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0); -+ return ata_pci_init_one(dev, ports, 1); -+} -+ -+static struct pci_device_id cs5535[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), }, -+ { 0, }, -+}; -+ -+static struct pci_driver cs5535_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = cs5535, -+ .probe = cs5535_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init cs5535_init(void) -+{ -+ return pci_register_driver(&cs5535_pci_driver); -+} -+ -+ -+static void __exit cs5535_exit(void) -+{ -+ pci_unregister_driver(&cs5535_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch"); -+MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, cs5535); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(cs5535_init); -+module_exit(cs5535_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cypress.c linux-2.6.16-rc4/drivers/scsi/pata_cypress.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_cypress.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_cypress.c 2006-02-16 15:37:46.000000000 +0000 -@@ -0,0 +1,215 @@ -+/* -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_cypress" -+#define DRV_VERSION "0.1" -+ -+/* here are the offset definitions for the registers */ -+ -+enum { -+ CY82_IDE_CMDREG = 0x04, -+ CY82_IDE_ADDRSETUP = 0x48, -+ CY82_IDE_MASTER_IOR = 0x4C, -+ CY82_IDE_MASTER_IOW = 0x4D, -+ CY82_IDE_SLAVE_IOR = 0x4E, -+ CY82_IDE_SLAVE_IOW = 0x4F, -+ CY82_IDE_MASTER_8BIT = 0x50, -+ CY82_IDE_SLAVE_8BIT = 0x51, -+ -+ CY82_INDEX_PORT = 0x22, -+ CY82_DATA_PORT = 0x23, -+ -+ CY82_INDEX_CTRLREG1 = 0x01, -+ CY82_INDEX_CHANNEL0 = 0x30, -+ CY82_INDEX_CHANNEL1 = 0x31, -+ CY82_INDEX_TIMEOUT = 0x32 -+}; -+ -+/* Phee Phy Pho Phum */ -+ -+static void cy82c693_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * cy82c693_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. -+ */ -+ -+static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct ata_timing t; -+ const unsigned long T = 1000000 / 33; -+ short time_16, time_8; -+ u32 addr; -+ -+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 1) < 0) { -+ printk(KERN_ERR DRV_NAME ": mome computation failed.\n"); -+ return; -+ } -+ -+ time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4); -+ time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4); -+ -+ if (adev->devno == 0) { -+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr); -+ -+ addr &= ~0x0F; /* Mask bits */ -+ addr |= FIT(t.setup, 0, 15); -+ -+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr); -+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16); -+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOW, time_16); -+ pci_write_config_byte(pdev, CY82_IDE_MASTER_8BIT, time_8); -+ } else { -+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr); -+ -+ addr &= ~0xF0; /* Mask bits */ -+ addr |= (FIT(t.setup, 0, 15) << 4); -+ -+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr); -+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16); -+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOW, time_16); -+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_8BIT, time_8); -+ } -+} -+ -+/** -+ * cy82c693_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the DMA mode setup. -+ */ -+ -+static void cy82c693_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ int reg = CY82_INDEX_CHANNEL0 + ap->hard_port_no; -+ -+ /* Be afraid, be very afraid. Magic registers in low I/O space */ -+ outb(reg, 0x22); -+ outb(adev->dma_mode - XFER_MW_DMA_0, 0x23); -+ -+ /* 0x50 gives the best behaviour on the Alpha's using this chip */ -+ outb(CY82_INDEX_TIMEOUT, 0x22); -+ outb(0x50, 0x23); -+} -+ -+static struct scsi_host_template cy82c693_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations cy82c693_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = cy82c693_set_piomode, -+ .set_dmamode = cy82c693_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = cy82c693_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &cy82c693_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &cy82c693_port_ops -+ }; -+ static struct ata_port_info *port_info[1] = { &info }; -+ -+ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the -+ moment we don't handle the secondary. FIXME */ -+ -+ if (PCI_FUNC(pdev->devfn) != 1) -+ return -ENODEV; -+ -+ return ata_pci_init_one(pdev, port_info, 1); -+} -+ -+static struct pci_device_id cy82c693[] = { -+ { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, }, -+}; -+ -+static struct pci_driver cy82c693_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = cy82c693, -+ .probe = cy82c693_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init cy82c693_init(void) -+{ -+ return pci_register_driver(&cy82c693_pci_driver); -+} -+ -+ -+static void __exit cy82c693_exit(void) -+{ -+ pci_unregister_driver(&cy82c693_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the CY82C693 PATA controller"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, cy82c693); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(cy82c693_init); -+module_exit(cy82c693_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_efar.c linux-2.6.16-rc4/drivers/scsi/pata_efar.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_efar.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_efar.c 2006-02-16 15:37:53.000000000 +0000 -@@ -0,0 +1,341 @@ -+/* -+ * pata_efar.c - EFAR PIIX clone controller driver -+ * -+ * (C) 2005 Red Hat <alan@redhat.com> -+ * -+ * Some parts based on ata_piix.c by Jeff Garzik and others. -+ * -+ * The EFAR is a PIIX4 clone with UDMA66 support. Unlike the later -+ * Intel ICH controllers the EFAR widened the UDMA mode register bits -+ * and doesn't require the funky clock selection. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_efar" -+#define DRV_VERSION "0.1" -+ -+/** -+ * efar_cable_detect - check for 40/80 pin -+ * @ap: Port -+ * -+ * Perform cable detection for the EFAR ATA interface. This is -+ * different to the PIIX arrangement -+ */ -+ -+static int efar_cable_detect(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 tmp; -+ -+ pci_read_config_byte(pdev, 0x47, &tmp); -+ if (tmp & (2 >> ap->hard_port_no)) -+ return ATA_CBL_PATA40; -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * efar_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void efar_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ const struct pci_bits efar_enable_bits[] = { -+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ -+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = efar_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * efar_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set PIO mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio = adev->pio_mode - XFER_PIO_0; -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ unsigned int idetm_port= ap->hard_port_no ? 0x42 : 0x40; -+ u16 idetm_data; -+ int control = 0; -+ -+ /* -+ * See Intel Document 298600-004 for the timing programing rules -+ * for PIIX/ICH. The EFAR is a clone so very similar -+ */ -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; -+ -+ if (pio > 2) -+ control |= 1; /* TIME1 enable */ -+ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */ -+ control |= 2; /* IE enable */ -+ /* Intel specifies that the PPE functionality is for disk only */ -+ if (adev->class == ATA_DEV_ATA) -+ control |= 4; /* PPE enable */ -+ -+ pci_read_config_word(dev, idetm_port, &idetm_data); -+ -+ /* Enable PPE, IE and TIME as appropriate */ -+ -+ if (adev->devno == 0) { -+ idetm_data &= 0xCCF0; -+ idetm_data |= control; -+ idetm_data |= (timings[pio][0] << 12) | -+ (timings[pio][1] << 8); -+ } else { -+ int shift = 4 * ap->hard_port_no; -+ u8 slave_data; -+ -+ idetm_data &= 0xCC0F; -+ idetm_data |= (control << 4); -+ -+ /* Slave timing in seperate register */ -+ pci_read_config_byte(dev, 0x44, &slave_data); -+ slave_data &= 0x0F << shift; -+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift; -+ pci_write_config_byte(dev, 0x44, slave_data); -+ } -+ -+ idetm_data |= 0x4000; /* Ensure SITRE is enabled */ -+ pci_write_config_word(dev, idetm_port, idetm_data); -+} -+ -+/** -+ * efar_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ u8 master_port = ap->hard_port_no ? 0x42 : 0x40; -+ u16 master_data; -+ u8 speed = adev->dma_mode; -+ int devid = adev->devno + 2 * ap->hard_port_no; -+ u8 udma_enable; -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; -+ -+ pci_read_config_word(dev, master_port, &master_data); -+ pci_read_config_byte(dev, 0x48, &udma_enable); -+ -+ if (speed >= XFER_UDMA_0) { -+ unsigned int udma = adev->dma_mode - XFER_UDMA_0; -+ u16 udma_timing; -+ -+ udma_enable |= (1 << devid); -+ -+ /* Load the UDMA mode number */ -+ pci_read_config_word(dev, 0x4A, &udma_timing); -+ udma_timing &= ~(7 << (4 * devid)); -+ udma_timing |= udma << (4 * devid); -+ pci_write_config_word(dev, 0x4A, udma_timing); -+ } else { -+ /* -+ * MWDMA is driven by the PIO timings. We must also enable -+ * IORDY unconditionally along with TIME1. PPE has already -+ * been set when the PIO timing was set. -+ */ -+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; -+ unsigned int control; -+ u8 slave_data; -+ const unsigned int needed_pio[3] = { -+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 -+ }; -+ int pio = needed_pio[mwdma] - XFER_PIO_0; -+ -+ control = 3; /* IORDY|TIME1 */ -+ -+ /* If the drive MWDMA is faster than it can do PIO then -+ we must force PIO into PIO0 */ -+ -+ if (adev->pio_mode < needed_pio[mwdma]) -+ /* Enable DMA timing only */ -+ control |= 8; /* PIO cycles in PIO0 */ -+ -+ if (adev->devno) { /* Slave */ -+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ -+ master_data |= control << 4; -+ pci_read_config_byte(dev, 0x44, &slave_data); -+ slave_data &= (0x0F + 0xE1 * ap->hard_port_no); -+ /* Load the matching timing */ -+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->hard_port_no ? 4 : 0); -+ pci_write_config_byte(dev, 0x44, slave_data); -+ } else { /* Master */ -+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY -+ and master timing bits */ -+ master_data |= control; -+ master_data |= -+ (timings[pio][0] << 12) | -+ (timings[pio][1] << 8); -+ } -+ udma_enable &= ~(1 << devid); -+ pci_write_config_word(dev, master_port, master_data); -+ } -+ pci_write_config_byte(dev, 0x48, udma_enable); -+} -+ -+static struct scsi_host_template efar_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations efar_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = efar_set_piomode, -+ .set_dmamode = efar_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = efar_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+ -+/** -+ * efar_init_one - Register EFAR ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in efar_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ static struct ata_port_info info = { -+ .sht = &efar_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma1-2 */ -+ .udma_mask = 0x0f, /* UDMA 66 */ -+ .port_ops = &efar_ops, -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id efar_pci_tbl[] = { -+ { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, }, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver efar_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = efar_pci_tbl, -+ .probe = efar_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init efar_init(void) -+{ -+ return pci_register_driver(&efar_pci_driver); -+} -+ -+static void __exit efar_exit(void) -+{ -+ pci_unregister_driver(&efar_pci_driver); -+} -+ -+ -+module_init(efar_init); -+module_exit(efar_exit); -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("SCSI low-level driver for EFAR PIIX clones"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, efar_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt34x.c linux-2.6.16-rc4/drivers/scsi/pata_hpt34x.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt34x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_hpt34x.c 2006-02-16 15:38:47.000000000 +0000 -@@ -0,0 +1,206 @@ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "hpt34x" -+#define DRV_VERSION "0.1" -+ -+/** -+ * hpt34x_bus_reset - reset the hpt34x bus -+ * @ap: ATA port to reset -+ * -+ * Perform the housekeeping when doing an ATA bus reeset. We just -+ * need to force the cable type. -+ */ -+ -+static void hpt34x_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA40; -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * hpt34x_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Set our PIO requirements. This is fairly simple on the HPT34x as -+ * all we have to do is clear the MWDMA and UDMA bits then load the -+ * mode number. -+ */ -+ -+static void hpt34x_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 r1, r2; -+ int dn = 2 * ap->hard_port_no + adev->devno; -+ -+ pci_read_config_dword(pdev, 0x44, &r1); -+ pci_read_config_dword(pdev, 0x48, &r2); -+ /* Load the PIO timing number */ -+ r1 &= ~(7 << (3 * dn)); -+ r1 |= (adev->pio_mode - XFER_PIO_0) << (3 * dn); -+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */ -+ -+ pci_write_config_dword(pdev, 0x44, r1); -+ pci_write_config_dword(pdev, 0x48, r2); -+} -+ -+/** -+ * hpt34x_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * Set up the channel for MWDMA or UDMA modes. Much the same as with -+ * PIO, load the mode number and then set MWDMA or UDMA flag. -+ */ -+ -+static void hpt34x_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 r1, r2; -+ int dn = 2 * ap->hard_port_no + adev->devno; -+ int mode_num = adev->dma_mode & 0x0F; -+ -+ pci_read_config_dword(pdev, 0x44, &r1); -+ pci_read_config_dword(pdev, 0x48, &r2); -+ /* Load the timing number */ -+ r1 &= ~(7 << (3 * dn)); -+ r1 |= (mode_num << (3 * dn)); -+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */ -+ -+ if (adev->dma_mode >= XFER_UDMA_0) -+ r2 |= 0x01 << dn; /* Ultra mode */ -+ else -+ r2 |= 0x10 << dn; /* MWDMA */ -+ -+ pci_write_config_dword(pdev, 0x44, r1); -+ pci_write_config_dword(pdev, 0x48, r2); -+} -+ -+static struct scsi_host_template hpt34x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations hpt34x_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt34x_set_piomode, -+ .set_dmamode = hpt34x_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt34x_phy_reset, -+ -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * hpt34x_init_one - Initialise an HPT343/363 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Perform basic initialisation. The chip has a quirk that it won't -+ * function unless it is at XX00. The old ATA driver touched this up -+ * but we leave it for pci quirks to do properly. -+ */ -+ -+static int hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &hpt34x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x07, -+ .port_ops = &hpt34x_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ u16 cmd; -+ -+ /* Initialize the board */ -+ pci_write_config_word(dev, 0x80, 0x00); -+ /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */ -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ if (cmd & PCI_COMMAND_MEMORY) -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); -+ else -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); -+ -+ /* Now kick off ATA set up */ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id hpt34x[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), }, -+ { 0, }, -+}; -+ -+static struct pci_driver hpt34x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = hpt34x, -+ .probe = hpt34x_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init hpt34x_init(void) -+{ -+ return pci_register_driver(&hpt34x_pci_driver); -+} -+ -+ -+static void __exit hpt34x_exit(void) -+{ -+ pci_unregister_driver(&hpt34x_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT343/363"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, hpt34x); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(hpt34x_init); -+module_exit(hpt34x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt366.c linux-2.6.16-rc4/drivers/scsi/pata_hpt366.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt366.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_hpt366.c 2006-02-16 15:45:36.000000000 +0000 -@@ -0,0 +1,479 @@ -+/* -+ * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers. -+ * -+ * This driver is heavily based upon: -+ * -+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 -+ * -+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> -+ * Portions Copyright (C) 2001 Sun Microsystems, Inc. -+ * Portions Copyright (C) 2003 Red Hat Inc -+ * -+ * -+ * TODO -+ * Maybe PLL mode -+ * Look into engine reset on timeout errors. Should not be -+ * required. -+ */ -+ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "hpt36x" -+#define DRV_VERSION "0.2" -+ -+struct hpt_clock { -+ u8 xfer_speed; -+ u32 timing; -+}; -+ -+/* key for bus clock timings -+ * bit -+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file -+ * register access. -+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file -+ * register access. -+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer. -+ * during task file register access. -+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA -+ * xfer. -+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task -+ * register access. -+ * 28 UDMA enable -+ * 29 DMA enable -+ * 30 PIO_MST enable. if set, the chip is in bus master mode during -+ * PIO. -+ * 31 FIFO enable. -+ */ -+ -+static struct chipset_bus_clock_list_entry hpt366_40[] = { -+ { XFER_UDMA_4, 0x900fd943 }, -+ { XFER_UDMA_3, 0x900ad943 }, -+ { XFER_UDMA_2, 0x900bd943 }, -+ { XFER_UDMA_1, 0x9008d943 }, -+ { XFER_UDMA_0, 0x9008d943 }, -+ -+ { XFER_MW_DMA_2, 0xa008d943 }, -+ { XFER_MW_DMA_1, 0xa010d955 }, -+ { XFER_MW_DMA_0, 0xa010d9fc }, -+ -+ { XFER_PIO_4, 0xc008d963 }, -+ { XFER_PIO_3, 0xc010d974 }, -+ { XFER_PIO_2, 0xc010d997 }, -+ { XFER_PIO_1, 0xc010d9c7 }, -+ { XFER_PIO_0, 0xc018d9d9 }, -+ { 0, 0x0120d9d9 } -+}; -+ -+static struct chipset_bus_clock_list_entry hpt366_33[] = { -+ { XFER_UDMA_4, 0x90c9a731 }, -+ { XFER_UDMA_3, 0x90cfa731 }, -+ { XFER_UDMA_2, 0x90caa731 }, -+ { XFER_UDMA_1, 0x90cba731 }, -+ { XFER_UDMA_0, 0x90c8a731 }, -+ -+ { XFER_MW_DMA_2, 0xa0c8a731 }, -+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */ -+ { XFER_MW_DMA_0, 0xa0c8a797 }, -+ -+ { XFER_PIO_4, 0xc0c8a731 }, -+ { XFER_PIO_3, 0xc0c8a742 }, -+ { XFER_PIO_2, 0xc0d0a753 }, -+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */ -+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ -+ { 0, 0x0120a7a7 } -+}; -+ -+static struct chipset_bus_clock_list_entry hpt366_25[] = { -+ { XFER_UDMA_4, 0x90c98521 }, -+ { XFER_UDMA_3, 0x90cf8521 }, -+ { XFER_UDMA_2, 0x90cf8521 }, -+ { XFER_UDMA_1, 0x90cb8521 }, -+ { XFER_UDMA_0, 0x90cb8521 }, -+ -+ { XFER_MW_DMA_2, 0xa0ca8521 }, -+ { XFER_MW_DMA_1, 0xa0ca8532 }, -+ { XFER_MW_DMA_0, 0xa0ca8575 }, -+ -+ { XFER_PIO_4, 0xc0ca8521 }, -+ { XFER_PIO_3, 0xc0ca8532 }, -+ { XFER_PIO_2, 0xc0ca8542 }, -+ { XFER_PIO_1, 0xc0d08572 }, -+ { XFER_PIO_0, 0xc0d08585 }, -+ { 0, 0x01208585 } -+}; -+ -+static const char *bad_ata33[] = { -+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", -+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", -+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", -+ "Maxtor 90510D4", -+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", -+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", -+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", -+ NULL -+}; -+ -+static const char *bad_ata66_4[] = { -+ "IBM-DTLA-307075", -+ "IBM-DTLA-307060", -+ "IBM-DTLA-307045", -+ "IBM-DTLA-307030", -+ "IBM-DTLA-307020", -+ "IBM-DTLA-307015", -+ "IBM-DTLA-305040", -+ "IBM-DTLA-305030", -+ "IBM-DTLA-305020", -+ "IC35L010AVER07-0", -+ "IC35L020AVER07-0", -+ "IC35L030AVER07-0", -+ "IC35L040AVER07-0", -+ "IC35L060AVER07-0", -+ "WDC AC310200R", -+ NULL -+}; -+ -+static const char *bad_ata66_3[] = { -+ "WDC AC310200R", -+ NULL -+}; -+ -+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) -+{ -+ unsigned char model_num[40]; -+ char *s; -+ unsigned int len; -+ int i = 0; -+ -+ ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS, -+ sizeof(model_num)); -+ s = &model_num[0]; -+ len = strnlen(s, sizeof(model_num)); -+ -+ /* ATAPI specifies that empty space is blank-filled; remove blanks */ -+ while ((len > 0) && (s[len - 1] == ' ')) { -+ len--; -+ s[len] = 0; -+ } -+ -+ while(list[i] != NULL) { -+ if (!strncmp(list[i], s, len)) { -+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", -+ modestr, list[i]); -+ return 1; -+ } -+ i++; -+ } -+ return 0; -+} -+ -+/** -+ * hpt366_filter - mode selection filter -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Block UDMA on devices that cause trouble with this controller. -+ */ -+ -+static unsigned int hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ if (adev->class != ATA_DEV_ATA) -+ return mask; -+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) -+ return 0; -+ if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3)) -+ return mask & 0x07; -+ if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) -+ return mask & 0x0F; -+ return mask; -+} -+ -+/** -+ * hpt36x_find_mode - reset the hpt36x bus -+ * @ap: ATA port -+ * @speed: transfer mode -+ * -+ * Return the 32bit register programming information for this channel -+ * that matches the speed provided. -+ */ -+ -+static u32 hpt36x_find_mode(struct ata_port *ap, int speed) -+{ -+ struct hpt_clock *clocks = ap->host_set->private_data; -+ -+ while(clocks->xfer_speed) { -+ if (clocks->xfer_speed == speed) -+ return clocks->timing; -+ clocks++; -+ } -+ BUG(); -+} -+ -+/** -+ * hpt36x_phy_reset - reset the hpt36x bus -+ * @ap: ATA port to reset -+ * -+ * Perform the PHY reset handling for the 366/368 -+ */ -+ -+static void hpt36x_phy_reset(struct ata_port *ap) -+{ -+ u8 scr2, ata66; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_byte(pdev, 0x5A, &ata66); -+ if (ata66 & (1 << ap->hard_port_no)) -+ ap->cbl = ATA_CBL_PATA40; -+ else -+ ap->cbl = ATA_CBL_PATA80; -+ -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * hpt366_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Perform PIO mode setup. -+ */ -+ -+static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ if (fast & 0x80) { -+ fast &= ~0x80; -+ pci_write_config_byte(pdev, addr2, fast); -+ } -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt36x_find_mode(ap, adev->pio_mode); -+ mode &= ~0x8000000; /* No FIFO in PIO */ -+ mode &= ~0x30070000; /* Leave config bits alone */ -+ reg &= 0x30070000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt366_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * Set up the channel for MWDMA or UDMA modes. Much the same as with -+ * PIO, load the mode number and then set MWDMA or UDMA flag. -+ */ -+ -+static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ if (fast & 0x80) { -+ fast &= ~0x80; -+ pci_write_config_byte(pdev, addr2, fast); -+ } -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt36x_find_mode(ap, adev->dma_mode); -+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -+ mode &= ~0xC0000000; /* Leave config bits alone */ -+ reg &= 0xC0000000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+static struct scsi_host_template hpt36x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+/* -+ * Configuration for HPT366/68 -+ */ -+ -+static struct ata_port_operations hpt366_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt366_set_piomode, -+ .set_dmamode = hpt366_set_dmamode, -+ .mode_filter = hpt366_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt36x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * hpt36x_init_one - Initialise an HPT366/368 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Initialise an HPT36x device. There are some interesting complications -+ * here. Firstly the chip may report 366 and be one of several variants. -+ * Secondly all the timings depend on the clock for the chip which we must -+ * detect and look up -+ * -+ * This is the known chip mappings. It may be missing a couple of later -+ * releases. -+ * -+ * Chip version PCI Rev Notes -+ * HPT366 4 (HPT366) 0 UDMA66 -+ * HPT366 4 (HPT366) 1 UDMA66 -+ * HPT368 4 (HPT366) 2 UDMA66 -+ * HPT37x/30x 4 (HPT366) 3+ Other driver -+ * -+ */ -+ -+static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info_hpt366 = { -+ .sht = &hpt366_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, -+ .port_ops = &hpt370_port_ops -+ }; -+ struct ata_port_info *port_info[2] = {&info_hpt366, &info_hpt366}; -+ -+ u8 irqmask; -+ u32 class_rev; -+ u32 reg1; -+ -+ struct hpt_chip *chip_table; -+ int clock_slot; -+ -+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); -+ class_rev &= 0xFF; -+ -+ /* May be a later chip in disguise. Check */ -+ /* Newer chips are in the HPT36x driver. Ignore them */ -+ if (class_rev > 2) -+ return -ENODEV; -+ -+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); -+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); -+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); -+ -+ pci_read_config_byte(dev, 0x51, &drive_fast); -+ if (drive_fast & 0x80) -+ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); -+ -+ pci_read_config_dword(dev, 0x40, ®1); -+ -+ /* PCI clocking determines the ATA timing values to use */ -+ switch((reg1 & 0x700) { -+ case 5: -+ port->private_data = hpt366_40; -+ break; -+ case 9: -+ port->private_data = hpt366_25; -+ break; -+ default: -+ port->private_data = hpt366_33; -+ break; -+ } -+ port_info[0] = port_info[1] = port; -+ /* Now kick off ATA set up */ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id hpt36x[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, -+ { 0, }, -+}; -+ -+static struct pci_driver hpt36x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = hpt36x, -+ .probe = hpt36x_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init hpt36x_init(void) -+{ -+ return pci_register_driver(&hpt36x_pci_driver); -+} -+ -+ -+static void __exit hpt36x_exit(void) -+{ -+ pci_unregister_driver(&hpt36x_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, hpt36x); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(hpt36x_init); -+module_exit(hpt36x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt37x.c linux-2.6.16-rc4/drivers/scsi/pata_hpt37x.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt37x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_hpt37x.c 2006-02-16 15:45:27.000000000 +0000 -@@ -0,0 +1,1232 @@ -+/* -+ * Libata driver for the highpoint 37x and 30x UDMA66 ATA controllers. -+ * -+ * This driver is heavily based upon: -+ * -+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 -+ * -+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> -+ * Portions Copyright (C) 2001 Sun Microsystems, Inc. -+ * Portions Copyright (C) 2003 Red Hat Inc -+ * -+ * TODO -+ * PLL mode -+ * Look into engine reset on timeout errors. Should not be -+ * required. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "hpt37x" -+#define DRV_VERSION "0.2" -+ -+struct hpt_clock { -+ u8 xfer_speed; -+ u32 timing; -+}; -+ -+struct hpt_chip { -+ const char *name; -+ unsigned int base; -+ struct hpt_clock *clocks[4]; -+}; -+ -+/* key for bus clock timings -+ * bit -+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file -+ * register access. -+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file -+ * register access. -+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer. -+ * during task file register access. -+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA -+ * xfer. -+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task -+ * register access. -+ * 28 UDMA enable -+ * 29 DMA enable -+ * 30 PIO_MST enable. if set, the chip is in bus master mode during -+ * PIO. -+ * 31 FIFO enable. -+ */ -+ -+/* from highpoint documentation. these are old values */ -+static struct hpt_clock hpt370_timings_33[] = { -+/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */ -+ { XFER_UDMA_5, 0x16454e31 }, -+ { XFER_UDMA_4, 0x16454e31 }, -+ { XFER_UDMA_3, 0x166d4e31 }, -+ { XFER_UDMA_2, 0x16494e31 }, -+ { XFER_UDMA_1, 0x164d4e31 }, -+ { XFER_UDMA_0, 0x16514e31 }, -+ -+ { XFER_MW_DMA_2, 0x26514e21 }, -+ { XFER_MW_DMA_1, 0x26514e33 }, -+ { XFER_MW_DMA_0, 0x26514e97 }, -+ -+ { XFER_PIO_4, 0x06514e21 }, -+ { XFER_PIO_3, 0x06514e22 }, -+ { XFER_PIO_2, 0x06514e33 }, -+ { XFER_PIO_1, 0x06914e43 }, -+ { XFER_PIO_0, 0x06914e57 }, -+ { 0, 0x06514e57 } -+}; -+ -+static struct hpt_clock hpt370_timings_66[] = { -+ { XFER_UDMA_5, 0x14846231 }, -+ { XFER_UDMA_4, 0x14886231 }, -+ { XFER_UDMA_3, 0x148c6231 }, -+ { XFER_UDMA_2, 0x148c6231 }, -+ { XFER_UDMA_1, 0x14906231 }, -+ { XFER_UDMA_0, 0x14986231 }, -+ -+ { XFER_MW_DMA_2, 0x26514e21 }, -+ { XFER_MW_DMA_1, 0x26514e33 }, -+ { XFER_MW_DMA_0, 0x26514e97 }, -+ -+ { XFER_PIO_4, 0x06514e21 }, -+ { XFER_PIO_3, 0x06514e22 }, -+ { XFER_PIO_2, 0x06514e33 }, -+ { XFER_PIO_1, 0x06914e43 }, -+ { XFER_PIO_0, 0x06914e57 }, -+ { 0, 0x06514e57 } -+}; -+ -+/* these are the current (4 sep 2001) timings from highpoint */ -+static struct hpt_clock hpt370a_timings_33[] = { -+ { XFER_UDMA_5, 0x12446231 }, -+ { XFER_UDMA_4, 0x12446231 }, -+ { XFER_UDMA_3, 0x126c6231 }, -+ { XFER_UDMA_2, 0x12486231 }, -+ { XFER_UDMA_1, 0x124c6233 }, -+ { XFER_UDMA_0, 0x12506297 }, -+ -+ { XFER_MW_DMA_2, 0x22406c31 }, -+ { XFER_MW_DMA_1, 0x22406c33 }, -+ { XFER_MW_DMA_0, 0x22406c97 }, -+ -+ { XFER_PIO_4, 0x06414e31 }, -+ { XFER_PIO_3, 0x06414e42 }, -+ { XFER_PIO_2, 0x06414e53 }, -+ { XFER_PIO_1, 0x06814e93 }, -+ { XFER_PIO_0, 0x06814ea7 }, -+ { 0, 0x06814ea7 } -+}; -+ -+/* 2x 33MHz timings */ -+static struct hpt_clock hpt370a_timings_66[] = { -+ { XFER_UDMA_5, 0x1488e673 }, -+ { XFER_UDMA_4, 0x1488e673 }, -+ { XFER_UDMA_3, 0x1498e673 }, -+ { XFER_UDMA_2, 0x1490e673 }, -+ { XFER_UDMA_1, 0x1498e677 }, -+ { XFER_UDMA_0, 0x14a0e73f }, -+ -+ { XFER_MW_DMA_2, 0x2480fa73 }, -+ { XFER_MW_DMA_1, 0x2480fa77 }, -+ { XFER_MW_DMA_0, 0x2480fb3f }, -+ -+ { XFER_PIO_4, 0x0c82be73 }, -+ { XFER_PIO_3, 0x0c82be95 }, -+ { XFER_PIO_2, 0x0c82beb7 }, -+ { XFER_PIO_1, 0x0d02bf37 }, -+ { XFER_PIO_0, 0x0d02bf5f }, -+ { 0, 0x0d02bf5f } -+}; -+ -+static struct hpt_clock hpt370a_timings_50[] = { -+ { XFER_UDMA_5, 0x12848242 }, -+ { XFER_UDMA_4, 0x12ac8242 }, -+ { XFER_UDMA_3, 0x128c8242 }, -+ { XFER_UDMA_2, 0x120c8242 }, -+ { XFER_UDMA_1, 0x12148254 }, -+ { XFER_UDMA_0, 0x121882ea }, -+ -+ { XFER_MW_DMA_2, 0x22808242 }, -+ { XFER_MW_DMA_1, 0x22808254 }, -+ { XFER_MW_DMA_0, 0x228082ea }, -+ -+ { XFER_PIO_4, 0x0a81f442 }, -+ { XFER_PIO_3, 0x0a81f443 }, -+ { XFER_PIO_2, 0x0a81f454 }, -+ { XFER_PIO_1, 0x0ac1f465 }, -+ { XFER_PIO_0, 0x0ac1f48a }, -+ { 0, 0x0ac1f48a } -+}; -+ -+static struct hpt_clock hpt372_timings_33[] = { -+ { XFER_UDMA_6, 0x1c81dc62 }, -+ { XFER_UDMA_5, 0x1c6ddc62 }, -+ { XFER_UDMA_4, 0x1c8ddc62 }, -+ { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */ -+ { XFER_UDMA_2, 0x1c91dc62 }, -+ { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */ -+ { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */ -+ -+ { XFER_MW_DMA_2, 0x2c829262 }, -+ { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */ -+ { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */ -+ -+ { XFER_PIO_4, 0x0c829c62 }, -+ { XFER_PIO_3, 0x0c829c84 }, -+ { XFER_PIO_2, 0x0c829ca6 }, -+ { XFER_PIO_1, 0x0d029d26 }, -+ { XFER_PIO_0, 0x0d029d5e }, -+ { 0, 0x0d029d5e } -+}; -+ -+static struct hpt_clock hpt372_timings_50[] = { -+ { XFER_UDMA_5, 0x12848242 }, -+ { XFER_UDMA_4, 0x12ac8242 }, -+ { XFER_UDMA_3, 0x128c8242 }, -+ { XFER_UDMA_2, 0x120c8242 }, -+ { XFER_UDMA_1, 0x12148254 }, -+ { XFER_UDMA_0, 0x121882ea }, -+ -+ { XFER_MW_DMA_2, 0x22808242 }, -+ { XFER_MW_DMA_1, 0x22808254 }, -+ { XFER_MW_DMA_0, 0x228082ea }, -+ -+ { XFER_PIO_4, 0x0a81f442 }, -+ { XFER_PIO_3, 0x0a81f443 }, -+ { XFER_PIO_2, 0x0a81f454 }, -+ { XFER_PIO_1, 0x0ac1f465 }, -+ { XFER_PIO_0, 0x0ac1f48a }, -+ { 0, 0x0a81f443 } -+}; -+ -+static struct hpt_clock hpt372_timings_66[] = { -+ { XFER_UDMA_6, 0x1c869c62 }, -+ { XFER_UDMA_5, 0x1cae9c62 }, -+ { XFER_UDMA_4, 0x1c8a9c62 }, -+ { XFER_UDMA_3, 0x1c8e9c62 }, -+ { XFER_UDMA_2, 0x1c929c62 }, -+ { XFER_UDMA_1, 0x1c9a9c62 }, -+ { XFER_UDMA_0, 0x1c829c62 }, -+ -+ { XFER_MW_DMA_2, 0x2c829c62 }, -+ { XFER_MW_DMA_1, 0x2c829c66 }, -+ { XFER_MW_DMA_0, 0x2c829d2e }, -+ -+ { XFER_PIO_4, 0x0c829c62 }, -+ { XFER_PIO_3, 0x0c829c84 }, -+ { XFER_PIO_2, 0x0c829ca6 }, -+ { XFER_PIO_1, 0x0d029d26 }, -+ { XFER_PIO_0, 0x0d029d5e }, -+ { 0, 0x0d029d26 } -+}; -+ -+static struct hpt_clock hpt374_timings_33[] = { -+ { XFER_UDMA_6, 0x12808242 }, -+ { XFER_UDMA_5, 0x12848242 }, -+ { XFER_UDMA_4, 0x12ac8242 }, -+ { XFER_UDMA_3, 0x128c8242 }, -+ { XFER_UDMA_2, 0x120c8242 }, -+ { XFER_UDMA_1, 0x12148254 }, -+ { XFER_UDMA_0, 0x121882ea }, -+ -+ { XFER_MW_DMA_2, 0x22808242 }, -+ { XFER_MW_DMA_1, 0x22808254 }, -+ { XFER_MW_DMA_0, 0x228082ea }, -+ -+ { XFER_PIO_4, 0x0a81f442 }, -+ { XFER_PIO_3, 0x0a81f443 }, -+ { XFER_PIO_2, 0x0a81f454 }, -+ { XFER_PIO_1, 0x0ac1f465 }, -+ { XFER_PIO_0, 0x0ac1f48a }, -+ { 0, 0x06814e93 } -+}; -+ -+static struct hpt_chip hpt370 = { -+ "HPT370", -+ 48, -+ { -+ hpt370_timings_33, -+ NULL, -+ NULL, -+ hpt370_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt370a = { -+ "HPT370A", -+ 48, -+ { -+ hpt370a_timings_33, -+ NULL, -+ hpt370a_timings_50, -+ hpt370a_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt372 = { -+ "HPT372", -+ 55, -+ { -+ hpt372_timings_33, -+ NULL, -+ hpt372_timings_50, -+ hpt372_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt302 = { -+ "HPT302", -+ 66, -+ { -+ hpt372_timings_33, -+ NULL, -+ hpt372_timings_50, -+ hpt372_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt371 = { -+ "HPT371", -+ 66, -+ { -+ hpt372_timings_33, -+ NULL, -+ hpt372_timings_50, -+ hpt372_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt372a = { -+ "HPT372A", -+ 66, -+ { -+ hpt372_timings_33, -+ NULL, -+ hpt372_timings_50, -+ hpt372_timings_66 -+ } -+}; -+ -+static struct hpt_chip hpt374 = { -+ "HPT374", -+ 48, -+ { -+ hpt374_timings_33, -+ NULL, -+ NULL, -+ NULL -+ } -+}; -+ -+/** -+ * hpt37x_find_mode - reset the hpt37x bus -+ * @ap: ATA port -+ * @speed: transfer mode -+ * -+ * Return the 32bit register programming information for this channel -+ * that matches the speed provided. -+ */ -+ -+static u32 hpt37x_find_mode(struct ata_port *ap, int speed) -+{ -+ struct hpt_clock *clocks = ap->host_set->private_data; -+ -+ while(clocks->xfer_speed) { -+ if (clocks->xfer_speed == speed) -+ return clocks->timing; -+ clocks++; -+ } -+ BUG(); -+} -+ -+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) -+{ -+ unsigned char model_num[40]; -+ char *s; -+ unsigned int len; -+ int i = 0; -+ -+ ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS, -+ sizeof(model_num)); -+ s = &model_num[0]; -+ len = strnlen(s, sizeof(model_num)); -+ -+ /* ATAPI specifies that empty space is blank-filled; remove blanks */ -+ while ((len > 0) && (s[len - 1] == ' ')) { -+ len--; -+ s[len] = 0; -+ } -+ -+ while(list[i] != NULL) { -+ if (!strncmp(list[i], s, len)) { -+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n", -+ modestr, list[i]); -+ return 1; -+ } -+ i++; -+ } -+ return 0; -+} -+ -+static const char *bad_ata33[] = { -+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", -+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", -+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", -+ "Maxtor 90510D4", -+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", -+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", -+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", -+ NULL -+}; -+ -+static const char *bad_ata100_5[] = { -+ "IBM-DTLA-307075", -+ "IBM-DTLA-307060", -+ "IBM-DTLA-307045", -+ "IBM-DTLA-307030", -+ "IBM-DTLA-307020", -+ "IBM-DTLA-307015", -+ "IBM-DTLA-305040", -+ "IBM-DTLA-305030", -+ "IBM-DTLA-305020", -+ "IC35L010AVER07-0", -+ "IC35L020AVER07-0", -+ "IC35L030AVER07-0", -+ "IC35L040AVER07-0", -+ "IC35L060AVER07-0", -+ "WDC AC310200R", -+ NULL -+}; -+ -+/** -+ * hpt370_filter - mode selection filter -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Block UDMA on devices that cause trouble with this controller. -+ */ -+ -+static unsigned int hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ if (adev->class != ATA_DEV_ATA) -+ return mask; -+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) -+ return mask & 0x1F; -+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) -+ return mask & 0x1F; -+ return mask; -+} -+ -+/** -+ * hpt370a_filter - mode selection filter -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Block UDMA on devices that cause trouble with this controller. -+ */ -+ -+static unsigned int hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ if (adev->class != ATA_DEV_ATA) -+ return mask; -+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) -+ return mask & 0x1F; -+ return mask; -+} -+ -+/** -+ * hpt37x_phy_reset - reset the hpt37x bus -+ * @ap: ATA port to reset -+ * -+ * Perform the PHY reset handling for the 370/372 and 374 func 0 -+ */ -+ -+static void hpt37x_phy_reset(struct ata_port *ap) -+{ -+ u8 scr2, ata66; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_byte(pdev, 0x5B, &scr2); -+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01); -+ /* Cable register now active */ -+ pci_read_config_byte(pdev, 0x5A, &ata66); -+ /* Restore state */ -+ pci_write_config_byte(pdev, 0x5B, scr2); -+ -+ if (ata66 & (1 << ap->hard_port_no)) -+ ap->cbl = ATA_CBL_PATA40; -+ else -+ ap->cbl = ATA_CBL_PATA80; -+ -+ /* Reset the state machine */ -+ pci_write_config_byte(pdev, 0x50, 0x37); -+ pci_write_config_byte(pdev, 0x54, 0x37); -+ udelay(100); -+ -+ printk("BUS RESET\n"); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * hpt374_phy_reset - reset the hpt374 -+ * @ap: ATA port to reset -+ * -+ * The 374 cable detect is a little different due to the extra -+ * channels. The function 0 channels work like usual but function 1 -+ * is special -+ */ -+ -+static void hpt374_phy_reset(struct ata_port *ap) -+{ -+ u16 mcr3, mcr6; -+ u8 ata66; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ if (!(PCI_FUNC(pdev->devfn) & 1)) { -+ hpt37x_phy_reset(ap); -+ return; -+ } -+ /* Do the extra channel work */ -+ pci_read_config_word(pdev, 0x52, &mcr3); -+ pci_read_config_word(pdev, 0x56, &mcr6); -+ /* Set bit 15 of 0x52 to enable TCBLID as input -+ Set bit 15 of 0x56 to enable FCBLID as input -+ */ -+ pci_write_config_word(pdev, 0x52, mcr3 | 0x8000); -+ pci_write_config_word(pdev, 0x56, mcr6 | 0x8000); -+ pci_read_config_byte(pdev, 0x5A, &ata66); -+ /* Reset TCBLID/FCBLID to output */ -+ pci_write_config_word(pdev, 0x52, mcr3); -+ pci_write_config_word(pdev, 0x56, mcr6); -+ -+ if (ata66 & (1 << ap->hard_port_no)) -+ ap->cbl = ATA_CBL_PATA40; -+ else -+ ap->cbl = ATA_CBL_PATA80; -+ -+ /* Reset the state machine */ -+ pci_write_config_byte(pdev, 0x50, 0x37); -+ pci_write_config_byte(pdev, 0x54, 0x37); -+ udelay(100); -+ -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+ -+/** -+ * hpt370_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Perform PIO mode setup. -+ */ -+ -+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x02; -+ fast |= 0x01; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt37x_find_mode(ap, adev->pio_mode); -+ mode &= ~0x8000000; /* No FIFO in PIO */ -+ mode &= ~0x30070000; /* Leave config bits alone */ -+ reg &= 0x30070000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt370_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * Set up the channel for MWDMA or UDMA modes. Much the same as with -+ * PIO, load the mode number and then set MWDMA or UDMA flag. -+ */ -+ -+static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x02; -+ fast |= 0x01; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt37x_find_mode(ap, adev->dma_mode); -+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -+ mode &= ~0xC0000000; /* Leave config bits alone */ -+ reg &= 0xC0000000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt370_bmdma_start - DMA engine begin -+ * @qc: ATA command -+ * -+ * The 370 and 370A want us to reset the DMA engine each time we -+ * use it. The 372 and later are fine. -+ */ -+ -+static void hpt370_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ pci_write_config_byte(pdev, 0x50 + 4 * ap->hard_port_no, 0x37); -+ udelay(10); -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * hpt370_bmdma_end - DMA engine stop -+ * @qc: ATA command -+ * -+ * Work around the HPT370 DMA engine. -+ */ -+ -+static void hpt370_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2); -+ u8 dma_cmd; -+ unsigned long bmdma = ap->ioaddr.bmdma_addr; -+ -+ if (dma_stat & 0x01) { -+ udelay(20); -+ dma_stat = inb(bmdma + 2); -+ } -+ if (dma_stat & 0x01) { -+ /* Clear the engine */ -+ pci_write_config_byte(pdev, 0x50 + 4 * ap->hard_port_no, 0x37); -+ udelay(10); -+ /* Stop DMA */ -+ dma_cmd = inb(bmdma ); -+ outb(dma_cmd & 0xFE, bmdma); -+ /* Clear Error */ -+ dma_stat = inb(bmdma + 2); -+ outb(dma_stat | 0x06 , bmdma + 2); -+ /* Clear the engine */ -+ pci_write_config_byte(pdev, 0x50 + 4 * ap->hard_port_no, 0x37); -+ udelay(10); -+ } -+ ata_bmdma_stop(qc); -+} -+ -+/** -+ * hpt372_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Perform PIO mode setup. -+ */ -+ -+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x07; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt37x_find_mode(ap, adev->pio_mode); -+ -+ printk("Find mode for %d reports %X\n", adev->pio_mode, mode); -+ mode &= ~0x8000000; /* No FIFO in PIO */ -+ mode &= ~0x30070000; /* Leave config bits alone */ -+ reg &= 0x30070000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt372_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * Set up the channel for MWDMA or UDMA modes. Much the same as with -+ * PIO, load the mode number and then set MWDMA or UDMA flag. -+ */ -+ -+static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x07; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt37x_find_mode(ap, adev->dma_mode); -+ printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode); -+ mode &= ~0xC0000000; /* Leave config bits alone */ -+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -+ reg &= 0xC0000000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt37x_bmdma_end - DMA engine stop -+ * @qc: ATA command -+ * -+ * Clean up after the HPT372 and later DMA engine -+ */ -+ -+static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int mscreg = 0x50 + 2 * ap->hard_port_no; -+ u8 bwsr_stat, msc_stat; -+ -+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat); -+ pci_read_config_byte(pdev, mscreg, &msc_stat); -+ if (bwsr_stat & (1 << ap->hard_port_no)) -+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30); -+ ata_bmdma_stop(qc); -+} -+ -+ -+static struct scsi_host_template hpt37x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+/* -+ * Configuration for HPT370 -+ */ -+ -+static struct ata_port_operations hpt370_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt370_set_piomode, -+ .set_dmamode = hpt370_set_dmamode, -+ .mode_filter = hpt370_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt37x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = hpt370_bmdma_start, -+ .bmdma_stop = hpt370_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Configuration for HPT370A. Close to 370 but less filters -+ */ -+ -+static struct ata_port_operations hpt370a_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt370_set_piomode, -+ .set_dmamode = hpt370_set_dmamode, -+ .mode_filter = hpt370a_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt37x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = hpt370_bmdma_start, -+ .bmdma_stop = hpt370_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Configuration for HPT372, HPT371, HPT302. Slightly different PIO -+ * and DMA mode setting functionality. -+ */ -+ -+static struct ata_port_operations hpt372_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt372_set_piomode, -+ .set_dmamode = hpt372_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt37x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = hpt37x_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Configuration for HPT374. Mode setting works like 372 and friends -+ * but we have a different cable detection procedure. -+ */ -+ -+static struct ata_port_operations hpt374_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt372_set_piomode, -+ .set_dmamode = hpt372_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt374_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = hpt37x_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * htp37x_clock_slot - Turn timing to PC clock entry -+ * @freq: Reported frequency timing -+ * @base: Base timing -+ * -+ * Turn the timing data intoa clock slot (0 for 33, 1 for 40, 2 for 50 -+ * and 3 for 66Mhz) -+ */ -+ -+static int hpt37x_clock_slot(unsigned int freq, unsigned int base) -+{ -+ unsigned int f = (base * freq) / 192; /* Mhz */ -+ if (f < 40) -+ return 0; /* 33Mhz slot */ -+ if (f < 45) -+ return 1; /* 40Mhz slot */ -+ if (f < 55) -+ return 2; /* 50Mhz slot */ -+ return 3; /* 60Mhz slot */ -+} -+ -+/** -+ * hpt37x_calibrate_dpll - Calibrate the DPLL loop -+ * @dev: PCI device -+ * -+ * Perform a calibration cycle on the HPT37x DPLL. Returns 1 if this -+ * succeeds -+ */ -+ -+static int hpt37x_calibrate_dpll(struct pci_dev *dev) -+{ -+ u8 reg5b; -+ u32 reg5c; -+ int tries; -+ -+ for(tries = 0; tries < 0x5000; tries++) { -+ udelay(50); -+ pci_read_config_byte(dev, 0x5b, ®5b); -+ if (reg5b & 0x80) { -+ /* See if it stays set */ -+ for(tries = 0; tries < 0x1000; tries ++) { -+ pci_read_config_byte(dev, 0x5b, ®5b); -+ /* Failed ? */ -+ if ((reg5b & 0x80) == 0) -+ return 0; -+ } -+ /* Turn off tuning, we have the DPLL set */ -+ pci_read_config_dword(dev, 0x5c, ®5c); -+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100); -+ return 1; -+ } -+ } -+ /* Never went stable */ -+ return 0; -+} -+/** -+ * hpt37x_init_one - Initialise an HPT37X/302 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Initialise an HPT37x device. There are some interesting complications -+ * here. Firstly the chip may report 366 and be one of several variants. -+ * Secondly all the timings depend on the clock for the chip which we must -+ * detect and look up -+ * -+ * This is the known chip mappings. It may be missing a couple of later -+ * releases. -+ * -+ * Chip version PCI Rev Notes -+ * HPT366 4 (HPT366) 0 Other driver -+ * HPT366 4 (HPT366) 1 Other driver -+ * HPT368 4 (HPT366) 2 Other driver -+ * HPT370 4 (HPT366) 3 UDMA100 -+ * HPT370A 4 (HPT366) 4 UDMA100 -+ * HPT372 4 (HPT366) 5 UDMA133 (1) -+ * HPT372N 4 (HPT366) 6 Other driver -+ * HPT372A 5 (HPT372) 1 UDMA133 (1) -+ * HPT372N 5 (HPT372) 2 Other driver -+ * HPT302 6 (HPT302) 1 UDMA133 -+ * HPT302N 6 (HPT302) 2 Other driver -+ * HPT371 7 (HPT371) * UDMA133 -+ * HPT374 8 (HPT374) * UDMA133 4 channel -+ * HPT372N 9 (HPT372N) * Other driver -+ * -+ * (1) UDMA133 support depends on the bus clock -+ */ -+ -+static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ /* HPT370 - UDMA100 */ -+ static struct ata_port_info info_hpt370 = { -+ .sht = &hpt37x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &hpt370_port_ops -+ }; -+ /* HPT370A - UDMA100 */ -+ static struct ata_port_info info_hpt370a = { -+ .sht = &hpt37x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &hpt370a_port_ops -+ }; -+ /* HPT371, 372 and friends - UDMA133 */ -+ static struct ata_port_info info_hpt372 = { -+ .sht = &hpt37x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &hpt372_port_ops -+ }; -+ /* HPT371, 372 and friends - UDMA100 at 50MHz clock */ -+ static struct ata_port_info info_hpt372_50 = { -+ .sht = &hpt37x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &hpt372_port_ops -+ }; -+ /* HPT374 - UDMA133 */ -+ static struct ata_port_info info_hpt374 = { -+ .sht = &hpt37x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &hpt374_port_ops -+ }; -+ -+ struct ata_port_info *port_info[2]; -+ struct ata_port_info *port; -+ -+ u8 irqmask; -+ u32 class_rev; -+ u32 freq; -+ -+ int MHz[4] = { 33, 40, 50, 66 }; -+ struct hpt_chip *chip_table; -+ int clock_slot; -+ -+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); -+ class_rev &= 0xFF; -+ -+ if (dev->device == PCI_DEVICE_ID_TTI_HPT366) { -+ /* May be a later chip in disguise. Check */ -+ /* Older chips are in the HPT366 driver. Ignore them */ -+ if (class_rev < 3) -+ return -ENODEV; -+ /* N series chips have their own driver. Ignore */ -+ if (class_rev == 6) -+ return -ENODEV; -+ -+ switch(class_rev) { -+ case 3: -+ port = &info_hpt370; -+ chip_table = &hpt370; -+ break; -+ case 4: -+ port = &info_hpt370a; -+ chip_table = &hpt370a; -+ break; -+ case 5: -+ port = &info_hpt372; -+ chip_table = &hpt372; -+ break; -+ default: -+ printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev); -+ return -ENODEV; -+ } -+ } else { -+ switch(dev->device) { -+ case PCI_DEVICE_ID_TTI_HPT372: -+ /* 372N if rev >= 2*/ -+ if (class_rev >= 2) -+ return -ENODEV; -+ port = &info_hpt372; -+ chip_table = &hpt372a; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT302: -+ /* 302N if rev > 1 */ -+ if (class_rev > 1) -+ return -ENODEV; -+ port = &info_hpt372; -+ /* Check this */ -+ chip_table = &hpt302; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT371: -+ port = &info_hpt372; -+ chip_table = &hpt371; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT374: -+ chip_table = &hpt374; -+ port = &info_hpt374; -+ break; -+ default: -+ printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device); -+ return -ENODEV; -+ } -+ } -+ /* Ok so this is a chip we support */ -+ -+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); -+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); -+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); -+ -+ pci_read_config_byte(dev, 0x5A, &irqmask); -+ irqmask &= ~0x10; -+ pci_write_config_byte(dev, 0x5a, irqmask); -+ -+ /* -+ * default to pci clock. make sure MA15/16 are set to output -+ * to prevent drives having problems with 40-pin cables. Needed -+ * for some drives such as IBM-DTLA which will not enter ready -+ * state on reset when PDIAG is a input. -+ */ -+ -+ pci_write_config_byte(dev, 0x5b, 0x23); -+ -+ pci_read_config_dword(dev, 0x70, &freq); -+ if ((freq >> 12) != 0xABCDE) { -+ int i; -+ u8 sr; -+ u32 total = 0; -+ -+ printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n"); -+ -+ /* This is the process the HPT371 BIOS is reported to use */ -+ for(i = 0; i < 128; i++) { -+ pci_read_config_byte(dev, 0x78, &sr); -+ total += sr; -+ udelay(15); -+ } -+ freq = total / 128; -+ } -+ freq &= 0x1FF; -+ -+ /* -+ * Turn the frequency check into a band and then find a timing -+ * table to match it. -+ */ -+ -+ clock_slot = hpt37x_clock_slot(freq, chip_table->base); -+ if (chip_table->clocks[clock_slot] == NULL) { -+ /* -+ * We need to try PLL mode instead -+ */ -+ unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192; -+ unsigned int f_high = f_low + 2; -+ int adjust; -+ -+ for(adjust = 0; adjust < 8; adjust++) { -+ if (hpt37x_calibrate_dpll(dev)) -+ break; -+ /* See if it'll settle at a fractionally different clock */ -+ if ((adjust & 3) == 3) { -+ f_low --; -+ f_high ++; -+ } -+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); -+ } -+ if (adjust == 8) { -+ printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n"); -+ return -ENODEV; -+ } -+ /* Check if this works for all cases */ -+ port->private_data = hpt370_timings_66; -+ -+ printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]); -+ } else { -+ port->private_data = chip_table->clocks[clock_slot]; -+ /* -+ * Perform a final fixup. The 371 and 372 clock determines -+ * if UDMA133 is available. -+ */ -+ -+ if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */ -+ printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n"); -+ if (port == &info_hpt372) -+ port = &info_hpt372_50; -+ else BUG(); -+ } -+ printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]); -+ } -+ port_info[0] = port_info[1] = port; -+ /* Now kick off ATA set up */ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id hpt37x[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), }, -+ { 0, }, -+}; -+ -+static struct pci_driver hpt37x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = hpt37x, -+ .probe = hpt37x_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init hpt37x_init(void) -+{ -+ return pci_register_driver(&hpt37x_pci_driver); -+} -+ -+ -+static void __exit hpt37x_exit(void) -+{ -+ pci_unregister_driver(&hpt37x_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, hpt37x); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(hpt37x_init); -+module_exit(hpt37x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt3x2n.c linux-2.6.16-rc4/drivers/scsi/pata_hpt3x2n.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_hpt3x2n.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_hpt3x2n.c 2006-02-16 15:36:58.000000000 +0000 -@@ -0,0 +1,580 @@ -+/* -+ * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers. -+ * -+ * This driver is heavily based upon: -+ * -+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 -+ * -+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> -+ * Portions Copyright (C) 2001 Sun Microsystems, Inc. -+ * Portions Copyright (C) 2003 Red Hat Inc -+ * -+ * -+ * TODO -+ * 371N -+ * Work out best PLL policy -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "hpt3x2n" -+#define DRV_VERSION "0.1" -+ -+enum { -+ HPT_PCI_FAST = (1 << 31), -+ PCI66 = (1 << 1), -+ USE_DPLL = (1 << 0) -+}; -+ -+struct hpt_clock { -+ u8 xfer_speed; -+ u32 timing; -+}; -+ -+struct hpt_chip { -+ const char *name; -+ struct hpt_clock *clocks[3]; -+}; -+ -+/* key for bus clock timings -+ * bit -+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW -+ * DMA. cycles = value + 1 -+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file -+ * register access. -+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file -+ * register access. -+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer. -+ * during task file register access. -+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA -+ * xfer. -+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task -+ * register access. -+ * 28 UDMA enable -+ * 29 DMA enable -+ * 30 PIO_MST enable. if set, the chip is in bus master mode during -+ * PIO. -+ * 31 FIFO enable. -+ */ -+ -+/* 66MHz DPLL clocks */ -+ -+static struct hpt_clock hpt3x2n_clocks[] = { -+ { XFER_UDMA_7, 0x1c869c62 }, -+ { XFER_UDMA_6, 0x1c869c62 }, -+ { XFER_UDMA_5, 0x1c8a9c62 }, -+ { XFER_UDMA_4, 0x1c8a9c62 }, -+ { XFER_UDMA_3, 0x1c8e9c62 }, -+ { XFER_UDMA_2, 0x1c929c62 }, -+ { XFER_UDMA_1, 0x1c9a9c62 }, -+ { XFER_UDMA_0, 0x1c829c62 }, -+ -+ { XFER_MW_DMA_2, 0x2c829c62 }, -+ { XFER_MW_DMA_1, 0x2c829c66 }, -+ { XFER_MW_DMA_0, 0x2c829d2c }, -+ -+ { XFER_PIO_4, 0x0c829c62 }, -+ { XFER_PIO_3, 0x0c829c84 }, -+ { XFER_PIO_2, 0x0c829ca6 }, -+ { XFER_PIO_1, 0x0d029d26 }, -+ { XFER_PIO_0, 0x0d029d5e }, -+ { 0, 0x0d029d5e } -+}; -+ -+/** -+ * hpt3x2n_find_mode - reset the hpt3x2n bus -+ * @ap: ATA port -+ * @speed: transfer mode -+ * -+ * Return the 32bit register programming information for this channel -+ * that matches the speed provided. For the moment the clocks table -+ * is hard coded but easy to change. This will be needed if we use -+ * different DPLLs -+ */ -+ -+static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) -+{ -+ struct hpt_clock *clocks = hpt3x2n_clocks; -+ -+ while(clocks->xfer_speed) { -+ if (clocks->xfer_speed == speed) -+ return clocks->timing; -+ clocks++; -+ } -+ BUG(); -+} -+ -+/** -+ * hpt3x2n_phy_reset - reset the hpt3x2n bus -+ * @ap: ATA port to reset -+ * -+ * Perform the PHY reset handling for the 3x2N -+ */ -+ -+static void hpt3x2n_phy_reset(struct ata_port *ap) -+{ -+ u8 scr2, ata66; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_byte(pdev, 0x5B, &scr2); -+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01); -+ /* Cable register now active */ -+ pci_read_config_byte(pdev, 0x5A, &ata66); -+ /* Restore state */ -+ pci_write_config_byte(pdev, 0x5B, scr2); -+ -+ if (ata66 & (1 << ap->hard_port_no)) -+ ap->cbl = ATA_CBL_PATA40; -+ else -+ ap->cbl = ATA_CBL_PATA80; -+ -+ /* Reset the state machine */ -+ pci_write_config_byte(pdev, 0x50, 0x37); -+ pci_write_config_byte(pdev, 0x54, 0x37); -+ udelay(100); -+ -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+/** -+ * hpt3x2n_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Perform PIO mode setup. -+ */ -+ -+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x07; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt3x2n_find_mode(ap, adev->pio_mode); -+ mode &= ~0x8000000; /* No FIFO in PIO */ -+ mode &= ~0x30070000; /* Leave config bits alone */ -+ reg &= 0x30070000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt3x2n_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * Set up the channel for MWDMA or UDMA modes. Much the same as with -+ * PIO, load the mode number and then set MWDMA or UDMA flag. -+ */ -+ -+static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 addr1, addr2; -+ u32 reg; -+ u32 mode; -+ u8 fast; -+ -+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->hard_port_no); -+ addr2 = 0x51 + 4 * ap->hard_port_no; -+ -+ /* Fast interrupt prediction disable, hold off interrupt disable */ -+ pci_read_config_byte(pdev, addr2, &fast); -+ fast &= ~0x07; -+ pci_write_config_byte(pdev, addr2, fast); -+ -+ pci_read_config_dword(pdev, addr1, ®); -+ mode = hpt3x2n_find_mode(ap, adev->dma_mode); -+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -+ mode &= ~0xC0000000; /* Leave config bits alone */ -+ reg &= 0xC0000000; /* Strip timing bits */ -+ pci_write_config_dword(pdev, addr1, reg | mode); -+} -+ -+/** -+ * hpt3x2n_bmdma_end - DMA engine stop -+ * @qc: ATA command -+ * -+ * Clean up after the HPT3x2n and later DMA engine -+ */ -+ -+static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int mscreg = 0x50 + 2 * ap->hard_port_no; -+ u8 bwsr_stat, msc_stat; -+ -+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat); -+ pci_read_config_byte(pdev, mscreg, &msc_stat); -+ if (bwsr_stat & (1 << ap->hard_port_no)) -+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30); -+ ata_bmdma_stop(qc); -+} -+ -+/** -+ * hpt3x2n_set_clock - clock control -+ * @ap: ATA port -+ * @source: 0x21 or 0x23 for PLL or PCI sourced clock -+ * -+ * Switch the ATA bus clock between the PLL and PCI clock sources -+ * while correctly isolating the bus and resetting internal logic -+ * -+ * We must use the DPLL for -+ * - writing -+ * - second channel UDMA7 (SATA ports) or higher -+ * - 66MHz PCI -+ * -+ * or we will underclock the device and get reduced performance. -+ */ -+ -+static void hpt3x2n_set_clock(struct ata_port *ap, int source) -+{ -+ unsigned long bmdma = ap->ioaddr.bmdma_addr; -+ -+ /* Tristate the bus */ -+ outb(0x80, bmdma+0x73); -+ outb(0x80, bmdma+0x77); -+ -+ /* Switch clock and reset channels */ -+ outb(source, bmdma+0x7B); -+ outb(0xC0, bmdma+0x79); -+ -+ /* Reset state machines */ -+ outb(0x37, bmdma+0x70); -+ outb(0x37, bmdma+0x74); -+ -+ /* Complete reset */ -+ outb(0x00, bmdma+0x79); -+ -+ /* Reconnect channels to bus */ -+ outb(0x00, bmdma+0x73); -+ outb(0x00, bmdma+0x77); -+} -+ -+/* Check if our partner interface is busy */ -+ -+static int hpt3x2n_pair_idle(struct ata_port *ap) -+{ -+ struct ata_host_set *host = ap->host_set; -+ struct ata_port *pair = host->ports[ap->hard_port_no ^ 1]; -+ -+ if (pair->hsm_task_state == HSM_ST_IDLE) -+ return 1; -+ return 0; -+} -+ -+static int hpt3x2n_use_dpll(struct ata_port *ap, int reading) -+{ -+ long flags = (long)ap->host_set->private_data; -+ /* See if we should use the DPLL */ -+ if (reading == 0) -+ return USE_DPLL; /* Needed for write */ -+ if (flags & PCI66) -+ return USE_DPLL; /* Needed at 66Mhz */ -+ return 0; -+} -+ -+static int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_taskfile *tf = &qc->tf; -+ struct ata_port *ap = qc->ap; -+ int flags = (long)ap->host_set->private_data; -+ -+ if (hpt3x2n_pair_idle(ap)) { -+ int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE)); -+ if ((flags & USE_DPLL) != dpll) { -+ if (dpll == 1) -+ hpt3x2n_set_clock(ap, 0x21); -+ else -+ hpt3x2n_set_clock(ap, 0x23); -+ } -+ } -+ return ata_qc_issue_prot(qc); -+} -+ -+static struct scsi_host_template hpt3x2n_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+/* -+ * Configuration for HPT3x2n. -+ */ -+ -+static struct ata_port_operations hpt3x2n_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = hpt3x2n_set_piomode, -+ .set_dmamode = hpt3x2n_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = hpt3x2n_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = hpt3x2n_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = hpt3x2n_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * hpt3xn_calibrate_dpll - Calibrate the DPLL loop -+ * @dev: PCI device -+ * -+ * Perform a calibration cycle on the HPT3xN DPLL. Returns 1 if this -+ * succeeds -+ */ -+ -+static int hpt3xn_calibrate_dpll(struct pci_dev *dev) -+{ -+ u8 reg5b; -+ u32 reg5c; -+ int tries; -+ -+ for(tries = 0; tries < 0x5000; tries++) { -+ udelay(50); -+ pci_read_config_byte(dev, 0x5b, ®5b); -+ if (reg5b & 0x80) { -+ /* See if it stays set */ -+ for(tries = 0; tries < 0x1000; tries ++) { -+ pci_read_config_byte(dev, 0x5b, ®5b); -+ /* Failed ? */ -+ if ((reg5b & 0x80) == 0) -+ return 0; -+ } -+ /* Turn off tuning, we have the DPLL set */ -+ pci_read_config_dword(dev, 0x5c, ®5c); -+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100); -+ return 1; -+ } -+ } -+ /* Never went stable */ -+ return 0; -+} -+ -+static int hpt3x2n_pci_clock(struct pci_dev *pdev) -+{ -+ unsigned long freq; -+ u32 fcnt; -+ -+ pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt); -+ if ((fcnt >> 12) != 0xABCDE) { -+ printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n"); -+ return 33; /* Not BIOS set */ -+ } -+ fcnt &= 0x1FF; -+ -+ freq = (fcnt * 77) / 192; -+ -+ /* Clamp to bands */ -+ if (freq < 40) -+ return 33; -+ if (freq < 45) -+ return 40; -+ if (freq < 55) -+ return 50; -+ return 66; -+} -+ -+/** -+ * hpt3x2n_init_one - Initialise an HPT37X/302 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Initialise an HPT3x2n device. There are some interesting complications -+ * here. Firstly the chip may report 366 and be one of several variants. -+ * Secondly all the timings depend on the clock for the chip which we must -+ * detect and look up -+ * -+ * This is the known chip mappings. It may be missing a couple of later -+ * releases. -+ * -+ * Chip version PCI Rev Notes -+ * HPT372 4 (HPT366) 5 Other driver -+ * HPT372N 4 (HPT366) 6 UDMA133 -+ * HPT372 5 (HPT372) 1 Other driver -+ * HPT372N 5 (HPT372) 2 UDMA133 -+ * HPT302 6 (HPT302) * Other driver -+ * HPT302N 6 (HPT302) > 1 UDMA133 -+ * HPT371 7 (HPT371) * Other driver -+ * HPT371N 7 (HPT371) > 1 UDMA133 -+ * HPT374 8 (HPT374) * Other driver -+ * HPT372N 9 (HPT372N) * UDMA133 -+ * -+ * (1) UDMA133 support depends on the bus clock -+ * -+ * To pin down HPT371N -+ */ -+ -+static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ /* HPT372N and friends - UDMA133 */ -+ static struct ata_port_info info = { -+ .sht = &hpt3x2n_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &hpt3x2n_port_ops -+ }; -+ struct ata_port_info *port_info[2]; -+ struct ata_port_info *port = &info; -+ -+ u8 irqmask; -+ u32 class_rev; -+ -+ unsigned int pci_mhz; -+ unsigned int f_low, f_high; -+ int adjust; -+ -+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); -+ class_rev &= 0xFF; -+ -+ switch(dev->device) { -+ case PCI_DEVICE_ID_TTI_HPT366: -+ if (class_rev < 6) -+ return -ENODEV; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT372: -+ /* 372N if rev >= 1*/ -+ if (class_rev == 0) -+ return -ENODEV; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT302: -+ if (class_rev < 2) -+ return -ENODEV; -+ break; -+ case PCI_DEVICE_ID_TTI_HPT372N: -+ break; -+ default: -+ printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device); -+ return -ENODEV; -+ } -+ -+ /* Ok so this is a chip we support */ -+ -+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); -+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); -+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); -+ -+ pci_read_config_byte(dev, 0x5A, &irqmask); -+ irqmask &= ~0x10; -+ pci_write_config_byte(dev, 0x5a, irqmask); -+ -+ /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or -+ 50 for UDMA100. Right now we always use 66 */ -+ -+ pci_mhz = hpt3x2n_pci_clock(dev); -+ -+ f_low = (pci_mhz * 48) / 66; /* PCI Mhz for 66Mhz DPLL */ -+ f_high = f_low + 2; /* Tolerance */ -+ -+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100); -+ /* PLL clock */ -+ pci_write_config_byte(dev, 0x5B, 0x21); -+ -+ /* Unlike the 37x we don't try jiggling the frequency */ -+ for(adjust = 0; adjust < 8; adjust++) { -+ if (hpt3xn_calibrate_dpll(dev)) -+ break; -+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low); -+ } -+ if (adjust == 8) -+ printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n"); -+ -+ /* Set our private data up. We only need a few flags so we use -+ it directly */ -+ port->private_data = NULL; -+ if (pci_mhz > 60) -+ port->private_data = (void *)PCI66; -+ -+ /* Now kick off ATA set up */ -+ port_info[0] = port_info[1] = port; -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id hpt3x2n[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), }, -+ { 0, }, -+}; -+ -+static struct pci_driver hpt3x2n_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = hpt3x2n, -+ .probe = hpt3x2n_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init hpt3x2n_init(void) -+{ -+ return pci_register_driver(&hpt3x2n_pci_driver); -+} -+ -+ -+static void __exit hpt3x2n_exit(void) -+{ -+ pci_unregister_driver(&hpt3x2n_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, hpt3x2n); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(hpt3x2n_init); -+module_exit(hpt3x2n_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_isapnp.c linux-2.6.16-rc4/drivers/scsi/pata_isapnp.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_isapnp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_isapnp.c 2006-01-21 16:52:31.000000000 +0000 -@@ -0,0 +1,151 @@ -+ -+/* -+ * pata-isapnp.c - ISA PnP PATA controller driver. -+ * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved. -+ * -+ * Based in part on ide-pnp.c by Andrey Panin <pazke@donpac.ru> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/isapnp.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/ata.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_isapnp" -+#define DRV_VERSION "0.1" -+ -+static struct scsi_host_template isapnp_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations isapnp_port_ops = { -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * isapnp_init_one - attach an isapnp interface -+ * @idev: PnP device -+ * @dev_id: matching detect line -+ * -+ * Register an ISA bus IDE interface. Such interfaces are PIO 0 and -+ * non shared IRQ. -+ */ -+ -+static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) -+{ -+ struct ata_probe_ent ae; -+ -+ if (pnp_port_valid(idev, 0) == 0) -+ return -ENODEV; -+ if (pnp_port_valid(idev, 1) == 0) -+ return -ENODEV; -+ -+ /* FIXME: Should selected polled PIO here not fail */ -+ if (pnp_irq_valid(idev, 0) == 0) -+ return -ENODEV; -+ -+ memset(&ae, 0, sizeof(struct ata_probe_ent)); -+ INIT_LIST_HEAD(&ae.node); -+ ae.dev = &idev->dev; -+ ae.port_ops = &isapnp_port_ops; -+ ae.sht = &isapnp_sht; -+ ae.n_ports = 1; -+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */ -+ ae.irq = pnp_irq(idev, 0); -+ ae.irq_flags = 0; -+ ae.host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IRQ_MASK; -+ ae.port[0].cmd_addr = pnp_port_start(idev, 0); -+ ae.port[0].altstatus_addr = pnp_port_start(idev, 1); -+ ae.port[0].ctl_addr = pnp_port_start(idev, 1); -+ ata_std_ports(&ae.port[0]); -+ -+ if (ata_device_add(&ae) == 0) -+ return -ENODEV; -+ return 0; -+} -+ -+/** -+ * isapnp_remove_one - unplug an isapnp interface -+ * @idev: PnP device -+ * -+ * Remove a previously configured PnP ATA port. Called only on module -+ * unload events as the core does not currently deal with ISAPnP docking. -+ */ -+ -+static void isapnp_remove_one(struct pnp_dev *idev) -+{ -+ struct device *dev = &idev->dev; -+ struct ata_host_set *host_set = dev_get_drvdata(dev); -+ -+ ata_host_set_remove(host_set); -+ dev_set_drvdata(dev, NULL); -+} -+ -+static struct pnp_device_id isapnp_devices[] = { -+ /* Generic ESDI/IDE/ATA compatible hard disk controller */ -+ {.id = "PNP0600", .driver_data = 0}, -+ {.id = ""} -+}; -+ -+static struct pnp_driver isapnp_driver = { -+ .name = DRV_NAME, -+ .id_table = isapnp_devices, -+ .probe = isapnp_init_one, -+ .remove = isapnp_remove_one, -+}; -+ -+static int __init isapnp_init(void) -+{ -+ return pnp_register_driver(&isapnp_driver); -+} -+ -+static void __exit isapnp_exit(void) -+{ -+ pnp_unregister_driver(&isapnp_driver); -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for ISA PnP ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(isapnp_init); -+module_exit(isapnp_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_it8172.c linux-2.6.16-rc4/drivers/scsi/pata_it8172.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_it8172.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_it8172.c 2006-02-16 15:39:11.000000000 +0000 -@@ -0,0 +1,280 @@ -+/* -+ * pata_it8172.c - IT8172 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based heavily on -+ * -+ * BRIEF MODULE DESCRIPTION -+ * IT8172 IDE controller support -+ * -+ * Copyright 2000 MontaVista Software Inc. -+ * Author: MontaVista Software, Inc. -+ * stevel@mvista.com or source@mvista.com -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (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. -+ * -+ * TODO -+ * Check for errata -+ * See if we really need to force native mode -+ * PIO timings (also lacking in original) -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "it8172" -+#define DRV_VERSION "0.1.1" -+ -+static void it8172_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits it8172_enable_bits[] = { -+ { 0x00, 0, 0x00, 0x00 }, -+ { 0x40, 1, 0x00, 0x01 } -+ }; -+ -+ if (ap->hard_port_no && !pci_test_config_bits(pdev, &it8172_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * it8172_set_pio_timing - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called by both the pio and dma setup functions to set the controller -+ * timings for PIO transfers. We must load both the mode number and -+ * timing values into the controller. -+ */ -+ -+static void it8172_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u16 reg40; -+ -+ pci_read_config_word(pdev, 0x40, ®40); -+ -+ /* -+ * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 -+ * are being left at the default values of 8 PCI clocks (242 nsec -+ * for a 33 MHz clock). These can be safely shortened at higher -+ * PIO modes. The DIOR/DIOW pulse width and recovery times only -+ * apply to PIO modes, not to the DMA modes. -+ */ -+ -+ /* -+ * Enable port 0x44. The IT8172G spec is confused; it calls -+ * this register the "Slave IDE Timing Register", but in fact, -+ * it controls timing for both master and slave drives. -+ */ -+ -+ reg40 |= 0x4000; -+ if (adev->devno) { -+ reg40 |= 0xC006; -+ if (pio > 1) -+ /* Enable prefetch and IORDY sample-point */ -+ reg40 |= 0x0060; -+ } else { -+ reg40 |= 0xC060; -+ if (pio > 1) -+ /* Enable prefetch and IORDY sample-point */ -+ reg40 |= 0x0006; -+ } -+ /* Write back the enables */ -+ pci_write_config_word(pdev, 0x40, reg40); -+} -+ -+/** -+ * it8172_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. We use a shared helper for this -+ * as the DMA setup must also adjust the PIO timing information. -+ */ -+ -+static void it8172_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ it8172_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0); -+} -+ -+/** -+ * it8172_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the DMA mode setup. We must tune an appropriate PIO -+ * mode to match. -+ */ -+ -+static void it8172_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int dn = (2 * ap->hard_port_no) + adev->devno; -+ u8 reg48, reg4a; -+ int pio; -+ -+ static int pio_map[] = { 1, 3, 4}; -+ /* -+ * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec -+ * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA -+ * transfers on some drives, even though both numbers meet the minimum -+ * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively. -+ * So the faster times are just commented out here. The good news is -+ * that the slower cycle time has very little affect on transfer -+ * performance. -+ */ -+ -+ pci_read_config_byte(pdev, 0x48, ®48); -+ pci_read_config_byte(pdev, 0x4A, ®4a); -+ -+ reg4a &= ~(3 << (4 * dn)); -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ reg48 |= 1 << dn; -+#ifdef UDMA_TIMING_SET -+ reg4a |= ((adev->dma_mode - XFER_UDMA_0) << (4 * dn)); -+#endif -+ pio = 4; -+ } else { -+ pio = pio_map[adev->dma_mode - XFER_MW_DMA_0]; -+ reg48 &= ~ (1 << dn); -+ } -+ pci_write_config_byte(pdev, 0x48, reg48); -+ pci_write_config_byte(pdev, 0x4A, reg4a); -+ it8172_set_pio_timing(ap, adev, pio); -+ -+} -+ -+static struct scsi_host_template it8172_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations it8172_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = it8172_set_piomode, -+ .set_dmamode = it8172_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = it8172_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &it8172_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x06, /* No MWDMA0 support */ -+ .udma_mask = 0x7, -+ .port_ops = &it8172_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ if ((!(PCI_FUNC(dev->devfn) & 1) || -+ (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) -+ return -ENODEV; /* IT8172 is more than an IDE controller */ -+ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id it8172[] = { -+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, }, -+}; -+ -+static struct pci_driver it8172_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = it8172, -+ .probe = it8172_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init it8172_init(void) -+{ -+ return pci_register_driver(&it8172_pci_driver); -+} -+ -+ -+static void __exit it8172_exit(void) -+{ -+ pci_unregister_driver(&it8172_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for ITE IT8172"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, it8172); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(it8172_init); -+module_exit(it8172_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_it821x.c linux-2.6.16-rc4/drivers/scsi/pata_it821x.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_it821x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_it821x.c 2006-02-20 12:27:55.000000000 +0000 -@@ -0,0 +1,743 @@ -+/* -+ * ata-it821x.c - IT821x PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon -+ * -+ * it821x.c -+ * -+ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 -+ * -+ * Copyright (C) 2004 Red Hat <alan@redhat.com> -+ * -+ * May be copied or modified under the terms of the GNU General Public License -+ * Based in part on the ITE vendor provided SCSI driver. -+ * -+ * Documentation available from -+ * http://www.ite.com.tw/pc/IT8212F_V04.pdf -+ * Some other documents are NDA. -+ * -+ * The ITE8212 isn't exactly a standard IDE controller. It has two -+ * modes. In pass through mode then it is an IDE controller. In its smart -+ * mode its actually quite a capable hardware raid controller disguised -+ * as an IDE controller. Smart mode only understands DMA read/write and -+ * identify, none of the fancier commands apply. The IT8211 is identical -+ * in other respects but lacks the raid mode. -+ * -+ * Errata: -+ * o Rev 0x10 also requires master/slave hold the same DMA timings and -+ * cannot do ATAPI MWDMA. -+ * o The identify data for raid volumes lacks CHS info (technically ok) -+ * but also fails to set the LBA28 and other bits. We fix these in -+ * the IDE probe quirk code. -+ * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode -+ * raid then the controller firmware dies -+ * o Smart mode without RAID doesn't clear all the necessary identify -+ * bits to reduce the command set to the one used -+ * -+ * This has a few impacts on the driver -+ * - In pass through mode we do all the work you would expect -+ * - In smart mode the clocking set up is done by the controller generally -+ * but we must watch the other limits and filter. -+ * - There are a few extra vendor commands that actually talk to the -+ * controller but only work PIO with no IRQ. -+ * -+ * Vendor areas of the identify block in smart mode are used for the -+ * timing and policy set up. Each HDD in raid mode also has a serial -+ * block on the disk. The hardware extra commands are get/set chip status, -+ * rebuild, get rebuild status. -+ * -+ * In Linux the driver supports pass through mode as if the device was -+ * just another IDE controller. If the smart mode is running then -+ * volumes are managed by the controller firmware and each IDE "disk" -+ * is a raid volume. Even more cute - the controller can do automated -+ * hotplug and rebuild. -+ * -+ * The pass through controller itself is a little demented. It has a -+ * flaw that it has a single set of PIO/MWDMA timings per channel so -+ * non UDMA devices restrict each others performance. It also has a -+ * single clock source per channel so mixed UDMA100/133 performance -+ * isn't perfect and we have to pick a clock. Thankfully none of this -+ * matters in smart mode. ATAPI DMA is not currently supported. -+ * -+ * It seems the smart mode is a win for RAID1/RAID10 but otherwise not. -+ * -+ * TODO -+ * - ATAPI and other speed filtering -+ * - Command filter in smart mode -+ * - RAID configuration ioctls -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+ -+#define DRV_NAME "it821x" -+#define DRV_VERSION "0.2.1" -+ -+struct it821x_dev -+{ -+ unsigned int smart:1, /* Are we in smart raid mode */ -+ timing10:1; /* Rev 0x10 */ -+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */ -+ u8 want[2][2]; /* Mode/Pri log for master slave */ -+ /* We need these for switching the clock when DMA goes on/off -+ The high byte is the 66Mhz timing */ -+ u16 pio[2]; /* Cached PIO values */ -+ u16 mwdma[2]; /* Cached MWDMA values */ -+ u16 udma[2]; /* Cached UDMA values (per drive) */ -+ u16 last_device; /* Master or slave loaded ? */ -+}; -+ -+#define ATA_66 0 -+#define ATA_50 1 -+#define ATA_ANY 2 -+ -+#define UDMA_OFF 0 -+#define MWDMA_OFF 0 -+ -+/* -+ * We allow users to force the card into non raid mode without -+ * flashing the alternative BIOS. This is also neccessary right now -+ * for embedded platforms that cannot run a PC BIOS but are using this -+ * device. -+ */ -+ -+static int it8212_noraid; -+ -+ -+/** -+ * it821x_phy_reset - probe/reset -+ * @ap: ATA port -+ * -+ * Set the cable type and trigger a probe -+ */ -+ -+static void it821x_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA80; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * it821x_program - program the PIO/MWDMA registers -+ * @ap: ATA port -+ * @adev: Device to program -+ * @timing: Timing value (66Mhz in top 8bits, 50 in the low 8) -+ * -+ * Program the PIO/MWDMA timing for this channel according to the -+ * current clock. These share the same register so are managed by -+ * the DMA start/stop sequence as with the old driver. -+ */ -+ -+static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct it821x_dev *itdev = ap->private_data; -+ int channel = ap->hard_port_no; -+ u8 conf; -+ -+ /* Program PIO/MWDMA timing bits */ -+ if (itdev->clock_mode == ATA_66) -+ conf = timing >> 8; -+ else -+ conf = timing & 0xFF; -+ pci_write_config_byte(pdev, 0x54 + 4 * channel, conf); -+} -+ -+ -+/** -+ * it821x_program_udma - program the UDMA registers -+ * @ap: ATA port -+ * @adev: ATA device to update -+ * @timing: Timing bits. Top 8 are for 66Mhz bottom for 50Mhz -+ * -+ * Program the UDMA timing for this drive according to the -+ * current clock. Handles the dual clocks and also knows about -+ * the errata on the 0x10 revision. The UDMA errata is partly handled -+ * here and partly in start_dma. -+ */ -+ -+static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing) -+{ -+ struct it821x_dev *itdev = ap->private_data; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int channel = ap->hard_port_no; -+ int unit = adev->devno; -+ u8 conf; -+ -+ /* Program UDMA timing bits */ -+ if (itdev->clock_mode == ATA_66) -+ conf = timing >> 8; -+ else -+ conf = timing & 0xFF; -+ if (itdev->timing10 == 0) -+ pci_write_config_byte(pdev, 0x56 + 4 * channel + unit, conf); -+ else { -+ /* Early revision must be programmed for both together */ -+ pci_write_config_byte(pdev, 0x56 + 4 * channel, conf); -+ pci_write_config_byte(pdev, 0x56 + 4 * channel + 1, conf); -+ } -+} -+ -+/** -+ * it821x_clock_strategy -+ * @ap: ATA interface -+ * @adev: ATA device being updated -+ * -+ * Select between the 50 and 66Mhz base clocks to get the best -+ * results for this interface. -+ */ -+ -+static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct it821x_dev *itdev = ap->private_data; -+ u8 unit = adev->devno; -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ -+ int clock, altclock; -+ u8 v; -+ int sel = 0; -+ -+ /* Look for the most wanted clocking */ -+ if (itdev->want[0][0] > itdev->want[1][0]) { -+ clock = itdev->want[0][1]; -+ altclock = itdev->want[1][1]; -+ } else { -+ clock = itdev->want[1][1]; -+ altclock = itdev->want[0][1]; -+ } -+ -+ /* Master doesn't care does the slave ? */ -+ if (clock == ATA_ANY) -+ clock = altclock; -+ -+ /* Nobody cares - keep the same clock */ -+ if (clock == ATA_ANY) -+ return; -+ /* No change */ -+ if (clock == itdev->clock_mode) -+ return; -+ -+ /* Load this into the controller ? */ -+ if (clock == ATA_66) -+ itdev->clock_mode = ATA_66; -+ else { -+ itdev->clock_mode = ATA_50; -+ sel = 1; -+ } -+ pci_read_config_byte(pdev, 0x50, &v); -+ v &= ~(1 << (1 + ap->hard_port_no)); -+ v |= sel << (1 + ap->hard_port_no); -+ pci_write_config_byte(pdev, 0x50, v); -+ -+ /* -+ * Reprogram the UDMA/PIO of the pair drive for the switch -+ * MWDMA will be dealt with by the dma switcher -+ */ -+ if (pair && itdev->udma[1-unit] != UDMA_OFF) { -+ it821x_program_udma(ap, pair, itdev->udma[1-unit]); -+ it821x_program(ap, pair, itdev->pio[1-unit]); -+ } -+ /* -+ * Reprogram the UDMA/PIO of our drive for the switch. -+ * MWDMA will be dealt with by the dma switcher -+ */ -+ if (itdev->udma[unit] != UDMA_OFF) { -+ it821x_program_udma(ap, adev, itdev->udma[unit]); -+ it821x_program(ap, adev, itdev->pio[unit]); -+ } -+} -+ -+/** -+ * it821x_passthru_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Configure for PIO mode. This is complicated as the register is -+ * shared by PIO and MWDMA and for both channels. -+ */ -+ -+static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ /* Spec says 89 ref driver uses 88 */ -+ static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; -+ static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; -+ -+ struct it821x_dev *itdev = ap->private_data; -+ int unit = adev->devno; -+ int mode_wanted = adev->pio_mode - XFER_PIO_0; -+ -+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ -+ itdev->want[unit][1] = pio_want[mode_wanted]; -+ itdev->want[unit][0] = 1; /* PIO is lowest priority */ -+ itdev->pio[unit] = pio[mode_wanted]; -+ it821x_clock_strategy(ap, adev); -+ it821x_program(ap, adev, itdev->pio[unit]); -+} -+ -+/** -+ * it821x_passthru_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Set up the DMA modes. The actions taken depend heavily on the mode -+ * to use. If UDMA is used as is hopefully the usual case then the -+ * timing register is private and we need only consider the clock. If -+ * we are using MWDMA then we have to manage the setting ourself as -+ * we switch devices and mode. -+ */ -+ -+static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; -+ static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; -+ static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; -+ static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct it821x_dev *itdev = ap->private_data; -+ int channel = ap->hard_port_no; -+ int unit = adev->devno; -+ u8 conf; -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ int mode_wanted = adev->dma_mode - XFER_UDMA_0; -+ -+ itdev->want[unit][1] = udma_want[mode_wanted]; -+ itdev->want[unit][0] = 3; /* UDMA is high priority */ -+ itdev->mwdma[unit] = MWDMA_OFF; -+ itdev->udma[unit] = udma[mode_wanted]; -+ if (mode_wanted >= 5) -+ itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ -+ -+ /* UDMA on. Again revision 0x10 must do the pair */ -+ pci_read_config_byte(pdev, 0x50, &conf); -+ if (itdev->timing10) -+ conf &= channel ? 0x9F: 0xE7; -+ else -+ conf &= ~ (1 << (3 + 2 * channel + unit)); -+ pci_write_config_byte(pdev, 0x50, conf); -+ it821x_clock_strategy(ap, adev); -+ it821x_program_udma(ap, adev, itdev->udma[unit]); -+ } else { -+ int mode_wanted = adev->dma_mode - XFER_UDMA_0; -+ -+ itdev->want[unit][1] = mwdma_want[mode_wanted]; -+ itdev->want[unit][0] = 2; /* MWDMA is low priority */ -+ itdev->mwdma[unit] = dma[mode_wanted]; -+ itdev->udma[unit] = UDMA_OFF; -+ -+ /* UDMA bits off - Revision 0x10 do them in pairs */ -+ pci_read_config_byte(pdev, 0x50, &conf); -+ if (itdev->timing10) -+ conf |= channel ? 0x60: 0x18; -+ else -+ conf |= 1 << (3 + 2 * channel + unit); -+ pci_write_config_byte(pdev, 0x50, conf); -+ it821x_clock_strategy(ap, adev); -+ } -+} -+ -+/** -+ * it821x_passthru_dma_start - DMA start callback -+ * @qc: Command in progress -+ * -+ * Usually drivers set the DMA timing at the point the set_dmamode call -+ * is made. IT821x however requires we load new timings on the -+ * transitions in some cases. -+ */ -+ -+static void it821x_passthru_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ struct it821x_dev *itdev = ap->private_data; -+ int unit = adev->devno; -+ -+ if (itdev->mwdma[unit] != MWDMA_OFF) -+ it821x_program(ap, adev, itdev->mwdma[unit]); -+ else if (itdev->udma[unit] != UDMA_OFF && itdev->timing10) -+ it821x_program_udma(ap, adev, itdev->udma[unit]); -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * it821x_passthru_dma_stop - DMA stop callback -+ * @qc: ATA command -+ * -+ * We loaded new timings in dma_start, as a result we need to restore -+ * the PIO timings in dma_stop so that the next command issue gets the -+ * right clock values. -+ */ -+ -+static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ struct it821x_dev *itdev = ap->private_data; -+ int unit = adev->devno; -+ -+ ata_bmdma_stop(qc); -+ if (itdev->mwdma[unit] != MWDMA_OFF) -+ it821x_program(ap, adev, itdev->pio[unit]); -+} -+ -+ -+/** -+ * it821x_passthru_dev_select - Select master/slave -+ * @ap: ATA port -+ * @device: Device number (not pointer) -+ * -+ * Device selection hook. If neccessary perform clock switching -+ */ -+ -+void it821x_passthru_dev_select(struct ata_port *ap, unsigned int device) -+{ -+ struct it821x_dev *itdev = ap->private_data; -+ if (itdev && device != itdev->last_device) { -+ struct ata_device *adev = &ap->device[device]; -+ it821x_program(ap, adev, itdev->pio[adev->devno]); -+ itdev->last_device = device; -+ } -+} -+ -+/** -+ * it821x_passthru_qc_issue_prot - wrap qc issue prot -+ * @qc: command -+ * -+ * Wrap the command issue sequence for the IT821x. We need to -+ * perform out own device selection timing loads before the -+ * usual happenings kick off -+ */ -+ -+static int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ it821x_passthru_dev_select(qc->ap, qc->dev->devno); -+ return ata_qc_issue_prot(qc); -+} -+ -+/** -+ * it821x_smart_set_mode - mode setting -+ * @ap: interface to set up -+ * -+ * Use a non standard set_mode function. We don't want to be tuned. -+ * The BIOS configured everything. Our job is not to fiddle. We -+ * read the dma enabled bits from the PCI configuration of the device -+ * and respect them. -+ */ -+ -+static void it821x_smart_set_mode(struct ata_port *ap) -+{ -+ int dma_enabled; -+ int i; -+ -+ /* Bits 5 and 6 indicate if DMA is active on master/slave */ -+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *dev = &ap->device[i]; -+ if (ata_dev_present(dev)) { -+ /* We don't really care */ -+ dev->pio_mode = XFER_PIO_0; -+ dev->dma_mode = XFER_MW_DMA_0; -+ /* We do need the right mode information for DMA or PIO -+ and this comes from the current configuration flags */ -+ if (dma_enabled & (1 << (5 + i))) { -+ dev->xfer_mode = XFER_MW_DMA_0; -+ dev->xfer_shift = ATA_SHIFT_MWDMA; -+ dev->flags &= ~ATA_DFLAG_PIO; -+ } else { -+ dev->xfer_mode = XFER_PIO_0; -+ dev->xfer_shift = ATA_SHIFT_PIO; -+ dev->flags |= ATA_DFLAG_PIO; -+ } -+ /* Keep sector count safe (LBA48 counts blow the -+ brains of the firmware) */ -+ -+ /* Do we need a dev_config method ? */ -+ dev->flags |= ATA_DFLAG_LOCK_SECTORS; -+ } -+ } -+} -+ -+/** -+ * it821x_check_atapi_dma - ATAPI DMA handler -+ * @qc: Command we are about to issue -+ * -+ * Decide if this ATAPI command can be issued by DMA on this -+ * controller. Return 0 if it can be. -+ */ -+ -+static int it821x_check_atapi_dma(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct it821x_dev *itdev = ap->private_data; -+ -+ /* No ATAPI DMA in smart mode */ -+ if (itdev->smart) -+ return -EOPNOTSUPP; -+ /* No ATAPI DMA on rev 10 */ -+ if (itdev->timing10) -+ return -EOPNOTSUPP; -+ /* Cool */ -+ return 0; -+} -+ -+ -+/** -+ * it821x_port_start - port setup -+ * @ap: ATA port being set up -+ * -+ * The it821x needs to maintain private data structures and also to -+ * use the standard PCI interface which lacks support for this -+ * functionality. We instead set up the private data on the port -+ * start hook, and tear it down on port stop -+ */ -+ -+static int it821x_port_start(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct it821x_dev *itdev; -+ u8 conf; -+ -+ int ret = ata_port_start(ap); -+ if (ret < 0) -+ return ret; -+ -+ ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL); -+ if (ap->private_data == NULL) { -+ ata_port_stop(ap); -+ return -ENOMEM; -+ } -+ -+ itdev = ap->private_data; -+ memset(itdev, 0, sizeof(struct it821x_dev)); -+ -+ pci_read_config_byte(pdev, 0x50, &conf); -+ -+ if (conf & 1) { -+ itdev->smart = 1; -+ /* Long I/O's although allowed in LBA48 space cause the -+ onboard firmware to enter the twighlight zone */ -+ /* No ATAPI DMA in this mode either */ -+ } -+ /* Pull the current clocks from 0x50 */ -+ if (conf & (1 << (1 + ap->hard_port_no))) -+ itdev->clock_mode = ATA_50; -+ else -+ itdev->clock_mode = ATA_66; -+ -+ itdev->want[0][1] = ATA_ANY; -+ itdev->want[1][1] = ATA_ANY; -+ itdev->last_device = -1; -+ -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &conf); -+ if (conf == 0x10) { -+ itdev->timing10 = 1; -+ /* Need to disable ATAPI DMA for this case */ -+ if (!itdev->smart) -+ printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n"); -+ } -+ -+ return 0; -+} -+ -+/** -+ * it821x_port_stop - port shutdown -+ * @ap: ATA port being removed -+ * -+ * Release the private objects we added in it821x_port_start -+ */ -+ -+static void it821x_port_stop(struct ata_port *ap) { -+ kfree(ap->private_data); -+ ap->private_data = NULL; /* We want an OOPS if we reuse this -+ too late! */ -+ ata_port_stop(ap); -+} -+ -+static struct scsi_host_template it821x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ /* 255 sectors to begin with. This is locked in smart mode but not -+ in pass through */ -+ .max_sectors = 255, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations it821x_smart_port_ops = { -+ .set_mode = it821x_smart_set_mode, -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .check_atapi_dma= it821x_check_atapi_dma, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = it821x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = it821x_port_start, -+ .port_stop = it821x_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations it821x_passthru_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = it821x_passthru_set_piomode, -+ .set_dmamode = it821x_passthru_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .check_atapi_dma= it821x_check_atapi_dma, -+ .dev_select = it821x_passthru_dev_select, -+ -+ .phy_reset = it821x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = it821x_passthru_bmdma_start, -+ .bmdma_stop = it821x_passthru_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = it821x_passthru_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ .irq_handler = ata_interrupt, -+ .port_start = it821x_port_start, -+ .port_stop = it821x_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static void __devinit it821x_disable_raid(struct pci_dev *pdev) -+{ -+ /* Reset local CPU, and set BIOS not ready */ -+ pci_write_config_byte(pdev, 0x5E, 0x01); -+ -+ /* Set to bypass mode, and reset PCI bus */ -+ pci_write_config_byte(pdev, 0x50, 0x00); -+ pci_write_config_word(pdev, PCI_COMMAND, -+ PCI_COMMAND_PARITY | PCI_COMMAND_IO | -+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); -+ pci_write_config_word(pdev, 0x40, 0xA0F3); -+ -+ pci_write_config_dword(pdev,0x4C, 0x02040204); -+ pci_write_config_byte(pdev, 0x42, 0x36); -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0); -+} -+ -+ -+static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ u8 conf; -+ -+ static struct ata_port_info info_smart = { -+ .sht = &it821x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &it821x_smart_port_ops -+ }; -+ static struct ata_port_info info_passthru = { -+ .sht = &it821x_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &it821x_passthru_port_ops -+ }; -+ static struct ata_port_info *port_info[2]; -+ -+ static char *mode[2] = { "pass through", "smart" }; -+ -+ /* Force the card into bypass mode if so requested */ -+ if (it8212_noraid) { -+ printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n"); -+ it821x_disable_raid(pdev); -+ } -+ pci_read_config_byte(pdev, 0x50, &conf); -+ conf &= 1; -+ -+ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]); -+ if (conf == 0) -+ port_info[0] = port_info[1] = &info_passthru; -+ else -+ port_info[0] = port_info[1] = &info_smart; -+ -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static struct pci_device_id it821x[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), }, -+ { 0, }, -+}; -+ -+static struct pci_driver it821x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = it821x, -+ .probe = it821x_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init it821x_init(void) -+{ -+ return pci_register_driver(&it821x_pci_driver); -+} -+ -+ -+static void __exit it821x_exit(void) -+{ -+ pci_unregister_driver(&it821x_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, it821x); -+MODULE_VERSION(DRV_VERSION); -+ -+ -+module_param_named(noraid, it8212_noraid, int, S_IRUGO); -+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode"); -+ -+module_init(it821x_init); -+module_exit(it821x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_legacy.c linux-2.6.16-rc4/drivers/scsi/pata_legacy.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_legacy.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_legacy.c 2006-02-16 15:33:52.000000000 +0000 -@@ -0,0 +1,672 @@ -+ -+/* -+ * pata-legacy.c - Legacy port PATA/SATA controller driver. -+ * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved. -+ * -+ * An ATA driver for the legacy ATA ports. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/ata.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "legacy" -+#define DRV_VERSION "0.3.1" -+ -+#define NR_HOST 6 -+ -+static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; -+static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 }; -+ -+static struct ata_host_set *legacy_host[NR_HOST]; -+static int nr_legacy_host; -+static int legacy_all; -+static int ht6560a; -+static int ht6560b; -+static int opti82c611a; -+ -+/** -+ * legacy_set_mode - mode setting -+ * @ap: IDE interface -+ * -+ * Use a non standard set_mode function. We don't want to be tuned. -+ * -+ * The BIOS configured everything. Our job is not to fiddle. Just use -+ * whatever PIO the hardware is using and leave it at that. When we -+ * get some kind of nice user driven API for control then we can -+ * expand on this as per hdparm in the base kernel. -+ */ -+ -+static void legacy_set_mode(struct ata_port *ap) -+{ -+ int i; -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *dev = &ap->device[i]; -+ if (ata_dev_present(dev)) { -+ dev->pio_mode = XFER_PIO_0; -+ dev->xfer_mode = XFER_PIO_0; -+ dev->xfer_shift = ATA_SHIFT_PIO; -+ dev->flags |= ATA_DFLAG_PIO; -+ } -+ } -+} -+ -+static struct scsi_host_template legacy_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations legacy_port_ops = { -+ .set_mode = legacy_set_mode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer_noirq, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Promise 20230C and 20620 support -+ * -+ * This controller supports PIO0 to PIO2. We set PIO timings conservatively to -+ * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to -+ * controller and PIO'd to the host and not supported. -+ */ -+ -+static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ int tries = 5; -+ int pio = adev->pio_mode - XFER_PIO_0; -+ u8 rt; -+ -+ do -+ { -+ inb(0x1F5); -+ outb(inb(0x1F2) | 0x80, 0x1F2); -+ inb(0x1F2); -+ inb(0x3F6); -+ inb(0x3F6); -+ inb(0x1F2); -+ inb(0x1F2); -+ } -+ while((inb(0x1F2) & 0x80) && --tries); -+ -+ outb(inb(0x1F4) & 0x07, 0x1F4); -+ -+ rt = inb(0x1F3); -+ rt &= 0x07 << (3 * adev->devno); -+ rt |= (3 * pio) << (3 * adev->devno); -+ -+ udelay(100); -+ outb(inb(0x1F2) | 0x01, 0x1F2); -+ udelay(100); -+ inb(0x1F5); -+ -+} -+ -+static void pdc_data_xfer_vlb(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) -+{ -+ int slop = buflen & 3; -+ unsigned long flags; -+ -+ if (ata_id_has_dword_io(adev->id)) { -+ local_irq_save(flags); -+ -+ /* Perform the 32bit I/O synchronization sequence */ -+ inb(ap->ioaddr.nsect_addr); -+ inb(ap->ioaddr.nsect_addr); -+ inb(ap->ioaddr.nsect_addr); -+ -+ /* Now the data */ -+ -+ if (write_data) -+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2); -+ else -+ insl(ap->ioaddr.data_addr, buf, buflen >> 2); -+ -+ if (unlikely(slop)) { -+ u32 pad; -+ if (write_data) { -+ memcpy(&pad, buf + buflen - slop, slop); -+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr); -+ } else { -+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); -+ memcpy(buf + buflen - slop, &pad, slop); -+ } -+ } -+ local_irq_restore(flags); -+ } -+ else -+ ata_pio_data_xfer_noirq(ap, adev, buf, buflen, write_data); -+} -+ -+static struct ata_port_operations pdc20230_port_ops = { -+ .set_piomode = pdc20230_set_piomode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = pdc_data_xfer_vlb, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Holtek 6560A support -+ * -+ * This controller supports PIO0 to PIO2 (no IORDY even though higher timings -+ * can be loaded). -+ */ -+ -+static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ u8 active, recover; -+ struct ata_timing t; -+ -+ /* Get the timing data in cycles. For now play safe at 50Mhz */ -+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); -+ -+ active = FIT(t.active, 2, 15); -+ recover = FIT(t.recover, 4, 15); -+ -+ inb(0x3E6); -+ inb(0x3E6); -+ inb(0x3E6); -+ inb(0x3E6); -+ -+ outb(recover << 4 | active, ap->ioaddr.device_addr); -+ inb(ap->ioaddr.status_addr); -+} -+ -+static struct ata_port_operations ht6560a_port_ops = { -+ .set_piomode = ht6560a_set_piomode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */ -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Holtek 6560B support -+ * -+ * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting -+ * unless we see an ATAPI device in which case we force it off. -+ * -+ * FIXME: need to implement 2nd channel support. -+ */ -+ -+static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ u8 active, recover; -+ struct ata_timing t; -+ -+ /* Get the timing data in cycles. For now play safe at 50Mhz */ -+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); -+ -+ active = FIT(t.active, 2, 15); -+ recover = FIT(t.recover, 2, 16); -+ recover &= 0x15; -+ -+ inb(0x3E6); -+ inb(0x3E6); -+ inb(0x3E6); -+ inb(0x3E6); -+ -+ outb(recover << 4 | active, ap->ioaddr.device_addr); -+ -+ if (adev->class != ATA_DEV_ATA) { -+ u8 rconf = inb(0x3E6); -+ if (rconf & 0x24) { -+ rconf &= ~ 0x24; -+ outb(rconf, 0x3E6); -+ } -+ } -+ inb(ap->ioaddr.status_addr); -+} -+ -+static struct ata_port_operations ht6560b_port_ops = { -+ .set_piomode = ht6560b_set_piomode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */ -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/* -+ * Opti 82C611A -+ * -+ * This controller supports PIO0 to PIO3. -+ */ -+ -+static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ u8 active, recover, setup; -+ struct ata_timing t; -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ int clock; -+ int khz[4] = { 50000, 40000, 33000, 25000 }; -+ u8 rc; -+ -+ /* Enter configuration mode */ -+ inb(ap->ioaddr.error_addr); -+ inb(ap->ioaddr.error_addr); -+ -+ /* Read VLB clock strapping */ -+ clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03]; -+ -+ /* Get the timing data in cycles */ -+ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); -+ -+ /* Setup timing is shared */ -+ if (pair) { -+ struct ata_timing tp; -+ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); -+ -+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); -+ } -+ -+ active = FIT(t.active, 2, 17) - 2; -+ recover = FIT(t.recover, 1, 16) - 1; -+ setup = FIT(t.setup, 1, 4) - 1; -+ -+ /* Select the right timing bank for write timing */ -+ rc = inb(ap->ioaddr.lbal_addr); -+ rc &= 0x7F; -+ rc |= (adev->devno << 7); -+ outb(rc, ap->ioaddr.lbal_addr); -+ -+ /* Write the timings */ -+ outb(active << 4 | recover, ap->ioaddr.error_addr); -+ -+ /* Select the right bank for read timings, also -+ load the shared timings for address */ -+ rc = inb(ap->ioaddr.device_addr); -+ rc &= 0xC0; -+ rc |= adev->devno; /* Index select */ -+ rc |= (setup << 4) | 0x04; -+ outb(rc, ap->ioaddr.device_addr); -+ -+ /* Load the read timings */ -+ outb(active << 4 | recover, ap->ioaddr.data_addr); -+ -+ /* Ensure the timing register mode is right */ -+ rc = inb (ap->ioaddr.lbal_addr); -+ rc &= 0x73; -+ rc |= 0x84; -+ outb(rc, ap->ioaddr.lbal_addr); -+ -+ /* Exit command mode */ -+ outb(0x82, ap->ioaddr.nsect_addr); -+} -+ -+static struct ata_port_operations opti82c611a_port_ops = { -+ .set_piomode = opti82c611a_set_piomode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * legacy_init_one - attach a legacy interface -+ * @io: I/O port start -+ * @ctrl: control port -+ * @irq: interrupt line -+ * -+ * Register an ISA bus IDE interface. Such interfaces are PIO and we -+ * assume do not support IRQ sharing. -+ */ -+ -+static __init int legacy_init_one(unsigned long io, unsigned long ctrl, int irq) -+{ -+ struct ata_probe_ent ae; -+ int ret; -+ struct ata_port_operations *ops = &legacy_port_ops; -+ int pio_mask = 0x1F; -+ -+ if (request_region(io, 8, "pata_legacy") == NULL) -+ return -EBUSY; -+ if (request_region(ctrl, 1, "pata_legacy") == NULL) { -+ release_region(io, 8); -+ return -EBUSY; -+ } -+ -+ if (ht6560a == 1 && (io == 0x1F0 || io == 0x170)) { -+ ops = &ht6560a_port_ops; -+ pio_mask = 0x07; -+ } -+ if (ht6560b == 1 && (io == 0x1F0 || io == 0x170)) { -+ ops = &ht6560b_port_ops; -+ pio_mask = 0x1F; -+ } -+ if (opti82c611a == 1 && (io == 0x1F0 || io == 0x170)) { -+ ops = &opti82c611a_port_ops; -+ pio_mask = 0x0F; -+ } -+ else if (io == 0x1F0) { -+ /* Probes */ -+ inb(0x1F5); -+ outb(inb(0x1F2) | 0x80, 0x1F2); -+ inb(0x1F2); -+ inb(0x3F6); -+ inb(0x3F6); -+ inb(0x1F2); -+ inb(0x1F2); -+ -+ if ((inb(0x1F2) & 0x80) == 0) { -+ /* PDC20230 or 20630 ? */ -+ printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n"); -+ pio_mask = 0x07; -+ ops = &pdc20230_port_ops; -+ udelay(100); -+ inb(0x1F5); -+ } else { -+ outb(0x55, 0x1F2); -+ inb(0x1F2); -+ inb(0x1F2); -+ if (inb(0x1F2) == 0x00) { -+ printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n"); -+ } -+ } -+ } -+ memset(&ae, 0, sizeof(struct ata_probe_ent)); -+ INIT_LIST_HEAD(&ae.node); -+ ae.dev = NULL; -+ ae.port_ops = ops; -+ ae.sht = &legacy_sht; -+ ae.n_ports = 1; -+ ae.pio_mask = pio_mask; -+ ae.irq = irq; -+ ae.irq_flags = 0; -+ ae.host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IRQ_MASK; -+ ae.port[0].cmd_addr = io; -+ ae.port[0].altstatus_addr = ctrl; -+ ae.port[0].ctl_addr = ctrl; -+ ata_std_ports(&ae.port[0]); -+ -+ ret = ata_device_add(&ae); -+ if (ret == 0) -+ return -ENODEV; -+ -+ legacy_host[nr_legacy_host++] = ae.host_set; -+ return 0; -+} -+ -+/** -+ * legacy_check_special_cases - ATA special cases -+ * @p: PCI device to check -+ * @master: set this if we find an ATA master -+ * @master: set this if we find an ATA secondary -+ * -+ * A small number of vendors implemented early PCI ATA interfaces on bridge logic -+ * without the ATA interface being PCI visible. Where we have a matching PCI driver -+ * we must skip the relevant device here. If we don't know about it then the legacy -+ * driver is the right driver anyway. -+ */ -+ -+static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary) -+{ -+ /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */ -+ if (p->vendor == 0x1078 && p->device == 0x0000) { -+ *primary = *secondary = 1; -+ return; -+ } -+ /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */ -+ if (p->vendor == 0x1078 && p->device == 0x0002) { -+ *primary = *secondary = 1; -+ return; -+ } -+ /* Intel MPIIX - PIO ATA on non PCI side of bridge */ -+ if (p->vendor == 0x8086 && p->device == 0x1234) { -+ u16 r; -+ pci_read_config_word(p, 0x6C, &r); -+ if (r & 0x8000) { /* ATA port enabled */ -+ if (r & 0x4000) -+ *secondary = 1; -+ else -+ *primary = 1; -+ } -+ return; -+ } -+} -+ -+/** -+ * legacy_init - attach legacy interfaces -+ * -+ * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects. -+ * Right now we do not scan the ide0 and ide1 address but should do so -+ * for non PCI systems or systems with no PCI IDE legacy mode devices. -+ * If you fix that note there are special cases to consider like VLB -+ * drivers and CS5510/20. -+ */ -+ -+static __init int legacy_init(void) -+{ -+ int i; -+ int ct = 0; -+ int primary = 0; -+ int secondary = 0; -+ int last_port = NR_HOST; -+ -+ struct pci_dev *p = NULL; -+ -+ for_each_pci_dev(p) { -+ int r; -+ /* Check for any overlap of the system ATA mappings. Native mode controllers -+ stuck on these addresses or some devices in 'raid' mode won't be found by -+ the storage class test */ -+ for (r = 0; r < 6; r++) { -+ if (pci_resource_start(p, r) == 0x1f0) -+ primary = 1; -+ if (pci_resource_start(p, r) == 0x170) -+ secondary = 1; -+ } -+ /* Check for special cases */ -+ legacy_check_special_cases(p, &primary, &secondary); -+ -+ /* If PCI bus is present then don't probe for tertiary legacy ports */ -+ if (legacy_all == 0) -+ last_port = 2; -+ } -+ -+ -+ for (i = 0; i < last_port; i++) { -+ /* Skip primary if we have seen a PCI one */ -+ if (i == 0 && primary == 1) -+ continue; -+ /* Skip secondary if we have seen a PCI one */ -+ if (i == 1 && secondary == 1) -+ continue; -+ if (legacy_init_one(legacy_port[i], -+ legacy_port[i] + 0x0206, -+ legacy_irq[i]) == 0) -+ ct++; -+ } -+ if (ct != 0) -+ return 0; -+ return -ENODEV; -+} -+ -+static __exit void legacy_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < nr_legacy_host; i++) { -+ struct ata_port *ap =legacy_host[i]->ports[0]; -+ unsigned long io = ap->ioaddr.cmd_addr; -+ unsigned long ctrl = ap->ioaddr.ctl_addr; -+ ata_host_set_remove(legacy_host[i]); -+ release_region(io, 8); -+ release_region(ctrl, 1); -+ } -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for legacy ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+ -+/** -+ * legacy_probe_all - setup argument handler -+ * @unused: unused -+ * -+ * Called when the probe_all argument is passed to this driver. This indicates -+ * that we should check all the legacy ATA addresses even if PCI is present. Should -+ * only ever be needed on very strange PCI/legacy combinations -+ */ -+ -+static int __init legacy_probe_all(char *unused) -+{ -+ legacy_all = 1; -+ return 1; -+} -+ -+__setup("probe-all", legacy_probe_all); -+ -+/** -+ * legacy_ht6560a - setup argument handler -+ * @unused: unused -+ * -+ * Called when the ht6560a argument is passed to this driver. This indicates -+ * that we should check all the legacy ATA addresses even if PCI is present. Should -+ * only ever be needed on very strange PCI/legacy combinations -+ */ -+ -+static int __init legacy_ht6560a(char *unused) -+{ -+ ht6560a = 1; -+ return 1; -+} -+ -+__setup("ht6560a", legacy_ht6560a); -+ -+/** -+ * legacy_ht6560b - setup argument handler -+ * @unused: unused -+ * -+ * Called when the ht6560b argument is passed to this driver. This indicates -+ * that we should check all the legacy ATA addresses even if PCI is present. Should -+ * only ever be needed on very strange PCI/legacy combinations -+ */ -+ -+static int __init legacy_ht6560b(char *unused) -+{ -+ ht6560b = 1; -+ return 1; -+} -+ -+__setup("ht6560b", legacy_ht6560b); -+ -+/** -+ * legacy_ht6560a - setup argument handler -+ * @unused: unused -+ * -+ * Called when the ht6560a argument is passed to this driver. This indicates -+ * that we should check all the legacy ATA addresses even if PCI is present. Should -+ * only ever be needed on very strange PCI/legacy combinations -+ */ -+ -+static int __init legacy_opti82c611a(char *unused) -+{ -+ opti82c611a = 1; -+ return 1; -+} -+ -+__setup("opti82c611a", legacy_opti82c611a); -+ -+module_init(legacy_init); -+module_exit(legacy_exit); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_mpiix.c linux-2.6.16-rc4/drivers/scsi/pata_mpiix.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_mpiix.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_mpiix.c 2006-02-16 15:38:41.000000000 +0000 -@@ -0,0 +1,303 @@ -+/* -+ * pata_mpiix.c - Intel MPIIX PATA for new ATA layer -+ * (C) 2005-2006 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * The MPIIX is different enough to the PIIX4 and friends that we give it -+ * a separate driver. The old ide/pci code handles this by just not tuning -+ * MPIIX at all. -+ * -+ * The MPIIX also differs in another important way from the majority of PIIX -+ * devices. The chip is a bridge (pardon the pun) between the old world of -+ * ISA IDE and PCI IDE. Although the ATA timings are PCI configured the actual -+ * IDE controller is not decoded in PCI space and the chip does not claim to -+ * be IDE class PCI. This requires slightly non-standard probe logic compared -+ * with PCI IDE and also that we do not disable the device when our driver is -+ * unloaded (as it has many other functions). -+ * -+ * The driver conciously keeps this logic internally to avoid pushing quirky -+ * PATA history into the clean libata layer. -+ * -+ * Thinkpad specific note: If you boot an MPIIX using thinkpad with a PCMCIA -+ * hard disk present this driver will not detect it. This is not a bug. In this -+ * configuration the secondary port of the MPIIX is disabled and the addresses -+ * are decoded by the PCMCIA bridge and therefore are for a generic IDE driver -+ * to operate. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_mpiix" -+#define DRV_VERSION "0.4" -+ -+/** -+ * mpiix_phy_reset - probe reset -+ * @ap: ATA port -+ * -+ * Perform the ATA probe and bus reset sequence plus specific handling -+ * for this hardware. The MPIIX has the enable bits in a different place -+ * to PIIX4 and friends. As a pure PIO device it has no cable detect -+ */ -+ -+static void mpiix_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static const struct pci_bits mpiix_enable_bits[] = { -+ { 0x6D, 1, 0x80, 0x80 }, -+ { 0x6F, 1, 0x80, 0x80 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * mpiix_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. The MPIIX allows us to program the -+ * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether -+ * prefetching or iordy are used. -+ * -+ * This would get very ugly because we can only program timing for one -+ * device at a time, the other gets PIO0. Fortunately libata calls -+ * our qc_issue_prot command before a command is issued so we can -+ * flip the timings back and forth to reduce the pain. -+ */ -+ -+static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ int control = 0; -+ int pio = adev->pio_mode - XFER_PIO_0; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u16 idetim; -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; -+ -+ pci_read_config_word(pdev, 0x6C, &idetim); -+ /* Mask the IORDY/TIME/PPE0 bank for this device */ -+ if (adev->class == ATA_DEV_ATA) -+ control |= 4; /* PPE enable for disk */ -+ if (ata_pio_need_iordy(adev)) -+ control |= 2; /* IORDY */ -+ if (pio > 0) -+ control |= 1; /* This drive is on the fast timing bank */ -+ -+ /* Mask out timing and clear both TIME bank selects */ -+ idetim &= 0xCCEE; -+ idetim &= ~(0x07 << (2 * adev->devno)); -+ idetim |= (control << (2 * adev->devno)); -+ -+ idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8); -+ pci_write_config_word(pdev, 0x6C, idetim); -+ -+ /* We use ap->private_data as a pointer to the device currently -+ loaded for timing */ -+ ap->private_data = adev; -+} -+ -+/** -+ * mpiix_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so -+ * that, even if we get this wrong, cycles to the other device will -+ * be made PIO0. -+ */ -+ -+static int mpiix_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ -+ /* If modes have been configured and the channel data is not loaded -+ then load it. We have to check if pio_mode is set as the core code -+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be -+ logical */ -+ -+ if (adev->pio_mode && adev != ap->private_data) -+ mpiix_set_piomode(ap, adev); -+ -+ return ata_qc_issue_prot(qc); -+} -+ -+static struct scsi_host_template mpiix_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations mpiix_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = mpiix_set_piomode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = mpiix_phy_reset, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = mpiix_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ /* Single threaded by the PCI probe logic */ -+ static struct ata_probe_ent probe[2]; -+ static int printed_version; -+ u16 idetim; -+ int enabled; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); -+ -+ /* MPIIX has many functions which can be turned on or off according -+ to other devices present. Make sure IDE is enabled before we try -+ and use it */ -+ -+ pci_read_config_word(dev, 0x6C, &idetim); -+ if (!(idetim & 0x8000)) -+ return -ENODEV; -+ -+ /* We do our own plumbing to avoid leaking special cases for whacko -+ ancient hardware into the core code. There are two issues to -+ worry about. #1 The chip is a bridge so if in legacy mode and -+ without BARs set fools the setup. #2 If you pci_disable_device -+ the MPIIX your box goes castors up */ -+ -+ INIT_LIST_HEAD(&probe[0].node); -+ probe[0].dev = pci_dev_to_dev(dev); -+ probe[0].port_ops = &mpiix_port_ops; -+ probe[0].sht = &mpiix_sht; -+ probe[0].pio_mask = 0x1F; -+ probe[0].irq = 14; -+ probe[0].irq_flags = SA_SHIRQ; -+ probe[0].host_flags = ATA_FLAG_SLAVE_POSS; -+ probe[0].legacy_mode = 1; -+ probe[0].hard_port_no = 0; -+ probe[0].n_ports = 1; -+ probe[0].port[0].cmd_addr = 0x1F0; -+ probe[0].port[0].ctl_addr = 0x3F6; -+ probe[0].port[0].altstatus_addr = 0x3F6; -+ -+ /* The secondary lurks at different addresses but is otherwise -+ the same beastie */ -+ -+ INIT_LIST_HEAD(&probe[1].node); -+ probe[1] = probe[0]; -+ probe[1].irq = 15; -+ probe[1].hard_port_no = 1; -+ probe[1].port[0].cmd_addr = 0x170; -+ probe[1].port[0].ctl_addr = 0x376; -+ probe[1].port[0].altstatus_addr = 0x376; -+ -+ /* Let libata fill in the port details */ -+ ata_std_ports(&probe[0].port[0]); -+ ata_std_ports(&probe[1].port[0]); -+ -+ /* Now add the port that is active */ -+ enabled = (idetim & 0x4000) ? 1 : 0; -+ -+ if (ata_device_add(&probe[enabled])) -+ return 0; -+ return -ENODEV; -+} -+ -+/** -+ * mpiix_remove_one - device unload -+ * @pdev: PCI device being removed -+ * -+ * Handle an unplug/unload event for a PCI device. Unload the -+ * PCI driver but do not use the default handler as we *MUST NOT* -+ * disable the device as it has other functions. -+ */ -+ -+static void __devexit mpiix_remove_one(struct pci_dev *pdev) -+{ -+ struct device *dev = pci_dev_to_dev(pdev); -+ struct ata_host_set *host_set = dev_get_drvdata(dev); -+ -+ ata_host_set_remove(host_set); -+ dev_set_drvdata(dev, NULL); -+} -+ -+ -+ -+static const struct pci_device_id mpiix[] = { -+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -+ { 0, }, -+}; -+ -+static struct pci_driver mpiix_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = mpiix, -+ .probe = mpiix_init_one, -+ .remove = mpiix_remove_one -+}; -+ -+static int __init mpiix_init(void) -+{ -+ return pci_register_driver(&mpiix_pci_driver); -+} -+ -+ -+static void __exit mpiix_exit(void) -+{ -+ pci_unregister_driver(&mpiix_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Intel MPIIX"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, mpiix); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(mpiix_init); -+module_exit(mpiix_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_netcell.c linux-2.6.16-rc4/drivers/scsi/pata_netcell.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_netcell.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_netcell.c 2006-02-08 14:05:57.000000000 +0000 -@@ -0,0 +1,176 @@ -+/* -+ * pata_netcell.c - Netcell PATA driver -+ * -+ * (c) 2006 Red Hat <alan@redhat.com> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_netcell" -+#define DRV_VERSION "0.1" -+ -+/** -+ * netcell_cable_detect - check for 40/80 pin -+ * @ap: Port -+ * -+ * Cables are handled by the RAID controller. Report 80 pin. -+ */ -+ -+static int netcell_cable_detect(struct ata_port *ap) -+{ -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * netcell_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void netcell_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = netcell_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/* No PIO or DMA methods needed for this device */ -+ -+static struct scsi_host_template netcell_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ /* Special handling needed if you have sector or LBA48 limits */ -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ /* Use standard CHS mapping rules */ -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations netcell_ops = { -+ .port_disable = ata_port_disable, -+ -+ /* Task file is PCI ATA format, use helpers */ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = netcell_phy_reset, -+ -+ /* BMDMA handling is PCI ATA format, use helpers */ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, /* In -ac only right now */ -+ -+ /* Timeout handling. Special recovery hooks here */ -+ .eng_timeout = ata_eng_timeout, -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ /* Generic PATA PCI ATA helpers */ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+ -+/** -+ * netcell_init_one - Register Netcell ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in netcell_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ static struct ata_port_info info = { -+ .sht = &netcell_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ /* Actually we don't really care about these as the -+ firmware deals with it */ -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = 0x3f, /* UDMA 133 */ -+ .port_ops = &netcell_ops, -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ /* Any chip specific setup/optimisation/messages here */ -+ ata_pci_clear_simplex(pdev); -+ -+ /* And let the library code do the work */ -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id netcell_pci_tbl[] = { -+ { 0x169C, 0x0044, PCI_ANY_ID, PCI_ANY_ID, }, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver netcell_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = netcell_pci_tbl, -+ .probe = netcell_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init netcell_init(void) -+{ -+ return pci_register_driver(&netcell_pci_driver); -+} -+ -+static void __exit netcell_exit(void) -+{ -+ pci_unregister_driver(&netcell_pci_driver); -+} -+ -+ -+module_init(netcell_init); -+module_exit(netcell_exit); -+ -+MODULE_AUTHOR(""); -+MODULE_DESCRIPTION("SCSI low-level driver for Netcell PATA RAID"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, netcell_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_ns87410.c linux-2.6.16-rc4/drivers/scsi/pata_ns87410.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_ns87410.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_ns87410.c 2006-02-15 15:05:43.000000000 +0000 -@@ -0,0 +1,213 @@ -+/* -+ * pata_ns87410.c - National Semiconductor 87410 PATA for new ATA layer -+ * (C) 2006 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_ns87410" -+#define DRV_VERSION "0.1" -+ -+/** -+ * ns87410_phy_reset - probe reset -+ * @ap: ATA port -+ * -+ * Perform the ATA probe and bus reset sequence plus specific handling -+ * for this hardware. The MPIIX has the enable bits in a different place -+ * to PIIX4 and friends. As a pure PIO device it has no cable detect -+ */ -+ -+static void ns87410_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static const struct pci_bits ns87410_enable_bits[] = { -+ { 0x43, 1, 0x08, 0x08 }, -+ { 0x47, 1, 0x08, 0x08 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * ns87410_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program timing data. This is kept per channel not per device, -+ * and only affects the data port. -+ */ -+ -+static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x40 + 4 * ap->hard_port_no; -+ u8 idetcr, idefr; -+ struct ata_timing at; -+ -+ static const u8 activebits[15] = { -+ 0, 1, 2, 3, 4, -+ 5, 5, 6, 6, 6, -+ 6, 7, 7, 7, 7 -+ }; -+ -+ static const u8 recoverbits[12] = { -+ 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7 -+ }; -+ -+ pci_read_config_byte(pdev, port + 3, &idefr); -+ -+ if (ata_pio_need_iordy(adev)) -+ idefr |= 0x04; /* IORDY enable */ -+ else -+ idefr &= ~0x04; -+ -+ if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) { -+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode); -+ return; -+ } -+ -+ at.active = FIT(at.active, 2, 16) - 2; -+ at.setup = FIT(at.setup, 1, 4) - 1; -+ at.recover = FIT(at.recover, 1, 12) - 1; -+ -+ idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active]; -+ -+ pci_write_config_byte(pdev, port, idetcr); -+ pci_write_config_byte(pdev, port + 3, idefr); -+ /* We use ap->private_data as a pointer to the device currently -+ loaded for timing */ -+ ap->private_data = adev; -+} -+ -+/** -+ * ns87410_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so -+ * that, even if we get this wrong, cycles to the other device will -+ * be made PIO0. -+ */ -+ -+static int ns87410_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ -+ /* If modes have been configured and the channel data is not loaded -+ then load it. We have to check if pio_mode is set as the core code -+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be -+ logical */ -+ -+ if (adev->pio_mode && adev != ap->private_data) -+ ns87410_set_piomode(ap, adev); -+ -+ return ata_qc_issue_prot(qc); -+} -+ -+static struct scsi_host_template ns87410_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations ns87410_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = ns87410_set_piomode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = ns87410_phy_reset, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ns87410_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &ns87410_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x0F, -+ .port_ops = &ns87410_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = {&info, &info}; -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static const struct pci_device_id ns87410[] = { -+ { PCI_DEVICE(0x100B, 0xD001), }, -+ { 0, }, -+}; -+ -+static struct pci_driver ns87410_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = ns87410, -+ .probe = ns87410_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init ns87410_init(void) -+{ -+ return pci_register_driver(&ns87410_pci_driver); -+} -+ -+ -+static void __exit ns87410_exit(void) -+{ -+ pci_unregister_driver(&ns87410_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Nat Semi 87410"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, ns87410); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(ns87410_init); -+module_exit(ns87410_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_oldpiix.c linux-2.6.16-rc4/drivers/scsi/pata_oldpiix.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_oldpiix.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_oldpiix.c 2006-01-21 16:55:29.000000000 +0000 -@@ -0,0 +1,327 @@ -+/* -+ * pata_oldpiix.c - Intel PATA/SATA controllers -+ * -+ * (C) 2005 Red Hat <alan@redhat.com> -+ * -+ * Some parts based on ata_piix.c by Jeff Garzik and others. -+ * -+ * Early PIIX differs significantly from the later PIIX as it lacks -+ * SITRE and the slave timing registers. This means that you have to -+ * set timing per channel, or be clever. Libata tells us whenever it -+ * does drive selection and we use this to reload the timings. -+ * -+ * Because of these behaviour differences PIIX gets its own driver module. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_oldpiix" -+#define DRV_VERSION "0.3" -+ -+/** -+ * oldpiix_pata_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void oldpiix_pata_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static const struct pci_bits oldpiix_enable_bits[] = { -+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ -+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * oldpiix_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set PIO mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio = adev->pio_mode - XFER_PIO_0; -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ unsigned int idetm_port= ap->hard_port_no ? 0x42 : 0x40; -+ u16 idetm_data; -+ int control = 0; -+ -+ /* -+ * See Intel Document 298600-004 for the timing programing rules -+ * for PIIX/ICH. Note that the early PIIX does not have the slave -+ * timing port at 0x44. -+ */ -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; -+ -+ if (pio > 2) -+ control |= 1; /* TIME1 enable */ -+ if (ata_pio_need_iordy(adev)) -+ control |= 2; /* IE IORDY */ -+ -+ /* Intel specifies that the PPE functionality is for disk only */ -+ if (adev->class == ATA_DEV_ATA) -+ control |= 4; /* PPE enable */ -+ -+ pci_read_config_word(dev, idetm_port, &idetm_data); -+ -+ /* Enable PPE, IE and TIME as appropriate. Clear the other -+ drive timing bits */ -+ if (adev->devno == 0) { -+ idetm_data &= 0xCCE0; -+ idetm_data |= control; -+ } else { -+ idetm_data &= 0xCC0E; -+ idetm_data |= (control << 4); -+ } -+ idetm_data |= (timings[pio][0] << 12) | -+ (timings[pio][1] << 8); -+ pci_write_config_word(dev, idetm_port, idetm_data); -+ -+ /* Track which port is configured */ -+ ap->private_data = adev; -+} -+ -+/** -+ * oldpiix_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * @isich: True if the device is an ICH and has IOCFG registers -+ * -+ * Set MWDMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ u8 idetm_port = ap->hard_port_no ? 0x42 : 0x40; -+ u16 idetm_data; -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 0 }, -+ { 2, 1 }, -+ { 2, 3 }, }; -+ -+ /* -+ * MWDMA is driven by the PIO timings. We must also enable -+ * IORDY unconditionally along with TIME1. PPE has already -+ * been set when the PIO timing was set. -+ */ -+ -+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; -+ unsigned int control; -+ const unsigned int needed_pio[3] = { -+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 -+ }; -+ int pio = needed_pio[mwdma] - XFER_PIO_0; -+ -+ pci_read_config_word(dev, idetm_port, &idetm_data); -+ -+ control = 3; /* IORDY|TIME0 */ -+ /* Intel specifies that the PPE functionality is for disk only */ -+ if (adev->class == ATA_DEV_ATA) -+ control |= 4; /* PPE enable */ -+ -+ /* If the drive MWDMA is faster than it can do PIO then -+ we must force PIO into PIO0 */ -+ -+ if (adev->pio_mode < needed_pio[mwdma]) -+ /* Enable DMA timing only */ -+ control |= 8; /* PIO cycles in PIO0 */ -+ -+ /* Mask out the relevant control and timing bits we will load. Also -+ clear the other drive TIME register as a precaution */ -+ if (adev->devno == 0) { -+ idetm_data &= 0xCCE0; -+ idetm_data |= control; -+ } else { -+ idetm_data &= 0xCC0E; -+ idetm_data |= (control << 4); -+ } -+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); -+ pci_write_config_word(dev, idetm_port, idetm_data); -+ -+ /* Track which port is configured */ -+ ap->private_data = adev; -+} -+ -+/** -+ * oldpiix_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so -+ * that, even if we get this wrong, cycles to the other device will -+ * be made PIO0. -+ */ -+ -+static int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ -+ if (adev != ap->private_data) { -+ if (adev->dma_mode) -+ oldpiix_set_dmamode(ap, adev); -+ else if (adev->pio_mode) -+ oldpiix_set_piomode(ap, adev); -+ } -+ return ata_qc_issue_prot(qc); -+} -+ -+ -+static struct scsi_host_template oldpiix_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations oldpiix_pata_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = oldpiix_set_piomode, -+ .set_dmamode = oldpiix_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = oldpiix_pata_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = oldpiix_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+ -+/** -+ * oldpiix_init_one - Register PIIX ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in oldpiix_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. We probe for combined mode (sigh), -+ * and then hand over control to libata, for it to do the rest. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ static struct ata_port_info info = { -+ .sht = &oldpiix_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma1-2 */ -+ .port_ops = &oldpiix_pata_ops, -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id oldpiix_pci_tbl[] = { -+ { 0x8086, 0x1230, PCI_ANY_ID, PCI_ANY_ID, }, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver oldpiix_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = oldpiix_pci_tbl, -+ .probe = oldpiix_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init oldpiix_init(void) -+{ -+ return pci_register_driver(&oldpiix_pci_driver); -+} -+ -+static void __exit oldpiix_exit(void) -+{ -+ pci_unregister_driver(&oldpiix_pci_driver); -+} -+ -+ -+module_init(oldpiix_init); -+module_exit(oldpiix_exit); -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_opti.c linux-2.6.16-rc4/drivers/scsi/pata_opti.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_opti.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_opti.c 2006-02-16 15:38:28.000000000 +0000 -@@ -0,0 +1,268 @@ -+/* -+ * pata_opti.c - ATI PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based on -+ * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002 -+ * -+ * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) -+ * -+ * Authors: -+ * Jaromir Koutek <miri@punknet.cz>, -+ * Jan Harkes <jaharkes@cwi.nl>, -+ * Mark Lord <mlord@pobox.com> -+ * Some parts of code are from ali14xx.c and from rz1000.c. -+ * -+ * Also consulted the FreeBSD prototype driver by Kevin Day to try -+ * and resolve some confusions. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_opti" -+#define DRV_VERSION "0.1.2" -+ -+enum { -+ READ_REG = 0, /* index of Read cycle timing register */ -+ WRITE_REG = 1, /* index of Write cycle timing register */ -+ CNTRL_REG = 3, /* index of Control register */ -+ STRAP_REG = 5, /* index of Strap register */ -+ MISC_REG = 6 /* index of Miscellaneous register */ -+}; -+ -+/** -+ * opti_phy_reset - probe reset -+ * @ap: ATA port -+ * -+ * Perform the ATA probe and bus reset sequence plus specific handling -+ * for this hardware. The Opti needs little handling - we have no UDMA66 -+ * capability that needs cable detection. All we must do is check the port -+ * is enabled. -+ */ -+ -+static void opti_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static const struct pci_bits opti_enable_bits[] = { -+ { 0x45, 1, 0x80, 0x00 }, -+ { 0x45, 1, 0x08, 0x00 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * opti_write_reg - control register setup -+ * @ap: ATA port -+ * @value: value -+ * @reg: control register number -+ * -+ * The Opti uses magic 'trapdoor' register accesses to do configuration -+ * rather than using PCI space as other controllers do. The double inw -+ * on the error register activates configuration mode. We can then write -+ * the control register -+ */ -+ -+static void opti_write_reg(struct ata_port *ap, u8 val, int reg) -+{ -+ unsigned long regio = ap->ioaddr.cmd_addr; -+ inw(regio + 1); -+ inw(regio + 1); -+ outb(3, regio + 2); -+ outb(val, regio + reg); -+ outb(0x83, regio + 2); -+} -+ -+#if 0 -+/** -+ * opti_read_reg - control register read -+ * @ap: ATA port -+ * @reg: control register number -+ * -+ * The Opti uses magic 'trapdoor' register accesses to do configuration -+ * rather than using PCI space as other controllers do. The double inw -+ * on the error register activates configuration mode. We can then read -+ * the control register -+ */ -+ -+static u8 opti_read_reg(struct ata_port *ap, int reg) -+{ -+ unsigned long regio = ap->ioaddr.cmd_addr; -+ u8 ret; -+ inw(regio + 1); -+ inw(regio + 1); -+ outb(3, regio + 2); -+ ret = inb(regio + reg); -+ outb(0x83, regio + 2); -+} -+#endif -+ -+/** -+ * opti_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. Timing numbers are taken from -+ * the FreeBSD driver then pre computed to keep the code clean. There -+ * are two tables depending on the hardware clock speed. -+ */ -+ -+static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ int clock; -+ int pio = adev->pio_mode - XFER_PIO_0; -+ unsigned long regio = ap->ioaddr.cmd_addr; -+ u8 addr; -+ -+ /* Address table precomputed with prefetch off and a DCLK of 2 */ -+ static const u8 addr_timing[2][5] = { -+ { 0x30, 0x20, 0x20, 0x10, 0x10 }, -+ { 0x20, 0x20, 0x10, 0x10, 0x10 } -+ }; -+ static const u8 data_rec_timing[2][5] = { -+ { 0x6B, 0x56, 0x42, 0x32, 0x31 }, -+ { 0x58, 0x44, 0x32, 0x22, 0x21 } -+ }; -+ -+ outb(0xff, regio + 5); -+ clock = inw(regio + 5) & 1; -+ -+ /* -+ * As with many controllers the address setup time is shared -+ * and must suit both devices if present. -+ */ -+ -+ addr = addr_timing[clock][pio]; -+ if (pair) { -+ /* Hardware constraint */ -+ u8 pair_addr = addr_timing[clock][pair->pio_mode - XFER_PIO_0]; -+ if (pair_addr > addr) -+ addr = pair_addr; -+ } -+ -+ /* Commence primary programming sequence */ -+ opti_write_reg(ap, adev->devno, MISC_REG); -+ opti_write_reg(ap, data_rec_timing[clock][pio], READ_REG); -+ opti_write_reg(ap, data_rec_timing[clock][pio], WRITE_REG); -+ opti_write_reg(ap, addr, MISC_REG); -+ -+ /* Programming sequence complete, override strapping */ -+ opti_write_reg(ap, 0x85, CNTRL_REG); -+} -+ -+static struct scsi_host_template opti_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations opti_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = opti_set_piomode, -+/* .set_dmamode = opti_set_dmamode, */ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = opti_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &opti_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .port_ops = &opti_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ static int printed_version; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); -+ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static const struct pci_device_id opti[] = { -+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { 0, }, -+}; -+ -+static struct pci_driver opti_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = opti, -+ .probe = opti_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init opti_init(void) -+{ -+ return pci_register_driver(&opti_pci_driver); -+} -+ -+ -+static void __exit opti_exit(void) -+{ -+ pci_unregister_driver(&opti_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Opti 621/621X"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, opti); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(opti_init); -+module_exit(opti_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pcmcia.c linux-2.6.16-rc4/drivers/scsi/pata_pcmcia.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pcmcia.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_pcmcia.c 2006-02-20 17:26:30.000000000 +0000 -@@ -0,0 +1,406 @@ -+/* -+ * pata-pcmcia.c - PCMCIA PATA controller driver. -+ * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved. -+ * -+ * Heavily based upon ide-cs.c -+ * The initial developer of the original code is David A. Hinds -+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds -+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/ata.h> -+#include <linux/libata.h> -+ -+#include <pcmcia/cs_types.h> -+#include <pcmcia/cs.h> -+#include <pcmcia/cistpl.h> -+#include <pcmcia/ds.h> -+#include <pcmcia/cisreg.h> -+#include <pcmcia/ciscode.h> -+ -+ -+#define DRV_NAME "pata_pcmcia" -+#define DRV_VERSION "0.1" -+ -+/* -+ * Private data structure to glue stuff together -+ */ -+ -+struct ata_pcmcia_info { -+ dev_link_t link; -+ int ndev; -+ dev_node_t node; -+}; -+ -+static struct scsi_host_template pcmcia_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations pcmcia_port_ops = { -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+#define CS_CHECK(fn, ret) \ -+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -+ -+/** -+ * pcmcia_init_one - attach an pcmcia interface -+ * @pdev: pcmcia device -+ * -+ * Register a PCMCIA IDE interface. Such interfaces are PIO 0 and -+ * non shared IRQ. -+ */ -+ -+static int pcmcia_init_one(struct pcmcia_device *pdev) -+{ -+ struct ata_probe_ent ae; -+ dev_link_t *link; -+ struct ata_pcmcia_info *info; -+ client_handle_t handle; -+ tuple_t tuple; -+ struct { -+ unsigned short buf[128]; -+ cisparse_t parse; -+ config_info_t conf; -+ cistpl_cftable_entry_t dflt; -+ } *stk = NULL; -+ cistpl_cftable_entry_t *cfg; -+ int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM; -+ unsigned long io_base, ctl_base; -+ -+ info = kzalloc(sizeof(*info), GFP_KERNEL); -+ if (info == NULL) -+ return -ENOMEM; -+ -+ link = &info->link; -+ link->priv = info; -+ -+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; -+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; -+ link->io.IOAddrLines = 3; -+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; -+ link->irq.IRQInfo1 = IRQ_LEVEL_ID; -+ link->conf.Attributes = CONF_ENABLE_IRQ; -+ link->conf.Vcc = 50; -+ link->conf.IntType = INT_MEMORY_AND_IO; -+ -+ link->handle = pdev; -+ pdev->instance = link; -+ -+ handle = link->handle; -+ -+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; -+ -+ stk = kzalloc(sizeof(*stk), GFP_KERNEL); -+ if (!stk) -+ goto out1; -+ -+ cfg = &stk->parse.cftable_entry; -+ -+ tuple.TupleData = (cisdata_t *)&stk->buf; -+ tuple.TupleOffset = 0; -+ tuple.TupleDataMax = 255; -+ tuple.Attributes = 0; -+ tuple.DesiredTuple = CISTPL_CONFIG; -+ -+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); -+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); -+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &stk->parse)); -+ link->conf.ConfigBase = stk->parse.config.base; -+ link->conf.Present = stk->parse.config.rmask[0]; -+ -+ tuple.DesiredTuple = CISTPL_MANFID; -+ if (!pcmcia_get_first_tuple(handle, &tuple) && !pcmcia_get_tuple_data(handle, &tuple) && !pcmcia_parse_tuple(handle, &tuple, &stk->parse)) -+ is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B))); -+ -+ /* Configure card */ -+ link->state |= DEV_CONFIG; -+ -+ /* Not sure if this is right... look up the current Vcc */ -+ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &stk->conf)); -+ link->conf.Vcc = stk->conf.Vcc; -+ -+ pass = io_base = ctl_base = 0; -+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; -+ tuple.Attributes = 0; -+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); -+ -+ while (1) { -+ if (pcmcia_get_tuple_data(handle, &tuple) != 0) -+ goto next_entry; -+ if (pcmcia_parse_tuple(handle, &tuple, &stk->parse) != 0) -+ goto next_entry; -+ /* Check for matching Vcc, unless we're desperate */ -+ if (!pass) { -+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { -+ if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) -+ goto next_entry; -+ } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { -+ if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) -+ goto next_entry; -+ } -+ } -+ -+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) -+ link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; -+ else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) -+ link->conf.Vpp1 = link->conf.Vpp2 = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; -+ -+ if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { -+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; -+ link->conf.ConfigIndex = cfg->index; -+ link->io.BasePort1 = io->win[0].base; -+ link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; -+ if (!(io->flags & CISTPL_IO_16BIT)) -+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; -+ if (io->nwin == 2) { -+ link->io.NumPorts1 = 8; -+ link->io.BasePort2 = io->win[1].base; -+ link->io.NumPorts2 = (is_kme) ? 2 : 1; -+ if (pcmcia_request_io(link->handle, &link->io) != 0) -+ goto next_entry; -+ io_base = link->io.BasePort1; -+ ctl_base = link->io.BasePort2; -+ } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { -+ link->io.NumPorts1 = io->win[0].len; -+ link->io.NumPorts2 = 0; -+ if (pcmcia_request_io(link->handle, &link->io) != 0) -+ goto next_entry; -+ io_base = link->io.BasePort1; -+ ctl_base = link->io.BasePort1 + 0x0e; -+ } else goto next_entry; -+ /* If we've got this far, we're done */ -+ break; -+ } -+next_entry: -+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT) -+ memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); -+ if (pass) { -+ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); -+ } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) { -+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); -+ memset(&stk->dflt, 0, sizeof(stk->dflt)); -+ pass++; -+ } -+ } -+ -+ if (is_kme) -+ outb(0x81, ctl_base + 0x01); -+ -+ /* FIXME: Could be more ports at base + 0x10 but we only deal with -+ one right now */ -+ -+ if (link->io.NumPorts1 >= 0x20) -+ printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n"); -+ -+ /* -+ * Having done the PCMCIA plumbing the ATA side is relatively -+ * sane. -+ */ -+ -+ memset(&ae, 0, sizeof(struct ata_probe_ent)); -+ INIT_LIST_HEAD(&ae.node); -+ ae.dev = &pdev->dev; -+ ae.port_ops = &pcmcia_port_ops; -+ ae.sht = &pcmcia_sht; -+ ae.n_ports = 1; -+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */ -+ ae.irq = link->irq.AssignedIRQ; -+ ae.irq_flags = 0; -+ ae.host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IRQ_MASK; -+ ae.port[0].cmd_addr = io_base; -+ ae.port[0].altstatus_addr = ctl_base; -+ ae.port[0].ctl_addr = ctl_base; -+ ata_std_ports(&ae.port[0]); -+ -+ if (ata_device_add(&ae) == 0) -+ goto failed; -+ -+ info->ndev = 1; -+ link->dev = &info->node; -+ link->state &= ~DEV_CONFIG_PENDING; -+ kfree(stk); -+ return 0; -+ -+cs_failed: -+ cs_error(link->handle, last_fn, last_ret); -+failed: -+ kfree(stk); -+ info->ndev = 0; -+ link->dev = NULL; -+ -+ pcmcia_release_configuration(link->handle); -+ pcmcia_release_io(link->handle, &link->io); -+ pcmcia_release_irq(link->handle, &link->irq); -+ -+ link->state &= ~DEV_CONFIG; -+out1: -+ kfree(info); -+ return ret; -+} -+ -+/** -+ * pcmcia_remove_one - unplug an pcmcia interface -+ * @pdev: pcmcia device -+ * -+ * A PCMCIA ATA device has been unplugged. Perform the needed -+ * cleanup. Also called on module unload for any active devices. -+ */ -+ -+void pcmcia_remove_one(struct pcmcia_device *pdev) -+{ -+ dev_link_t *link = dev_to_instance(pdev); -+ struct ata_pcmcia_info *info = link->priv; -+ struct device *dev = &pdev->dev; -+ -+ if (link->state & DEV_CONFIG) { -+ if (info->ndev) { -+ struct ata_host_set *host_set = dev_get_drvdata(dev); -+ ata_host_set_remove(host_set); -+ dev_set_drvdata(dev, NULL); -+ } -+ info->ndev = 0; -+ link->dev = NULL; -+ -+ pcmcia_release_configuration(link->handle); -+ pcmcia_release_io(link->handle, &link->io); -+ pcmcia_release_irq(link->handle, &link->irq); -+ link->state &= ~DEV_CONFIG; -+ } -+ kfree(link->priv); -+} -+ -+static int pcmcia_suspend(struct pcmcia_device *dev) -+{ -+ dev_link_t *link = dev_to_instance(dev); -+ -+ link->state |= DEV_SUSPEND; -+ if (link->state & DEV_CONFIG) -+ pcmcia_release_configuration(link->handle); -+ -+ return 0; -+} -+ -+static int pcmcia_resume(struct pcmcia_device *dev) -+{ -+ dev_link_t *link = dev_to_instance(dev); -+ -+ link->state &= ~DEV_SUSPEND; -+ if (DEV_OK(link)) -+ pcmcia_request_configuration(link->handle, &link->conf); -+ -+ return 0; -+} -+ -+static struct pcmcia_device_id pcmcia_devices[] = { -+ PCMCIA_DEVICE_FUNC_ID(4), -+ PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ -+ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), -+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), -+ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ -+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), -+ PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ -+ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ -+ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), -+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ -+ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), -+ PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), -+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), -+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), -+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), -+ PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), -+ PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), -+ PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), -+ PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf), -+ PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), -+ PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), -+ PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), -+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), -+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), -+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), -+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), -+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), -+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674), -+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b), -+ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79), -+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591), -+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728), -+ PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1), -+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), -+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), -+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), -+ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), -+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), -+ PCMCIA_DEVICE_NULL, -+}; -+ -+MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices); -+ -+static struct pcmcia_driver pcmcia_driver = { -+ .owner = THIS_MODULE, -+ .drv = { -+ .name = DRV_NAME, -+ }, -+ .id_table = pcmcia_devices, -+ .probe = pcmcia_init_one, -+ .remove = pcmcia_remove_one, -+ .suspend = pcmcia_suspend, -+ .resume = pcmcia_resume, -+}; -+ -+static int __init pcmcia_init(void) -+{ -+ return pcmcia_register_driver(&pcmcia_driver); -+} -+ -+static void __exit pcmcia_exit(void) -+{ -+ pcmcia_unregister_driver(&pcmcia_driver); -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for PCMCIA ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(pcmcia_init); -+module_exit(pcmcia_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pdc2027x.c linux-2.6.16-rc4/drivers/scsi/pata_pdc2027x.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pdc2027x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_pdc2027x.c 2006-01-21 16:56:47.000000000 +0000 -@@ -0,0 +1,857 @@ -+/* -+ * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277. -+ * -+ * 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. -+ * -+ * Ported to libata by: -+ * Albert Lee <albertcc@tw.ibm.com> IBM Corporation -+ * -+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> -+ * Portions Copyright (C) 1999 Promise Technology, Inc. -+ * -+ * Author: Frank Tiernan (frankt@promise.com) -+ * Released under terms of General Public License -+ * -+ * -+ * libata documentation is available via 'make {ps|pdf}docs', -+ * as Documentation/DocBook/libata.* -+ * -+ * Hardware information only available under NDA. -+ * -+ */ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi.h> -+#include <scsi/scsi_host.h> -+#include <scsi/scsi_cmnd.h> -+#include <linux/libata.h> -+#include <asm/io.h> -+ -+#define DRV_NAME "pata_pdc2027x" -+#define DRV_VERSION "0.73" -+#undef PDC_DEBUG -+ -+#ifdef PDC_DEBUG -+#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) -+#else -+#define PDPRINTK(fmt, args...) -+#endif -+ -+enum { -+ PDC_UDMA_100 = 0, -+ PDC_UDMA_133 = 1, -+ -+ PDC_100_MHZ = 100000000, -+ PDC_133_MHZ = 133333333, -+ -+ PDC_SYS_CTL = 0x1100, -+ PDC_ATA_CTL = 0x1104, -+ PDC_GLOBAL_CTL = 0x1108, -+ PDC_CTCR0 = 0x110C, -+ PDC_CTCR1 = 0x1110, -+ PDC_BYTE_COUNT = 0x1120, -+ PDC_PLL_CTL = 0x1202, -+}; -+ -+static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -+static void pdc2027x_remove_one(struct pci_dev *pdev); -+static void pdc2027x_phy_reset(struct ata_port *ap); -+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); -+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); -+static void pdc2027x_post_set_mode(struct ata_port *ap); -+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); -+ -+/* -+ * ATA Timing Tables based on 133MHz controller clock. -+ * These tables are only used when the controller is in 133MHz clock. -+ * If the controller is in 100MHz clock, the ASIC hardware will -+ * set the timing registers automatically when "set feature" command -+ * is issued to the device. However, if the controller clock is 133MHz, -+ * the following tables must be used. -+ */ -+static struct pdc2027x_pio_timing { -+ u8 value0, value1, value2; -+} pdc2027x_pio_timing_tbl [] = { -+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */ -+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */ -+ { 0x23, 0x26, 0x64 }, /* PIO mode 2 */ -+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ -+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ -+}; -+ -+static struct pdc2027x_mdma_timing { -+ u8 value0, value1; -+} pdc2027x_mdma_timing_tbl [] = { -+ { 0xdf, 0x5f }, /* MDMA mode 0 */ -+ { 0x6b, 0x27 }, /* MDMA mode 1 */ -+ { 0x69, 0x25 }, /* MDMA mode 2 */ -+}; -+ -+static struct pdc2027x_udma_timing { -+ u8 value0, value1, value2; -+} pdc2027x_udma_timing_tbl [] = { -+ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ -+ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ -+ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ -+ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ -+ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ -+ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ -+ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ -+}; -+ -+static const struct pci_device_id pdc2027x_pci_tbl[] = { -+#ifdef ATA_ENABLE_PATA -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, -+#endif -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver pdc2027x_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = pdc2027x_pci_tbl, -+ .probe = pdc2027x_init_one, -+ .remove = __devexit_p(pdc2027x_remove_one), -+}; -+ -+static struct scsi_host_template pdc2027x_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+}; -+ -+static struct ata_port_operations pdc2027x_pata100_ops = { -+ .port_disable = ata_port_disable, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = pdc2027x_phy_reset, -+ -+ .check_atapi_dma = pdc2027x_check_atapi_dma, -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_mmio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static struct ata_port_operations pdc2027x_pata133_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = pdc2027x_set_piomode, -+ .set_dmamode = pdc2027x_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = pdc2027x_phy_reset, -+ .post_set_mode = pdc2027x_post_set_mode, -+ -+ .check_atapi_dma = pdc2027x_check_atapi_dma, -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_mmio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static struct ata_port_info pdc2027x_port_info[] = { -+ /* PDC_UDMA_100 */ -+ { -+ .sht = &pdc2027x_sht, -+ .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | -+ ATA_FLAG_SRST | ATA_FLAG_MMIO, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = ATA_UDMA5, /* udma0-5 */ -+ .port_ops = &pdc2027x_pata100_ops, -+ }, -+ /* PDC_UDMA_133 */ -+ { -+ .sht = &pdc2027x_sht, -+ .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | -+ ATA_FLAG_SRST | ATA_FLAG_MMIO, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma0-2 */ -+ .udma_mask = ATA_UDMA6, /* udma0-6 */ -+ .port_ops = &pdc2027x_pata133_ops, -+ }, -+}; -+ -+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee"); -+MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl); -+ -+/** -+ * port_mmio - Get the MMIO address of PDC2027x extended registers -+ * @ap: Port -+ * @offset: offset from mmio base -+ */ -+static inline void* port_mmio(struct ata_port *ap, unsigned int offset) -+{ -+ return ap->host_set->mmio_base + ap->port_no * 0x100 + offset; -+} -+ -+/** -+ * dev_mmio - Get the MMIO address of PDC2027x extended registers -+ * @ap: Port -+ * @adev: device -+ * @offset: offset from mmio base -+ */ -+static inline void* dev_mmio(struct ata_port *ap, struct ata_device *adev, unsigned int offset) -+{ -+ u8 adj = (adev->devno) ? 0x08 : 0x00; -+ return port_mmio(ap, offset) + adj; -+} -+ -+/** -+ * pdc2027x_pata_cbl_detect - Probe host controller cable detect info -+ * @ap: Port for which cable detect info is desired -+ * -+ * Read 80c cable indicator from Promise extended register. -+ * This register is latched when the system is reset. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+static void pdc2027x_cbl_detect(struct ata_port *ap) -+{ -+ u32 cgcr; -+ -+ /* check cable detect results */ -+ cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL)); -+ if (cgcr & (1 << 26)) -+ goto cbl40; -+ -+ PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no); -+ -+ ap->cbl = ATA_CBL_PATA80; -+ return; -+ -+cbl40: -+ printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no); -+ ap->cbl = ATA_CBL_PATA40; -+ ap->udma_mask &= ATA_UDMA_MASK_40C; -+} -+ -+/** -+ * pdc2027x_port_enabled - Check PDC ATA control register to see whether the port is enabled. -+ * @ap: Port to check -+ */ -+static inline int pdc2027x_port_enabled(struct ata_port *ap) -+{ -+ return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02; -+} -+ -+/** -+ * pdc2027x_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * Probe PATA phy. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+static void pdc2027x_phy_reset(struct ata_port *ap) -+{ -+ /* Check whether port enabled */ -+ if (!pdc2027x_port_enabled(ap)) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ -+ pdc2027x_cbl_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * pdc2027x_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port to configure -+ * @adev: um -+ * @pio: PIO mode, 0 - 4 -+ * -+ * Set PIO mode for device. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio = adev->pio_mode - XFER_PIO_0; -+ u32 ctcr0, ctcr1; -+ -+ PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode); -+ -+ /* Sanity check */ -+ if (pio > 4) { -+ printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio); -+ return; -+ -+ } -+ -+ /* Set the PIO timing registers using value table for 133MHz */ -+ PDPRINTK("Set pio regs... \n"); -+ -+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); -+ ctcr0 &= 0xffff0000; -+ ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 | -+ (pdc2027x_pio_timing_tbl[pio].value1 << 8); -+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); -+ -+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); -+ ctcr1 &= 0x00ffffff; -+ ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24); -+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); -+ -+ PDPRINTK("Set pio regs done\n"); -+ -+ PDPRINTK("Set to pio mode[%u] \n", pio); -+} -+ -+/** -+ * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings -+ * @ap: Port to configure -+ * @adev: um -+ * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6 -+ * -+ * Set UDMA mode for device. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int dma_mode = adev->dma_mode; -+ u32 ctcr0, ctcr1; -+ -+ if ((dma_mode >= XFER_UDMA_0) && -+ (dma_mode <= XFER_UDMA_6)) { -+ /* Set the UDMA timing registers with value table for 133MHz */ -+ unsigned int udma_mode = dma_mode & 0x07; -+ -+ if (dma_mode == XFER_UDMA_2) { -+ /* -+ * Turn off tHOLD. -+ * If tHOLD is '1', the hardware will add half clock for data hold time. -+ * This code segment seems to be no effect. tHOLD will be overwritten below. -+ */ -+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); -+ writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1)); -+ } -+ -+ PDPRINTK("Set udma regs... \n"); -+ -+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1)); -+ ctcr1 &= 0xff000000; -+ ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 | -+ (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) | -+ (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16); -+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1)); -+ -+ PDPRINTK("Set udma regs done\n"); -+ -+ PDPRINTK("Set to udma mode[%u] \n", udma_mode); -+ -+ } else if ((dma_mode >= XFER_MW_DMA_0) && -+ (dma_mode <= XFER_MW_DMA_2)) { -+ /* Set the MDMA timing registers with value table for 133MHz */ -+ unsigned int mdma_mode = dma_mode & 0x07; -+ -+ PDPRINTK("Set mdma regs... \n"); -+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0)); -+ -+ ctcr0 &= 0x0000ffff; -+ ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) | -+ (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24); -+ -+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0)); -+ PDPRINTK("Set mdma regs done\n"); -+ -+ PDPRINTK("Set to mdma mode[%u] \n", mdma_mode); -+ } else { -+ printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode); -+ } -+} -+ -+/** -+ * pdc2027x_post_set_mode - Set the timing registers back to correct values. -+ * @ap: Port to configure -+ * -+ * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers -+ * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL. -+ * This function overwrites the possibly incorrect values set by the hardware to be correct. -+ */ -+static void pdc2027x_post_set_mode(struct ata_port *ap) -+{ -+ int i; -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *dev = &ap->device[i]; -+ -+ if (ata_dev_present(dev)) { -+ -+ pdc2027x_set_piomode(ap, dev); -+ -+ /* -+ * Enable prefetch if the device support PIO only. -+ */ -+ if (dev->xfer_shift == ATA_SHIFT_PIO) { -+ u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1)); -+ ctcr1 |= (1 << 25); -+ writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1)); -+ -+ PDPRINTK("Turn on prefetch\n"); -+ } else { -+ pdc2027x_set_dmamode(ap, dev); -+ } -+ } -+ } -+} -+ -+/** -+ * pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command -+ * @qc: Metadata associated with taskfile to check -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ * -+ * RETURNS: 0 when ATAPI DMA can be used -+ * 1 otherwise -+ */ -+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc) -+{ -+ struct scsi_cmnd *cmd = qc->scsicmd; -+ u8 *scsicmd = cmd->cmnd; -+ int rc = 1; /* atapi dma off by default */ -+ -+ /* -+ * This workaround is from Promise's GPL driver. -+ * If ATAPI DMA is used for commands not in the -+ * following white list, say MODE_SENSE and REQUEST_SENSE, -+ * pdc2027x might hit the irq lost problem. -+ */ -+ switch (scsicmd[0]) { -+ case READ_10: -+ case WRITE_10: -+ case READ_12: -+ case WRITE_12: -+ case READ_6: -+ case WRITE_6: -+ case 0xad: /* READ_DVD_STRUCTURE */ -+ case 0xbe: /* READ_CD */ -+ /* ATAPI DMA is ok */ -+ rc = 0; -+ break; -+ default: -+ ; -+ } -+ -+ return rc; -+} -+ -+/** -+ * pdc_read_counter - Read the ctr counter -+ * @probe_ent: for the port address -+ */ -+ -+static long pdc_read_counter(struct ata_probe_ent *probe_ent) -+{ -+ long counter; -+ int retry = 1; -+ u32 bccrl, bccrh, bccrlv, bccrhv; -+ -+retry: -+ bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; -+ bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; -+ rmb(); -+ -+ /* Read the counter values again for verification */ -+ bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; -+ bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; -+ rmb(); -+ -+ counter = (bccrh << 15) | bccrl; -+ -+ PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh, bccrl); -+ PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv); -+ -+ /* -+ * The 30-bit decreasing counter are read by 2 pieces. -+ * Incorrect value may be read when both bccrh and bccrl are changing. -+ * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read. -+ */ -+ if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) { -+ retry--; -+ PDPRINTK("rereading counter\n"); -+ goto retry; -+ } -+ -+ return counter; -+} -+ -+/** -+ * adjust_pll - Adjust the PLL input clock in Hz. -+ * -+ * @pdc_controller: controller specific information -+ * @probe_ent: For the port address -+ * @pll_clock: The input of PLL in HZ -+ */ -+static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx) -+{ -+ -+ u16 pll_ctl; -+ long pll_clock_khz = pll_clock / 1000; -+ long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; -+ long ratio = pout_required / pll_clock_khz; -+ int F, R; -+ -+ /* Sanity check */ -+ if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) { -+ printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz); -+ return; -+ } -+ -+#ifdef PDC_DEBUG -+ PDPRINTK("pout_required is %ld\n", pout_required); -+ -+ /* Show the current clock value of PLL control register -+ * (maybe already configured by the firmware) -+ */ -+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); -+ -+ PDPRINTK("pll_ctl[%X]\n", pll_ctl); -+#endif -+ -+ /* -+ * Calculate the ratio of F, R and OD -+ * POUT = (F + 2) / (( R + 2) * NO) -+ */ -+ if (ratio < 8600L) { /* 8.6x */ -+ /* Using NO = 0x01, R = 0x0D */ -+ R = 0x0d; -+ } else if (ratio < 12900L) { /* 12.9x */ -+ /* Using NO = 0x01, R = 0x08 */ -+ R = 0x08; -+ } else if (ratio < 16100L) { /* 16.1x */ -+ /* Using NO = 0x01, R = 0x06 */ -+ R = 0x06; -+ } else if (ratio < 64000L) { /* 64x */ -+ R = 0x00; -+ } else { -+ /* Invalid ratio */ -+ printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio); -+ return; -+ } -+ -+ F = (ratio * (R+2)) / 1000 - 2; -+ -+ if (unlikely(F < 0 || F > 127)) { -+ /* Invalid F */ -+ printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F); -+ return; -+ } -+ -+ PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio); -+ -+ pll_ctl = (R << 8) | F; -+ -+ PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); -+ -+ writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL); -+ readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */ -+ -+ /* Wait the PLL circuit to be stable */ -+ mdelay(30); -+ -+#ifdef PDC_DEBUG -+ /* -+ * Show the current clock value of PLL control register -+ * (maybe configured by the firmware) -+ */ -+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); -+ -+ PDPRINTK("pll_ctl[%X]\n", pll_ctl); -+#endif -+ -+ return; -+} -+ -+/** -+ * detect_pll_input_clock - Detect the PLL input clock in Hz. -+ * @probe_ent: for the port address -+ * Ex. 16949000 on 33MHz PCI bus for pdc20275. -+ * Half of the PCI clock. -+ */ -+static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) -+{ -+ u32 scr; -+ long start_count, end_count; -+ long pll_clock; -+ -+ /* Read current counter value */ -+ start_count = pdc_read_counter(probe_ent); -+ -+ /* Start the test mode */ -+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); -+ PDPRINTK("scr[%X]\n", scr); -+ writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); -+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ -+ -+ /* Let the counter run for 100 ms. */ -+ mdelay(100); -+ -+ /* Read the counter values again */ -+ end_count = pdc_read_counter(probe_ent); -+ -+ /* Stop the test mode */ -+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); -+ PDPRINTK("scr[%X]\n", scr); -+ writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); -+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ -+ -+ /* calculate the input clock in Hz */ -+ pll_clock = (start_count - end_count) * 10; -+ -+ PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count); -+ PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock); -+ -+ return pll_clock; -+} -+ -+/** -+ * pdc_hardware_init - Initialize the hardware. -+ * @pdev: instance of pci_dev found -+ * @pdc_controller: controller specific information -+ * @pe: for the port address -+ */ -+static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx) -+{ -+ long pll_clock; -+ -+ /* -+ * Detect PLL input clock rate. -+ * On some system, where PCI bus is running at non-standard clock rate. -+ * Ex. 25MHz or 40MHz, we have to adjust the cycle_time. -+ * The pdc20275 controller employs PLL circuit to help correct timing registers setting. -+ */ -+ pll_clock = pdc_detect_pll_input_clock(pe); -+ -+ if (pll_clock < 0) /* counter overflow? Try again. */ -+ pll_clock = pdc_detect_pll_input_clock(pe); -+ -+ dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000); -+ -+ /* Adjust PLL control register */ -+ pdc_adjust_pll(pe, pll_clock, board_idx); -+ -+ return 0; -+} -+ -+/** -+ * pdc_ata_setup_port - setup the mmio address -+ * @port: ata ioports to setup -+ * @base: base address -+ */ -+static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) -+{ -+ port->cmd_addr = -+ port->data_addr = base; -+ port->feature_addr = -+ port->error_addr = base + 0x05; -+ port->nsect_addr = base + 0x0a; -+ port->lbal_addr = base + 0x0f; -+ port->lbam_addr = base + 0x10; -+ port->lbah_addr = base + 0x15; -+ port->device_addr = base + 0x1a; -+ port->command_addr = -+ port->status_addr = base + 0x1f; -+ port->altstatus_addr = -+ port->ctl_addr = base + 0x81a; -+} -+ -+/** -+ * pdc2027x_init_one - PCI probe function -+ * Called when an instance of PCI adapter is inserted. -+ * This function checks whether the hardware is supported, -+ * initialize hardware and register an instance of ata_host_set to -+ * libata by providing struct ata_probe_ent and ata_device_add(). -+ * (implements struct pci_driver.probe() ) -+ * -+ * @pdev: instance of pci_dev found -+ * @ent: matching entry in the id_tbl[] -+ */ -+static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ unsigned int board_idx = (unsigned int) ent->driver_data; -+ -+ struct ata_probe_ent *probe_ent = NULL; -+ unsigned long base; -+ void *mmio_base; -+ int rc; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); -+ -+ rc = pci_enable_device(pdev); -+ if (rc) -+ return rc; -+ -+ rc = pci_request_regions(pdev, DRV_NAME); -+ if (rc) -+ goto err_out; -+ -+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); -+ if (rc) -+ goto err_out_regions; -+ -+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); -+ if (rc) -+ goto err_out_regions; -+ -+ /* Prepare the probe entry */ -+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); -+ if (probe_ent == NULL) { -+ rc = -ENOMEM; -+ goto err_out_regions; -+ } -+ -+ memset(probe_ent, 0, sizeof(*probe_ent)); -+ probe_ent->dev = pci_dev_to_dev(pdev); -+ INIT_LIST_HEAD(&probe_ent->node); -+ -+ mmio_base = ioremap(pci_resource_start(pdev, 5), -+ pci_resource_len(pdev, 5)); -+ -+ if (mmio_base == NULL) { -+ rc = -ENOMEM; -+ goto err_out_free_ent; -+ } -+ -+ base = (unsigned long) mmio_base; -+ -+ probe_ent->sht = pdc2027x_port_info[board_idx].sht; -+ probe_ent->host_flags = pdc2027x_port_info[board_idx].host_flags; -+ probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask; -+ probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask; -+ probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask; -+ probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops; -+ -+ probe_ent->irq = pdev->irq; -+ probe_ent->irq_flags = SA_SHIRQ; -+ probe_ent->mmio_base = mmio_base; -+ -+ pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0); -+ probe_ent->port[0].bmdma_addr = base + 0x1000; -+ pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0); -+ probe_ent->port[1].bmdma_addr = base + 0x1008; -+ -+ probe_ent->n_ports = 2; -+ -+ pci_set_master(pdev); -+ //pci_enable_intx(pdev); -+ -+ /* initialize adapter */ -+ if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0) -+ goto err_out_free_ent; -+ -+ ata_device_add(probe_ent); -+ kfree(probe_ent); -+ -+ return 0; -+ -+err_out_free_ent: -+ kfree(probe_ent); -+err_out_regions: -+ pci_release_regions(pdev); -+err_out: -+ pci_disable_device(pdev); -+ return rc; -+} -+ -+/** -+ * pdc2027x_remove_one - Called to remove a single instance of the -+ * adapter. -+ * -+ * @dev: The PCI device to remove. -+ * FIXME: module load/unload not working yet -+ */ -+static void __devexit pdc2027x_remove_one(struct pci_dev *pdev) -+{ -+ ata_pci_remove_one(pdev); -+} -+ -+/** -+ * pdc2027x_init - Called after this module is loaded into the kernel. -+ */ -+static int __init pdc2027x_init(void) -+{ -+ return pci_register_driver(&pdc2027x_pci_driver); -+} -+ -+/** -+ * pdc2027x_exit - Called before this module unloaded from the kernel -+ */ -+static void __exit pdc2027x_exit(void) -+{ -+ pci_unregister_driver(&pdc2027x_pci_driver); -+} -+ -+module_init(pdc2027x_init); -+module_exit(pdc2027x_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pdc202xx_old.c linux-2.6.16-rc4/drivers/scsi/pata_pdc202xx_old.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_pdc202xx_old.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_pdc202xx_old.c 2006-02-20 13:19:57.000000000 +0000 -@@ -0,0 +1,428 @@ -+/* -+ * pata_pdc202xx_old.c - SL82C105 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based in part on linux/drivers/ide/pci/pdc202xx_old.c -+ * -+ * Initial revision -+ * -+ * TODO: -+ * Channel interlock/reset on both required ? -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_pdc202xx_old" -+#define DRV_VERSION "0.1.2" -+ -+static void pdc2024x_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+ -+static void pdc2026x_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u16 cis; -+ -+ pci_read_config_word(pdev, 0x50, &cis); -+ if (cis & (1 << (10 + ap->hard_port_no))) -+ ap->cbl = ATA_CBL_PATA80; -+ else -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+ -+/** -+ * pdc_configure_piomode - set chip PIO timing -+ * @ap: ATA interface -+ * @adev: ATA device -+ * @pio: PIO mode -+ * -+ * Called to do the PIO mode setup. Our timing registers are shared -+ * so a configure_dmamode call will undo any work we do here and vice -+ * versa -+ */ -+ -+static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x60 + 4 * ap->hard_port_no + 2 * adev->devno; -+ static u16 pio_timing[5] = { -+ 0x0913, 0x050C , 0x0308, 0x0206, 0x0104 -+ }; -+ u8 r_ap, r_bp; -+ -+ /* FIFO, IORDY ? */ -+ pci_read_config_byte(pdev, port, &r_ap); -+ pci_read_config_byte(pdev, port + 1, &r_bp); -+ r_ap &= ~0x0F; -+ r_bp &= ~0x07; -+ r_ap |= (pio_timing[pio] >> 8); -+ r_bp |= (pio_timing[pio] & 0xFF); -+ pci_write_config_byte(pdev, port, r_ap); -+ pci_write_config_byte(pdev, port + 1, r_bp); -+} -+ -+/** -+ * pdc_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. Our timing registers are shared -+ * but we want to set the PIO timing by default. -+ */ -+ -+static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); -+} -+ -+/** -+ * pdc_configure_dmamode - set DMA mode in chip -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Load DMA cycle times into the chip ready for a DMA transfer -+ * to occur. -+ */ -+ -+static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x60 + 4 * ap->hard_port_no + 2 * adev->devno; -+ static u8 udma_timing[6][2] = { -+ { 0x60, 0x03 }, /* 33 Mhz Clock */ -+ { 0x40, 0x02 }, -+ { 0x20, 0x01 }, -+ { 0x40, 0x02 }, /* 66 Mhz Clock */ -+ { 0x20, 0x01 }, -+ { 0x20, 0x01 } -+ }; -+ u8 r_bp, r_cp; -+ -+ pci_read_config_byte(pdev, port + 1, &r_bp); -+ pci_read_config_byte(pdev, port + 2, &r_cp); -+ -+ r_bp &= ~0xF0; -+ r_cp &= ~0x0F; -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ int speed = adev->dma_mode - XFER_UDMA_0; -+ r_bp |= udma_timing[speed][0]; -+ r_cp |= udma_timing[speed][1]; -+ -+ } else { -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ r_bp |= 0x60; -+ r_cp |= (5 - speed); -+ } -+ pci_write_config_byte(pdev, port + 1, r_bp); -+ pci_write_config_byte(pdev, port + 2, r_cp); -+ -+} -+ -+/** -+ * pdc2026x_reset_engine - Reset the DMA engine -+ * @ap: ATA interface -+ * -+ * Reset the 2026x DMA engine. This is not something we want to do, -+ * and we need to figure out how to serialize this across dual channel -+ * devices if it is neccessary. -+ * -+ * FIXME: Do we need to reset the other interface too ? -+ */ -+ -+static void pdc2026x_reset_engine(struct ata_port *ap) -+{ -+ unsigned long ctrl = ap->host_set->ports[0]->ioaddr.bmdma_addr + 0x1F; -+ -+ u8 val = inb(ctrl); -+ outb(val | 0x10, ctrl); -+ mdelay(100); -+ outb(val & ~0x10, ctrl); -+ mdelay(2000); /* Check - seems to be overkill, plus if needed -+ redo locking */ -+ /* Need to fix up speed info at this point */ -+} -+ -+/** -+ * pdc2026x_bmdma_start - DMA engine begin -+ * @qc: ATA command -+ * -+ * In UDMA3 or higher we have to clock switch for the duration of the -+ * DMA transfer sequence. -+ */ -+ -+static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ int sel66 = ap->hard_port_no ? 0x08: 0x02; -+ /* The clock bits are in the same register for both channels */ -+ unsigned long clock = ap->host_set->ports[0]->ioaddr.bmdma_addr + 0x11; -+ -+ /* Check we keep host_set level locking here */ -+ if (adev->dma_mode >= XFER_UDMA_2) -+ outb(inb(clock) | sel66, clock); -+ else -+ outb(inb(clock) & ~sel66, clock); -+ /* The DMA clocks may have been trashed by a reset. FIXME: make conditional -+ and move to qc_issue ? */ -+ pdc_set_dmamode(ap, qc->dev); -+ /* Activate DMA */ -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * pdc2026x_bmdma_end - DMA engine stop -+ * @qc: ATA command -+ * -+ * After a DMA completes we need to put the clock back to 33MHz for -+ * PIO timings. -+ */ -+ -+static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ int sel66 = ap->hard_port_no ? 0x08: 0x02; -+ /* The clock bits are in the same register for both channels */ -+ unsigned long clock = ap->host_set->ports[0]->ioaddr.bmdma_addr + 0x11; -+ -+ /* FIXME: Review LBA48 code in ide/pci driver */ -+ ata_bmdma_stop(qc); -+ /* Check we keep host_set level locking here */ -+ /* Flip back to 33Mhz for PIO */ -+ if (adev->dma_mode >= XFER_UDMA_2) -+ outb(inb(clock) & ~sel66, clock); -+} -+ -+/** -+ * pdc2026x_eng_timeout - command timeout -+ * @qc: command that timed out -+ * -+ * When the PDC2026x times out hit the controller over the head -+ * with a hammer before continuing. The reset unfortunately also -+ * resets the timing registers so we must reprogram these. -+ */ -+ -+static void pdc2026x_eng_timeout(struct ata_port *ap) -+{ -+ int i; -+ -+ /* Perform libata side housekeeping */ -+ ata_eng_timeout(ap); -+ -+ /* Reset the controller */ -+ pdc2026x_reset_engine(ap); -+ -+ /* Reprogram the device timings */ -+ for (i = 0; i < 2; i++) { -+ struct ata_device *adev = &ap->device[i]; -+ if (ata_dev_present(adev)) { -+ pdc_set_piomode(ap, adev); -+ if (adev->dma_mode) -+ pdc_set_dmamode(ap, adev); -+ } -+ } -+} -+ -+/** -+ * pdc2026x_dev_config - device setup hook -+ * @ap: ATA port -+ * @adev: newly found device -+ * -+ * Perform chip specific early setup. We need to lock the transfer -+ * sizes to 8bit to avoid making the state engine on the 2026x cards -+ * barf. -+ */ -+ -+static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev) -+{ -+ /* We cannot blindly set 256 as the core code may already -+ have picked a lower limit */ -+ -+ if(ap->host->max_sectors > 256) { -+ ap->host->max_sectors = 256; -+ ap->host->hostt->max_sectors = 256; -+ } -+ adev->flags |= ATA_DFLAG_LOCK_SECTORS; -+} -+ -+static struct scsi_host_template pdc_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations pdc2024x_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = pdc_set_piomode, -+ .set_dmamode = pdc_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = pdc2024x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations pdc2026x_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = pdc_set_piomode, -+ .set_dmamode = pdc_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ .dev_config = pdc2026x_dev_config, -+ -+ .phy_reset = pdc2026x_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = pdc2026x_bmdma_start, -+ .bmdma_stop = pdc2026x_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = pdc2026x_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info[3] = { -+ { -+ .sht = &pdc_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA2, -+ .port_ops = &pdc2024x_port_ops -+ }, -+ { -+ .sht = &pdc_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA4, -+ .port_ops = &pdc2026x_port_ops -+ }, -+ { -+ .sht = &pdc_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &pdc2026x_port_ops -+ } -+ -+ }; -+ static struct ata_port_info *port_info[2]; -+ -+ port_info[0] = port_info[1] = &info[id->driver_data]; -+ -+ if (dev->device == PCI_DEVICE_ID_PROMISE_20265) { -+ struct pci_dev *bridge = dev->bus->self; -+ /* Don't grab anything behind a Promise I2O RAID */ -+ if (bridge && bridge->vendor == PCI_VENDOR_ID_INTEL) { -+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960) -+ return -ENODEV; -+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960RM) -+ return -ENODEV; -+ } -+ } -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static struct pci_device_id pdc[] = { -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { 0, }, -+}; -+ -+static struct pci_driver pdc_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = pdc, -+ .probe = pdc_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init pdc_init(void) -+{ -+ return pci_register_driver(&pdc_pci_driver); -+} -+ -+ -+static void __exit pdc_exit(void) -+{ -+ pci_unregister_driver(&pdc_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, pdc); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(pdc_init); -+module_exit(pdc_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_qdi.c linux-2.6.16-rc4/drivers/scsi/pata_qdi.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_qdi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_qdi.c 2006-02-15 15:08:22.000000000 +0000 -@@ -0,0 +1,370 @@ -+/* -+ * pata_qdi.c - QDI VLB ATA controllers -+ * (C) 2006 Red Hat <alan@redhat.com> -+ * -+ * This driver mostly exists as a proof of concept for non PCI devices under libata. -+ * While the QDI6580 was 'neat' in 1993 it is no longer terribly useful. -+ * -+ * Tuning code written from the documentation at -+ * http://www.ryston.cz/petr/vlb/qd6500.html -+ * http://www.ryston.cz/petr/vlb/qd6580.html -+ * -+ * Probe code based on drivers/ide/legacy/qd65xx.c -+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by -+ * Samuel Thibault <samuel.thibault@fnac.net> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_qdi" -+#define DRV_VERSION "0.2" -+ -+#define NR_HOST 4 /* Two 6580s */ -+ -+struct qdi_data { -+ unsigned long timing; -+ u8 clock[2]; -+ u8 last; -+ int fast; -+ -+}; -+ -+static struct ata_host_set *qdi_host[NR_HOST]; -+static struct qdi_data qdi_data[NR_HOST]; -+static int nr_qdi_host = 0; -+ -+static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct ata_timing t; -+ struct qdi_data *qdi = ap->host_set->private_data; -+ int active, recovery; -+ u8 timing; -+ -+ /* Get the timing data in cycles */ -+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); -+ -+ if (qdi->fast) { -+ active = 8 - FIT(t.active, 1, 8); -+ recovery = 18 - FIT(t.recover, 3, 18); -+ } else { -+ active = 9 - FIT(t.active, 2, 9); -+ recovery = 15 - FIT(t.recover, 0, 15); -+ } -+ timing = (recovery << 4) | active | 0x08; -+ -+ qdi->clock[adev->devno] = timing; -+ -+ outb(timing, qdi->timing); -+} -+ -+static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct ata_timing t; -+ struct qdi_data *qdi = ap->host_set->private_data; -+ int active, recovery; -+ u8 timing; -+ -+ /* Get the timing data in cycles */ -+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); -+ -+ if (qdi->fast) { -+ active = 8 - FIT(t.active, 1, 8); -+ recovery = 18 - FIT(t.recover, 3, 18); -+ } else { -+ active = 9 - FIT(t.active, 2, 9); -+ recovery = 15 - FIT(t.recover, 0, 15); -+ } -+ timing = (recovery << 4) | active | 0x08; -+ -+ qdi->clock[adev->devno] = timing; -+ -+ outb(timing, qdi->timing); -+ -+ /* Clear the FIFO */ -+ if (adev->class != ATA_DEV_ATA) -+ outb(0x5F, (qdi->timing & 0xFFF0) + 3); -+} -+ -+/** -+ * qdi_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings. -+ */ -+ -+static int qdi_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ struct qdi_data *qdi = ap->host_set->private_data; -+ -+ if (qdi->clock[adev->devno] != qdi->last) { -+ if (adev->pio_mode) { -+ qdi->last = qdi->clock[adev->devno]; -+ outb(qdi->clock[adev->devno], qdi->timing); -+ } -+ } -+ return ata_qc_issue_prot(qc); -+} -+ -+static void qdi_data_xfer(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) -+{ -+ int slop = buflen & 3; -+ -+ if (ata_id_has_dword_io(adev->id)) { -+ if (write_data) -+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2); -+ else -+ insl(ap->ioaddr.data_addr, buf, buflen >> 2); -+ -+ if (unlikely(slop)) { -+ u32 pad; -+ if (write_data) { -+ memcpy(&pad, buf + buflen - slop, slop); -+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr); -+ } else { -+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); -+ memcpy(buf + buflen - slop, &pad, slop); -+ } -+ } -+ } else -+ ata_pio_data_xfer(ap, adev, buf, buflen, write_data); -+} -+ -+static struct scsi_host_template qdi_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations qdi6500_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = qdi6500_set_piomode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = qdi_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = qdi_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations qdi6580_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = qdi6580_set_piomode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = qdi_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = qdi_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * qdi_init_one - attach a qdi interface -+ * @type: Type to display -+ * @io: I/O port start -+ * @irq: interrupt line -+ * @fast: True if on a > 33Mhz VLB -+ * -+ * Register an ISA bus IDE interface. Such interfaces are PIO and we -+ * assume do not support IRQ sharing. -+ */ -+ -+static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast) -+{ -+ struct ata_probe_ent ae; -+ int ret; -+ -+ unsigned long ctrl = io + 0x206; -+ -+ /* -+ * Fill in a probe structure first of all -+ */ -+ -+ memset(&ae, 0, sizeof(struct ata_probe_ent)); -+ INIT_LIST_HEAD(&ae.node); -+ ae.dev = NULL; -+ -+ if (type == 6580) { -+ ae.port_ops = &qdi6580_port_ops; -+ ae.pio_mask = 0x1F; -+ } else { -+ ae.port_ops = &qdi6500_port_ops; -+ ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */ -+ } -+ -+ ae.sht = &qdi_sht; -+ ae.n_ports = 1; -+ ae.irq = irq; -+ ae.irq_flags = 0; -+ ae.host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IRQ_MASK; -+ ae.port[0].cmd_addr = io; -+ ae.port[0].altstatus_addr = ctrl; -+ ae.port[0].ctl_addr = ctrl; -+ ata_std_ports(&ae.port[0]); -+ -+ /* -+ * Hook in a private data structure per channel -+ */ -+ ae.private_data = &qdi_data[nr_qdi_host]; -+ -+ qdi_data[nr_qdi_host].timing = port; -+ qdi_data[nr_qdi_host].fast = fast; -+ -+ printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); -+ ret = ata_device_add(&ae); -+ if (ret == 0) -+ return -ENODEV; -+ -+ qdi_host[nr_qdi_host++] = ae.host_set; -+ return 0; -+} -+ -+/** -+ * qdi_init - attach qdi interfaces -+ * -+ * Attach qdi IDE interfaces by scanning the ports it may occupy. -+ */ -+ -+static __init int qdi_init(void) -+{ -+ unsigned long flags; -+ unsigned long qd_port[2] = { 0x30, 0xB0 }; -+ unsigned long ide_port[2] = { 0x170, 0x1F0 }; -+ int ide_irq[2] = { 14, 15 }; -+ int ct = 0; -+ int i; -+ -+ /* -+ * Check each possible QD65xx base address -+ */ -+ -+ for (i = 0; i < 2; i++) { -+ unsigned long port = qd_port[i]; -+ u8 r, res; -+ -+ -+ if (request_region(port, 2, "pata_qdi")) { -+ /* Check for a card */ -+ local_irq_save(flags); -+ r = inb_p(port); -+ outb_p(0x19, port); -+ res = inb_p(port); -+ outb_p(r, port); -+ local_irq_restore(flags); -+ -+ /* Fail */ -+ if (res == 0x19) -+ { -+ release_region(port, 2); -+ continue; -+ } -+ -+ /* Passes the presence test */ -+ r = inb_p(port + 1); /* Check port agrees with port set */ -+ if ((r & 2) >> 1 != i) { -+ release_region(port, 2); -+ continue; -+ } -+ -+ /* Check card type */ -+ if ((r & 0xF0) == 0xC0) { -+ /* QD6500: single channel */ -+ if (r & 8) { -+ /* Disabled ? */ -+ release_region(port, 2); -+ continue; -+ } -+ ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04); -+ } -+ if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { -+ /* QD6580: dual channel */ -+ if (!request_region(port + 2 , 2, "pata_qdi")) -+ { -+ release_region(port, 2); -+ continue; -+ } -+ res = inb(port + 3); -+ if (res & 1) { -+ /* Single channel mode */ -+ ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04); -+ } else { -+ /* Dual channel mode */ -+ ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04); -+ ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04); -+ } -+ } -+ } -+ } -+ if (ct != 0) -+ return 0; -+ return -ENODEV; -+} -+ -+static __exit void qdi_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < nr_qdi_host; i++) { -+ ata_host_set_remove(qdi_host[i]); -+ /* Free the control resource. The 6580 dual channel has the resources -+ * claimed as a pair of 2 byte resources so we need no special cases... -+ */ -+ release_region(qdi_data[i].timing, 2); -+ } -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for qdi ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(qdi_init); -+module_exit(qdi_exit); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_radisys.c linux-2.6.16-rc4/drivers/scsi/pata_radisys.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_radisys.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_radisys.c 2006-02-17 15:31:12.000000000 +0000 -@@ -0,0 +1,321 @@ -+/* -+ * pata_radisys.c - Intel PATA/SATA controllers -+ * -+ * (C) 2006 Red Hat <alan@redhat.com> -+ * -+ * Some parts based on ata_piix.c by Jeff Garzik and others. -+ * -+ * A PIIX relative, this device has a single ATA channel and no -+ * slave timings, SITRE or PPE. In that sense it is a close relative -+ * of the original PIIX. It does however support UDMA 33/66 per channel -+ * although no other modes/timings. Also lacking is 32bit I/O on the ATA -+ * port. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_radisys" -+#define DRV_VERSION "0.2" -+ -+/** -+ * radisys_pata_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void radisys_pata_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA80; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * radisys_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: um -+ * -+ * Set PIO mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ unsigned int pio = adev->pio_mode - XFER_PIO_0; -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ u16 idetm_data; -+ int control = 0; -+ -+ /* -+ * See Intel Document 298600-004 for the timing programing rules -+ * for PIIX/ICH. Note that the early PIIX does not have the slave -+ * timing port at 0x44. The Radisys is a relative of the PIIX -+ * but not the same so be careful. -+ */ -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, /* Check me */ -+ { 0, 0 }, -+ { 1, 1 }, -+ { 2, 2 }, -+ { 3, 3 }, }; -+ -+ if (pio > 0) -+ control |= 1; /* TIME1 enable */ -+ if (ata_pio_need_iordy(adev)) -+ control |= 2; /* IE IORDY */ -+ -+ pci_read_config_word(dev, 0x40, &idetm_data); -+ -+ /* Enable IE and TIME as appropriate. Clear the other -+ drive timing bits */ -+ idetm_data &= 0xCCCC; -+ idetm_data |= (control << (4 * adev->devno)); -+ idetm_data |= (timings[pio][0] << 12) | -+ (timings[pio][1] << 8); -+ pci_write_config_word(dev, 0x40, idetm_data); -+ -+ /* Track which port is configured */ -+ ap->private_data = adev; -+} -+ -+/** -+ * radisys_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * @isich: True if the device is an ICH and has IOCFG registers -+ * -+ * Set MWDMA mode for device, in host controller PCI config space. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *dev = to_pci_dev(ap->host_set->dev); -+ u16 idetm_data; -+ u8 udma_enable; -+ -+ static const /* ISP RTC */ -+ u8 timings[][2] = { { 0, 0 }, -+ { 0, 0 }, -+ { 1, 1 }, -+ { 2, 2 }, -+ { 3, 3 }, }; -+ -+ /* -+ * MWDMA is driven by the PIO timings. We must also enable -+ * IORDY unconditionally. -+ */ -+ -+ pci_read_config_word(dev, 0x40, &idetm_data); -+ pci_read_config_byte(dev, 0x48, &udma_enable); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; -+ const unsigned int needed_pio[3] = { -+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 -+ }; -+ int pio = needed_pio[mwdma] - XFER_PIO_0; -+ int control = 3; /* IORDY|TIME0 */ -+ -+ /* If the drive MWDMA is faster than it can do PIO then -+ we must force PIO0 for PIO cycles. */ -+ -+ if (adev->pio_mode < needed_pio[mwdma]) -+ control = 1; -+ -+ /* Mask out the relevant control and timing bits we will load. Also -+ clear the other drive TIME register as a precaution */ -+ -+ idetm_data &= 0xCCCC; -+ idetm_data |= control << (4 * adev->devno); -+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); -+ -+ udma_enable &= ~(1 << adev->devno); -+ } else { -+ u8 udma_mode; -+ -+ /* UDMA66 on. It isn't clear from the documentation whether -+ UDMA 33 and 66 are switchable via register 0x4A */ -+ -+ pci_read_config_byte(dev, 0x4A, &udma_mode); -+ -+ if (adev->xfer_mode == XFER_UDMA_2) -+ udma_mode &= ~ (1 << adev->devno); -+ else /* UDMA 4 */ -+ udma_mode |= (1 << adev->devno); -+ -+ pci_write_config_byte(dev, 0x4A, udma_mode); -+ -+ udma_enable |= (1 << adev->devno); -+ } -+ pci_write_config_word(dev, 0x40, idetm_data); -+ pci_write_config_byte(dev, 0x48, udma_enable); -+ -+ /* Track which port is configured */ -+ ap->private_data = adev; -+} -+ -+/** -+ * radisys_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so -+ * that, even if we get this wrong, cycles to the other device will -+ * be made PIO0. -+ */ -+ -+static int radisys_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ -+ if (adev != ap->private_data) { -+ /* UDMA timing is not shared */ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ if (adev->dma_mode) -+ radisys_set_dmamode(ap, adev); -+ else if (adev->pio_mode) -+ radisys_set_piomode(ap, adev); -+ } -+ } -+ return ata_qc_issue_prot(qc); -+} -+ -+ -+static struct scsi_host_template radisys_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations radisys_pata_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = radisys_set_piomode, -+ .set_dmamode = radisys_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = radisys_pata_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = radisys_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+ -+/** -+ * radisys_init_one - Register PIIX ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in radisys_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. We probe for combined mode (sigh), -+ * and then hand over control to libata, for it to do the rest. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ static struct ata_port_info info = { -+ .sht = &radisys_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, /* mwdma1-2 */ -+ .udma_mask = 0x14, /* UDMA33/66 only */ -+ .port_ops = &radisys_pata_ops, -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id radisys_pci_tbl[] = { -+ { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, }, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver radisys_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = radisys_pci_tbl, -+ .probe = radisys_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init radisys_init(void) -+{ -+ return pci_register_driver(&radisys_pci_driver); -+} -+ -+static void __exit radisys_exit(void) -+{ -+ pci_unregister_driver(&radisys_pci_driver); -+} -+ -+ -+module_init(radisys_init); -+module_exit(radisys_exit); -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("SCSI low-level driver for Radisys R82600 controllers"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, radisys_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_rz1000.c linux-2.6.16-rc4/drivers/scsi/pata_rz1000.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_rz1000.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_rz1000.c 2006-02-16 15:38:18.000000000 +0000 -@@ -0,0 +1,183 @@ -+/* -+ * RZ1000/1001 driver based upon -+ * -+ * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003 -+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below) -+ * Principal Author: mlord@pobox.com (Mark Lord) -+ * -+ * See linux/MAINTAINERS for address of current maintainer. -+ * -+ * This file provides support for disabling the buggy read-ahead -+ * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "rz1000" -+#define DRV_VERSION "0.01" -+ -+static void rz1000_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * rz1000_set_mode - mode setting function -+ * @ap: ATA interface -+ * -+ * Use a non standard set_mode function. We don't want to be tuned. We -+ * would prefer to be BIOS generic but for the fact our hardware is -+ * whacked out. -+ */ -+ -+static void rz1000_set_mode(struct ata_port *ap) -+{ -+ int i; -+ -+ for (i = 0; i < ATA_MAX_DEVICES; i++) { -+ struct ata_device *dev = &ap->device[i]; -+ if (ata_dev_present(dev)) { -+ /* We don't really care */ -+ dev->pio_mode = XFER_PIO_0; -+ dev->xfer_mode = XFER_PIO_0; -+ dev->xfer_shift = ATA_SHIFT_PIO; -+ dev->flags |= ATA_DFLAG_PIO; -+ } -+ } -+} -+ -+ -+static struct scsi_host_template rz1000_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations rz1000_port_ops = { -+ .set_mode = rz1000_set_mode, -+ -+ .port_disable = ata_port_disable, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = rz1000_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in rz1000_pci_tbl matching with @pdev -+ * -+ * Configure an RZ1000 interface. This doesn't require much special -+ * handling except that we *MUST* kill the chipset readahead or the -+ * user may experience data corruption. -+ */ -+ -+static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ struct ata_port_info *port_info[2]; -+ u16 reg; -+ static struct ata_port_info info = { -+ .sht = &rz1000_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .port_ops = &rz1000_port_ops -+ }; -+ -+ if (!printed_version++) -+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); -+ -+ /* Be exceptionally paranoid as we must be sure to apply the fix */ -+ if (pci_read_config_word(pdev, 0x40, ®) != 0) -+ goto fail; -+ reg &= 0xDFFF; -+ if (pci_write_config_word(pdev, 0x40, reg) != 0) -+ goto fail; -+ printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n"); -+ -+ port_info[0] = &info; -+ port_info[1] = &info; -+ return ata_pci_init_one(pdev, port_info, 2); -+fail: -+ printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n"); -+ /* Not safe to use so skip */ -+ return -ENODEV; -+} -+ -+static struct pci_device_id pata_rz1000[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), }, -+ { 0, }, -+}; -+ -+static struct pci_driver rz1000_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = pata_rz1000, -+ .probe = rz1000_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+ -+static int __init rz1000_init(void) -+{ -+ return pci_register_driver(&rz1000_pci_driver); -+} -+ -+static void __exit rz1000_exit(void) -+{ -+ pci_unregister_driver(&rz1000_pci_driver); -+} -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for RZ1000 PCI ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, pata_rz1000); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(rz1000_init); -+module_exit(rz1000_exit); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sc1200.c linux-2.6.16-rc4/drivers/scsi/pata_sc1200.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sc1200.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_sc1200.c 2006-02-16 15:46:11.000000000 +0000 -@@ -0,0 +1,286 @@ -+/* -+ * New ATA layer SC1200 driver Alan Cox <alan@redhat.com> -+ * -+ * TODO: Mode selection filtering -+ * TODO: Can't enable second channel until ATA core has serialize -+ * TODO: Needs custom DMA cleanup code -+ * -+ * Based very heavily on -+ * -+ * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003 -+ * -+ * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com> -+ * May be copied or modified under the terms of the GNU General Public License -+ * -+ * Development of this chipset driver was funded -+ * by the nice folks at National Semiconductor. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "sc1200" -+#define DRV_VERSION "0.2" -+ -+#define SC1200_REV_A 0x00 -+#define SC1200_REV_B1 0x01 -+#define SC1200_REV_B3 0x02 -+#define SC1200_REV_C1 0x03 -+#define SC1200_REV_D1 0x04 -+ -+/** -+ * sc1200_clock - PCI clock -+ * -+ * Return the PCI bus clocking for the SC1200 chipset configuration -+ * in use. We return 0 for 33MHz 1 for 48MHz and 2 for 66Mhz -+ */ -+ -+static int sc1200_clock(void) -+{ -+ /* Magic registers that give us the chipset data */ -+ u8 chip_id = inb(0x903C); -+ u8 silicon_rev = inb(0x903D); -+ u16 pci_clock; -+ -+ if (chip_id == 0x04 && silicon_rev < SC1200_REV_B1) -+ return 0; /* 33 MHz mode */ -+ -+ /* Clock generator configuration 0x901E its 8/9 are the PCI clocking -+ 0/3 is 33Mhz 1 is 48 2 is 66 */ -+ -+ pci_clock = inw(0x901E); -+ pci_clock >>= 8; -+ pci_clock &= 0x03; -+ if (pci_clock == 3) -+ pci_clock = 0; -+ return pci_clock; -+} -+ -+/** -+ * sc1200_set_piomode - PIO setup -+ * @ap: ATA interface -+ * @adev: device on the interface -+ * -+ * Set our PIO requirements. This is fairly simple on the SC1200 -+ */ -+ -+static void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u32 pio_timings[4][5] = { -+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz -+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz -+ {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz -+ {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131} // format1, 66Mhz -+ }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 format; -+ unsigned int reg = 0x40 + 0x10 * ap->hard_port_no; -+ int mode = adev->pio_mode - XFER_PIO_0; -+ -+ pci_read_config_dword(pdev, reg + 4, &format); -+ format >>= 31; -+ format += sc1200_clock(); -+ pci_write_config_dword(pdev, reg + 8 * adev->devno, -+ pio_timings[format][mode]); -+} -+ -+/** -+ * sc1200_set_dmamode - DMA timing setup -+ * @ap: ATA interface -+ * @adev: Device being configured -+ * -+ * We cannot mix MWDMA and UDMA without reloading timings each switch -+ * master to slave. -+ */ -+ -+static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u32 udma_timing[3][3] = { -+ { 0x00921250, 0x00911140, 0x00911030 }, -+ { 0x00932470, 0x00922260, 0x00922140 }, -+ { 0x009436A1, 0x00933481, 0x00923261 } -+ }; -+ -+ static u32 mwdma_timing[3][3] = { -+ { 0x00077771, 0x00012121, 0x00002020 }, -+ { 0x000BBBB2, 0x00024241, 0x00013131 }, -+ { 0x000FFFF3, 0x00035352, 0x00015151 } -+ }; -+ -+ int clock = sc1200_clock(); -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ unsigned int reg = 0x40 + 0x10 * ap->hard_port_no; -+ int mode = adev->dma_mode; -+ u32 format; -+ -+ if (mode >= XFER_UDMA_0) -+ format = udma_timing[clock][mode - XFER_UDMA_0]; -+ else -+ format = mwdma_timing[clock][mode - XFER_MW_DMA_0]; -+ -+ if (adev->devno == 0) { -+ u32 timings; -+ -+ pci_read_config_dword(pdev, reg + 4, &timings); -+ timings &= 0x80000000UL; -+ timings |= format; -+ pci_write_config_dword(pdev, reg + 4, timings); -+ } else -+ pci_write_config_dword(pdev, reg + 12, format); -+} -+ -+/** -+ * sc1200_qc_issue_prot - command issue -+ * @qc: command pending -+ * -+ * Called when the libata layer is about to issue a command. We wrap -+ * this interface so that we can load the correct ATA timings if -+ * neccessary. Specifically we have a problem that there is only -+ * one MWDMA/UDMA bit. -+ */ -+ -+static int sc1200_qc_issue_prot(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_device *adev = qc->dev; -+ struct ata_device *prev = ap->private_data; -+ -+ /* See if the DMA settings could be wrong */ -+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) { -+ /* Maybe, but do the channels match MWDMA/UDMA ? */ -+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) || -+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0)) -+ /* Switch the mode bits */ -+ sc1200_set_dmamode(ap, adev); -+ } -+ -+ return ata_qc_issue_prot(qc); -+} -+ -+static struct scsi_host_template sc1200_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations sc1200_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sc1200_set_piomode, -+ .set_dmamode = sc1200_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = sc1200_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * sc1200_init_one - Initialise an SC1200 -+ * @dev: PCI device -+ * @id: Entry in match table -+ * -+ * Just throw the needed data at the libata helper and it does all -+ * our work. -+ */ -+ -+static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &sc1200_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x07, -+ .port_ops = &sc1200_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ -+ /* Can't enable port 2 yet, see top comments */ -+ return ata_pci_init_one(dev, port_info, 1); -+} -+ -+static struct pci_device_id sc1200[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), }, -+ { 0, }, -+}; -+ -+static struct pci_driver sc1200_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = sc1200, -+ .probe = sc1200_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init sc1200_init(void) -+{ -+ return pci_register_driver(&sc1200_pci_driver); -+} -+ -+ -+static void __exit sc1200_exit(void) -+{ -+ pci_unregister_driver(&sc1200_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox, Mark Lord"); -+MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, sc1200); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(sc1200_init); -+module_exit(sc1200_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_serverworks.c linux-2.6.16-rc4/drivers/scsi/pata_serverworks.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_serverworks.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_serverworks.c 2006-02-16 15:37:31.000000000 +0000 -@@ -0,0 +1,586 @@ -+/* -+ * ata-serverworks.c - Serverworks PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon -+ * -+ * serverworks.c -+ * -+ * Copyright (C) 1998-2000 Michel Aubry -+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz -+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> -+ * Portions copyright (c) 2001 Sun Microsystems -+ * -+ * -+ * RCC/ServerWorks IDE driver for Linux -+ * -+ * OSB4: `Open South Bridge' IDE Interface (fn 1) -+ * supports UDMA mode 2 (33 MB/s) -+ * -+ * CSB5: `Champion South Bridge' IDE Interface (fn 1) -+ * all revisions support UDMA mode 4 (66 MB/s) -+ * revision A2.0 and up support UDMA mode 5 (100 MB/s) -+ * -+ * *** The CSB5 does not provide ANY register *** -+ * *** to detect 80-conductor cable presence. *** -+ * -+ * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) -+ * -+ * Documentation: -+ * Available under NDA only. Errata info very hard to get. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "serverworks" -+#define DRV_VERSION "0.1.1" -+ -+#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ -+#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ -+ -+/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 -+ * can overrun their FIFOs when used with the CSB5 */ -+ -+static const char *csb_bad_ata100[] = { -+ "ST320011A", -+ "ST340016A", -+ "ST360021A", -+ "ST380021A", -+ NULL -+}; -+ -+/** -+ * dell_cable - Dell serverworks cable detection -+ * @ap: ATA port to do cable detect -+ * -+ * Dell hide the 40/80 pin select for their interfaces in the top two -+ * bits of the subsystem ID. -+ */ -+ -+static int dell_cable(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ if (pdev->subsystem_device & (1 << (ap->hard_port_no + 14))) -+ return ATA_CBL_PATA80; -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * sun_cable - Sun Cobalt 'Alpine' cable detection -+ * @ap: ATA port to do cable select -+ * -+ * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the -+ * subsystem ID the same as dell. We could use one function but we may -+ * need to extend the Dell one in future -+ */ -+ -+static int sun_cable(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ if (pdev->subsystem_device & (1 << (ap->hard_port_no + 14))) -+ return ATA_CBL_PATA80; -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * osb4_cable - OSB4 cable detect -+ * @ap: ATA port to check -+ * -+ * The OSB4 isn't UDMA66 capable so this is easy -+ */ -+ -+static int osb4_cable(struct ata_port *ap) { -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * csb4_cable - CSB5/6 cable detect -+ * @ap: ATA port to check -+ * -+ * Serverworks default arrangement is to use the drive side detection -+ * only. -+ */ -+ -+static int csb_cable(struct ata_port *ap) { -+ return ATA_CBL_PATA80; -+} -+ -+struct sv_cable_table { -+ int device; -+ int subvendor; -+ int (*cable_detect)(struct ata_port *ap); -+}; -+ -+/* -+ * Note that we don't copy the old serverworks code because the old -+ * code contains obvious mistakes -+ */ -+ -+static struct sv_cable_table cable_detect[] = { -+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_OSB4, PCI_ANY_ID, osb4_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable }, -+ { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable }, -+ { } -+}; -+ -+/** -+ * serverworks_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection according to the device and subvendor -+ * identifications -+ */ -+ -+static int serverworks_cable_detect(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct sv_cable_table *cb = cable_detect; -+ -+ while(cb->device) { -+ if (cb->device == pdev->device && -+ (cb->subvendor == pdev->subsystem_vendor || -+ cb->subvendor == PCI_ANY_ID)) { -+ return cb->cable_detect(ap); -+ } -+ cb++; -+ } -+ BUG(); -+} -+ -+static void serverworks_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = serverworks_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * serverworks_is_csb - Check for CSB or OSB -+ * @pdev: PCI device to check -+ * -+ * Returns true if the device being checked is known to be a CSB -+ * series device. -+ */ -+ -+static u8 serverworks_is_csb(struct pci_dev *pdev) -+{ -+ switch (pdev->device) { -+ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: -+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: -+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: -+ case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: -+ return 1; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+/** -+ * serverworks_osb4_filter - mode selection filter -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Filter the offered modes for the device to apply controller -+ * specific rules. OSB4 requires no UDMA for disks due to a FIFO -+ * bug we hit. -+ */ -+ -+static unsigned int serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ if (adev->class == ATA_DEV_ATA) -+ return 0; -+ return mask; -+} -+ -+ -+/** -+ * serverworks_csb_filter - mode selection filter -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Check the blacklist and disable UDMA5 if matched -+ */ -+ -+static unsigned int serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned int mask, int shift) -+{ -+ const char *p; -+ char model_num[40]; -+ int len, i; -+ -+ /* Disk, UDMA */ -+ if (shift != ATA_SHIFT_UDMA) -+ return mask; -+ if (adev->class != ATA_DEV_ATA) -+ return mask; -+ -+ /* Actually do need to check */ -+ ata_dev_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); -+ /* Precuationary - why not do this in the libata core ?? */ -+ -+ len = strlen(model_num); -+ while ((len > 0) && (model_num[len - 1] == ' ')) { -+ len--; -+ model_num[len] = 0; -+ } -+ -+ for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { -+ if (!strncmp(p, model_num, len)) -+ return mask & 0x1F; -+ } -+ return mask; -+} -+ -+ -+/** -+ * serverworks_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the OSB4/CSB5 timing registers for PIO. The PIO register -+ * load is done as a simple lookup. -+ */ -+static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; -+ int offset = 1 + 2 * ap->hard_port_no - adev->devno; -+ int devbits = (2 * ap->hard_port_no + adev->devno) * 4; -+ u16 csb5_pio; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int pio = adev->pio_mode - XFER_PIO_0; -+ -+ pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]); -+ -+ /* The OSB4 just requires the timing but the CSB series want the -+ mode number as well */ -+ if (serverworks_is_csb(pdev)) { -+ pci_read_config_word(pdev, 0x4A, &csb5_pio); -+ csb5_pio &= ~(0x0F << devbits); -+ pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits)); -+ } -+} -+ -+/** -+ * serverworks_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5 -+ * chipset. The MWDMA mode values are pulled from a lookup table -+ * while the chipset uses mode number for UDMA. -+ */ -+ -+static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u8 dma_mode[] = { 0x77, 0x21, 0x20 }; -+ int offset = 1 + 2 * ap->hard_port_no - adev->devno; -+ int devbits = (2 * ap->hard_port_no + adev->devno); -+ u8 ultra; -+ u8 ultra_cfg; -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ pci_read_config_byte(pdev, 0x54, &ultra_cfg); -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ pci_write_config_byte(pdev, 0x44 + offset, 0x20); -+ -+ pci_read_config_byte(pdev, 0x56 + ap->hard_port_no, &ultra); -+ ultra &= ~(0x0F << (ap->hard_port_no * 4)); -+ ultra |= (adev->dma_mode - XFER_UDMA_0) -+ << (ap->hard_port_no * 4); -+ pci_write_config_byte(pdev, 0x56 + ap->hard_port_no, ultra); -+ -+ ultra_cfg |= (1 << devbits); -+ } else { -+ pci_write_config_byte(pdev, 0x44 + offset, -+ dma_mode[adev->dma_mode - XFER_MW_DMA_0]); -+ ultra_cfg &= ~(1 << devbits); -+ } -+ pci_write_config_byte(pdev, 0x54, ultra_cfg); -+} -+ -+static struct scsi_host_template serverworks_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations serverworks_osb4_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = serverworks_set_piomode, -+ .set_dmamode = serverworks_set_dmamode, -+ .mode_filter = serverworks_osb4_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = serverworks_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations serverworks_csb_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = serverworks_set_piomode, -+ .set_dmamode = serverworks_set_dmamode, -+ .mode_filter = serverworks_csb_filter, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = serverworks_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int serverworks_fixup_osb4(struct pci_dev *pdev) -+{ -+ u32 reg; -+ struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, -+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); -+ if (isa_dev) { -+ pci_read_config_dword(isa_dev, 0x64, ®); -+ reg &= ~0x00002000; /* disable 600ns interrupt mask */ -+ if (!(reg & 0x00004000)) -+ printk(KERN_DEBUG DRV_NAME ": UDMA not BIOS enabled.\n"); -+ reg |= 0x00004000; /* enable UDMA/33 support */ -+ pci_write_config_dword(isa_dev, 0x64, reg); -+ pci_dev_put(isa_dev); -+ return 0; -+ } -+ printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n"); -+ return -ENODEV; -+} -+ -+static int serverworks_fixup_csb(struct pci_dev *pdev) -+{ -+ u8 rev; -+ u8 btr; -+ -+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); -+ -+ /* Third Channel Test */ -+ if (!(PCI_FUNC(pdev->devfn) & 1)) { -+ struct pci_dev * findev = NULL; -+ u32 reg4c = 0; -+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, -+ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); -+ if (findev) { -+ pci_read_config_dword(findev, 0x4C, ®4c); -+ reg4c &= ~0x000007FF; -+ reg4c |= 0x00000040; -+ reg4c |= 0x00000020; -+ pci_write_config_dword(findev, 0x4C, reg4c); -+ pci_dev_put(findev); -+ } -+ } else { -+ struct pci_dev * findev = NULL; -+ u8 reg41 = 0; -+ -+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, -+ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); -+ if (findev) { -+ pci_read_config_byte(findev, 0x41, ®41); -+ reg41 &= ~0x40; -+ pci_write_config_byte(findev, 0x41, reg41); -+ pci_dev_put(findev); -+ } -+ } -+ /* setup the UDMA Control register -+ * -+ * 1. clear bit 6 to enable DMA -+ * 2. enable DMA modes with bits 0-1 -+ * 00 : legacy -+ * 01 : udma2 -+ * 10 : udma2/udma4 -+ * 11 : udma2/udma4/udma5 -+ */ -+ pci_read_config_byte(pdev, 0x5A, &btr); -+ btr &= ~0x40; -+ if (!(PCI_FUNC(pdev->devfn) & 1)) -+ btr |= 0x2; -+ else -+ btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; -+ pci_write_config_byte(pdev, 0x5A, btr); -+ -+ return btr; -+} -+ -+static void serverworks_fixup_ht1000(struct pci_dev *pdev) -+{ -+ u8 btr; -+ /* Setup HT1000 SouthBridge Controller - Single Channel Only */ -+ pci_read_config_byte(pdev, 0x5A, &btr); -+ btr &= ~0x40; -+ btr |= 0x3; -+ pci_write_config_byte(pdev, 0x5A, btr); -+} -+ -+ -+static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ int ports = 2; -+ static struct ata_port_info info[4] = { -+ { /* OSB4 */ -+ .sht = &serverworks_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x07, -+ .port_ops = &serverworks_osb4_port_ops -+ }, { /* OSB4 no UDMA */ -+ .sht = &serverworks_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x00, -+ .port_ops = &serverworks_osb4_port_ops -+ }, { /* CSB5 */ -+ .sht = &serverworks_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, -+ .port_ops = &serverworks_csb_port_ops -+ }, { /* CSB5 - later revisions*/ -+ .sht = &serverworks_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &serverworks_csb_port_ops -+ } -+ }; -+ static struct ata_port_info *port_info[2]; -+ struct ata_port_info *devinfo = &info[id->driver_data]; -+ -+ /* Force master latency timer to 64 PCI clocks */ -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); -+ -+ /* OSB4 : South Bridge and IDE */ -+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { -+ /* Select non UDMA capable OSB4 if we can't do fixups */ -+ if ( serverworks_fixup_osb4(pdev) < 0) -+ devinfo = &info[1]; -+ } -+ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ -+ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || -+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || -+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { -+ -+ /* If the returned btr is the newer revision then -+ select the right info block */ -+ if (serverworks_fixup_csb(pdev) == 3) -+ devinfo = &info[3]; -+ -+ /* Is this the 3rd channel CSB6 IDE ? */ -+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) -+ ports = 1; -+ } -+ /* setup HT1000E */ -+ else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) -+ serverworks_fixup_ht1000(pdev); -+ -+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) -+ ata_pci_clear_simplex(pdev); -+ -+ port_info[0] = port_info[1] = devinfo; -+ return ata_pci_init_one(pdev, port_info, ports); -+} -+ -+static struct pci_device_id serverworks[] = { -+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -+ { 0, }, -+}; -+ -+static struct pci_driver serverworks_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = serverworks, -+ .probe = serverworks_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init serverworks_init(void) -+{ -+ return pci_register_driver(&serverworks_pci_driver); -+} -+ -+ -+static void __exit serverworks_exit(void) -+{ -+ pci_unregister_driver(&serverworks_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, serverworks); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(serverworks_init); -+module_exit(serverworks_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sil680.c linux-2.6.16-rc4/drivers/scsi/pata_sil680.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sil680.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_sil680.c 2006-02-16 15:28:00.000000000 +0000 -@@ -0,0 +1,368 @@ -+/* -+ * pata_sil680.c - SIL680 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon -+ * -+ * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003 -+ * -+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> -+ * Copyright (C) 2003 Red Hat <alan@redhat.com> -+ * -+ * May be copied or modified under the terms of the GNU General Public License -+ * -+ * Documentation publically available. -+ * -+ * If you have strange problems with nVidia chipset systems please -+ * see the SI support documentation and update your system BIOS -+ * if neccessary -+ * -+ * TODO -+ * If we know all our devices are LBA28 (or LBA28 sized) we could use -+ * the command fifo mode. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_sil680" -+#define DRV_VERSION "0.2.1" -+ -+/** -+ * sil680_selreg - return register base -+ * @hwif: interface -+ * @r: config offset -+ * -+ * Turn a config register offset into the right address in either -+ * PCI space or MMIO space to access the control register in question -+ * Thankfully this is a configuration operation so isnt performance -+ * criticial. -+ */ -+ -+static unsigned long sil680_selreg(struct ata_port *ap, int r) -+{ -+ unsigned long base = 0xA0 + r; -+ base += (ap->hard_port_no << 4); -+ return base; -+} -+ -+/** -+ * sil680_seldev - return register base -+ * @hwif: interface -+ * @r: config offset -+ * -+ * Turn a config register offset into the right address in either -+ * PCI space or MMIO space to access the control register in question -+ * including accounting for the unit shift. -+ */ -+ -+static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r) -+{ -+ unsigned long base = 0xA0 + r; -+ base += (ap->hard_port_no << 4); -+ base |= adev->devno ? 2 : 0; -+ return base; -+} -+ -+ -+/** -+ * sil680_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection. The SIL680 stores this in PCI config -+ * space for us. -+ */ -+ -+static int sil680_cable_detect(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ unsigned long addr = sil680_selreg(ap, 0); -+ u8 ata66; -+ pci_read_config_byte(pdev, addr, &ata66); -+ if (ata66 & 1) -+ return ATA_CBL_PATA80; -+ else -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * sil680_bus_reset - reset the SIL680 bus -+ * @ap: ATA port to reset -+ * -+ * Perform the SIL680 housekeeping when doing an ATA bus reset -+ */ -+ -+static void sil680_bus_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ unsigned long addr = sil680_selreg(ap, 0); -+ u8 reset; -+ -+ pci_read_config_byte(pdev, addr, &reset); -+ pci_write_config_byte(pdev, addr, reset | 0x03); -+ udelay(25); -+ pci_write_config_byte(pdev, addr, reset); -+ ata_bus_reset(ap); -+} -+ -+static void sil680_phy_reset(struct ata_port *ap) -+{ -+ ap->cbl = sil680_cable_detect(ap); -+ sil680_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * sil680_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the SIL680 registers for PIO mode. Note that the task speed -+ * registers are shared between the devices so we must pick the lowest -+ * mode for command work. -+ */ -+ -+static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 }; -+ static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 }; -+ -+ unsigned long tfaddr = sil680_selreg(ap, 0x02); -+ unsigned long addr = sil680_seldev(ap, adev, 0x04); -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int pio = adev->pio_mode - XFER_PIO_0; -+ int lowest_pio = pio; -+ u16 reg; -+ -+ struct ata_device *pair = ata_dev_pair(ap, adev); -+ -+ if (pair != NULL) { -+ if (adev->pio_mode > pair->pio_mode) -+ lowest_pio = pair->pio_mode - XFER_PIO_0; -+ } -+ -+ pci_write_config_word(pdev, addr, speed_p[pio]); -+ pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]); -+ -+ pci_read_config_word(pdev, tfaddr-2, ®); -+ reg &= ~0x0200; /* Clear IORDY */ -+ if (ata_pio_need_iordy(adev)) -+ reg |= 0x0200; /* Enable IORDY */ -+ pci_write_config_word(pdev, tfaddr-2, reg); -+} -+ -+/** -+ * sil680_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Program the MWDMA/UDMA modes for the sil680 k -+ * chipset. The MWDMA mode values are pulled from a lookup table -+ * while the chipset uses mode number for UDMA. -+ */ -+ -+static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ static u8 ultra_table[2][7] = { -+ { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF }, /* 100MHz */ -+ { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, /* 133Mhz */ -+ }; -+ static u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 }; -+ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ unsigned long ma = sil680_seldev(ap, adev, 0x08); -+ unsigned long ua = sil680_seldev(ap, adev, 0x0C); -+ unsigned long addr_mask = 0x80 + 4 * ap->hard_port_no; -+ int port_shift = adev->devno * 4; -+ u8 scsc, mode; -+ u16 multi, ultra; -+ -+ pci_read_config_byte(pdev, 0x8A, &scsc); -+ pci_read_config_byte(pdev, addr_mask, &mode); -+ pci_read_config_word(pdev, ma, &multi); -+ pci_read_config_word(pdev, ua, &ultra); -+ -+ /* Mask timing bits */ -+ ultra &= ~0x3F; -+ mode &= ~(0x03 << port_shift); -+ -+ /* Extract scsc */ -+ scsc = (scsc & 0x30) ? 1: 0; -+ -+ if (adev->dma_mode >= XFER_UDMA_0) { -+ multi = 0x10C1; -+ ultra |= ultra_table[scsc][adev->dma_mode - XFER_UDMA_0]; -+ mode |= (0x03 << port_shift); -+ } else { -+ multi = dma_table[adev->dma_mode - XFER_MW_DMA_0]; -+ mode |= (0x02 << port_shift); -+ } -+ pci_write_config_byte(pdev, addr_mask, mode); -+ pci_write_config_word(pdev, ma, multi); -+ pci_write_config_word(pdev, ua, ultra); -+} -+ -+static struct scsi_host_template sil680_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations sil680_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sil680_set_piomode, -+ .set_dmamode = sil680_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sil680_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &sil680_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7f, -+ .port_ops = &sil680_port_ops -+ }; -+ static struct ata_port_info info_slow = { -+ .sht = &sil680_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &sil680_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = {&info, &info}; -+ static int printed_version; -+ u32 class_rev = 0; -+ u8 tmpbyte = 0; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); -+ -+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); -+ class_rev &= 0xff; -+ /* FIXME: double check */ -+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255); -+ -+ pci_write_config_byte(pdev, 0x80, 0x00); -+ pci_write_config_byte(pdev, 0x84, 0x00); -+ pci_read_config_byte(pdev, 0x8A, &tmpbyte); -+ switch(tmpbyte & 0x30) { -+ case 0x00: -+ /* 133 clock attempt to force it on */ -+ pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10); -+ case 0x30: -+ /* if clocking is disabled */ -+ /* 133 clock attempt to force it on */ -+ pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20); -+ case 0x10: -+ /* 133 already */ -+ break; -+ case 0x20: -+ /* BIOS set PCI x2 clocking */ -+ break; -+ } -+ -+ pci_read_config_byte(pdev, 0x8A, &tmpbyte); -+ if ((tmpbyte & 0x30) == 0) -+ port_info[0] = port_info[1] = &info_slow; -+ -+ pci_write_config_byte(pdev, 0xA1, 0x72); -+ pci_write_config_word(pdev, 0xA2, 0x328A); -+ pci_write_config_dword(pdev, 0xA4, 0x62DD62DD); -+ pci_write_config_dword(pdev, 0xA8, 0x43924392); -+ pci_write_config_dword(pdev, 0xAC, 0x40094009); -+ pci_write_config_byte(pdev, 0xB1, 0x72); -+ pci_write_config_word(pdev, 0xB2, 0x328A); -+ pci_write_config_dword(pdev, 0xB4, 0x62DD62DD); -+ pci_write_config_dword(pdev, 0xB8, 0x43924392); -+ pci_write_config_dword(pdev, 0xBC, 0x40094009); -+ -+ switch(tmpbyte & 0x30) { -+ case 0x00: printk(KERN_INFO "sil680: 100MHz clock.\n");break; -+ case 0x10: printk(KERN_INFO "sil680: 133MHz clock.\n");break; -+ case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break; -+ /* This last case is _NOT_ ok */ -+ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n"); -+ return -EIO; -+ } -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id sil680[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), }, -+ { 0, }, -+}; -+ -+static struct pci_driver sil680_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = sil680, -+ .probe = sil680_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init sil680_init(void) -+{ -+ return pci_register_driver(&sil680_pci_driver); -+} -+ -+ -+static void __exit sil680_exit(void) -+{ -+ pci_unregister_driver(&sil680_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for SI680 PATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, sil680); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(sil680_init); -+module_exit(sil680_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sis.c linux-2.6.16-rc4/drivers/scsi/pata_sis.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sis.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_sis.c 2006-02-16 15:36:13.000000000 +0000 -@@ -0,0 +1,982 @@ -+/* -+ * pata_sis.c - SiS ATA driver -+ * -+ * (C) 2005 Red Hat <alan@redhat.com> -+ * -+ * Based upon linux/drivers/ide/pci/sis5513.c -+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> -+ * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer -+ * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> -+ * SiS Taiwan : for direct support and hardware. -+ * Daniela Engert : for initial ATA100 advices and numerous others. -+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt : -+ * for checking code correctness, providing patches. -+ * Original tests and design on the SiS620 chipset. -+ * ATA100 tests and design on the SiS735 chipset. -+ * ATA16/33 support from specs -+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw> -+ * -+ * -+ * TODO -+ * Check MWDMA on drives that don't support MWDMA speed pio cycles ? -+ * More Testing -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+#include <linux/ata.h> -+ -+#define DRV_NAME "pata_sis" -+#define DRV_VERSION "0.1" -+ -+struct sis_chipset { -+ u16 device; /* PCI host ID */ -+ struct ata_port_info *info; /* Info block */ -+ /* Probably add family, cable detect type etc here to clean -+ up code later */ -+}; -+ -+/** -+ * sis_133_cable_detect - check for 40/80 pin -+ * @ap: Port -+ * -+ * Perform cable detection for the later UDMA133 capable -+ * SiS chipset. -+ */ -+ -+static int sis_133_cable_detect(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u16 tmp; -+ -+ pci_read_config_word(pdev, 0x50 + 2 * ap->hard_port_no, &tmp); -+ if (tmp & 0x8000) -+ return ATA_CBL_PATA40; -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * sis_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_133_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits sis_enable_bits[] = { -+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ -+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = sis_133_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+ -+/** -+ * sis_66_cable_detect - check for 40/80 pin -+ * @ap: Port -+ * -+ * Perform cable detection on the UDMA66, UDMA100 and early UDMA133 -+ * SiS IDE controllers. -+ */ -+ -+static int sis_66_cable_detect(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 tmp; -+ -+ pci_read_config_byte(pdev, 0x48, &tmp); -+ tmp >>= ap->hard_port_no; -+ if (tmp & 0x10) -+ return ATA_CBL_PATA40; -+ return ATA_CBL_PATA80; -+} -+ -+/** -+ * sis_66_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_66_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits sis_enable_bits[] = { -+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ -+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = sis_66_cable_detect(ap); -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+ -+/** -+ * sis_old_phy_reset - Probe specified port on PATA host controller -+ * @ap: Port to probe -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_old_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits sis_enable_bits[] = { -+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */ -+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */ -+ }; -+ -+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * sis_set_fifo - Set RWP fifo bits for this device -+ * @ap: Port -+ * @adev: Device -+ * -+ * SIS chipsets implement prefetch/postwrite bits for each device -+ * on both channels. This functionality is not ATAPI compatible and -+ * must be configured according to the class of device present -+ */ -+ -+static void sis_set_fifo(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u8 reg4b; -+ u8 mask = 0x11; -+ -+ mask <<= (2 * ap->hard_port_no); -+ mask <<= adev->devno; -+ -+ pci_read_config_byte(pdev, 0x4B, ®4b); -+ reg4b &= ~mask; -+ -+ /* Enable for ATA (disk) only */ -+ if (adev->class == ATA_DEV_ATA) -+ reg4b |= mask; -+ pci_write_config_byte(pdev, 0x4B, reg4b); -+} -+ -+/** -+ * sis_old_set_piomode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring for. -+ * -+ * Set PIO mode for device, in host controller PCI config space. This -+ * function handles PIO set up for all chips that are pre ATA100 and -+ * also early ATA100 devices. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ u8 t1, t2; -+ int speed = adev->pio_mode - XFER_PIO_0; -+ -+ const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 }; -+ const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 }; -+ -+ sis_set_fifo(ap, adev); -+ -+ pci_read_config_byte(pdev, port, &t1); -+ pci_read_config_byte(pdev, port + 1, &t2); -+ -+ t1 &= ~0x0F; /* Clear active/recovery timings */ -+ t2 &= ~0x07; -+ -+ t1 |= active[speed]; -+ t2 |= recovery[speed]; -+ -+ pci_write_config_byte(pdev, port, t1); -+ pci_write_config_byte(pdev, port + 1, t2); -+} -+ -+/** -+ * sis_100_set_pioode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring for. -+ * -+ * Set PIO mode for device, in host controller PCI config space. This -+ * function handles PIO set up for ATA100 devices and early ATA133. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ int speed = adev->pio_mode - XFER_PIO_0; -+ -+ const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 }; -+ -+ sis_set_fifo(ap, adev); -+ -+ pci_write_config_byte(pdev, port, actrec[speed]); -+} -+ -+/** -+ * sis_133_set_pioode - Initialize host controller PATA PIO timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device we are configuring for. -+ * -+ * Set PIO mode for device, in host controller PCI config space. This -+ * function handles PIO set up for the later ATA133 devices. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int port = 0x40; -+ u32 t1; -+ u32 reg54; -+ int speed = adev->pio_mode - XFER_PIO_0; -+ -+ const u32 timing100[] = { -+ 0x28269000, /* Recovery << 24 | Act << 16 | Ini << 12 */ -+ 0x0C266000, -+ 0x04263000, -+ 0x0C0A3000, -+ 0x05093000 -+ }; -+ const u32 timing133[] = { -+ 0x1E1C6000, /* Recovery << 24 | Act << 16 | Ini << 12 */ -+ 0x091C4000, -+ 0x031C2000, -+ 0x09072000, -+ 0x04062000 -+ }; -+ -+ sis_set_fifo(ap, adev); -+ -+ pci_read_config_dword(pdev, 0x54, ®54); -+ if (reg54 & 0x40000000) -+ port = 0x70; -+ port += 8 * ap->hard_port_no + 4 * adev->devno; -+ -+ pci_read_config_dword(pdev, port, &t1); -+ t1 &= 0xC0C00FFF; /* Mask out timing */ -+ -+ if (t1 & 0x08) /* 100 or 133 ? */ -+ t1 |= timing133[speed]; -+ else -+ t1 |= timing100[speed]; -+ pci_write_config_byte(pdev, port, t1); -+} -+ -+/** -+ * sis_old_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * Handles pre UDMA and UDMA33 devices. Supports MWDMA as well unlike -+ * the old ide/pci driver. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ int drive_pci = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ u16 timing; -+ -+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 }; -+ const u16 udma_bits[] = { -+ 0xE000, 0xC000, 0xA000 -+ }; -+ -+ pci_read_config_word(pdev, drive_pci, &timing); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ /* bits 3-0 hold recovery timing bits 8-10 active timing and -+ the higer bits are dependant on the device */ -+ timing &= ~ 0x870F; -+ timing |= mwdma_bits[speed]; -+ pci_write_config_word(pdev, drive_pci, timing); -+ } else { -+ /* Bit 15 is UDMA on/off, bit 13-14 are cycle time */ -+ speed = adev->dma_mode - XFER_UDMA_0; -+ timing &= ~0x6000; -+ timing |= udma_bits[speed]; -+ } -+} -+ -+/** -+ * sis_66_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * Handles UDMA66 and early UDMA100 devices. Supports MWDMA as well unlike -+ * the old ide/pci driver. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ int drive_pci = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ u16 timing; -+ -+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 }; -+ const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000}; -+ -+ pci_read_config_word(pdev, drive_pci, &timing); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ /* bits 3-0 hold recovery timing bits 8-10 active timing and -+ the higer bits are dependant on the device, bit 15 udma */ -+ timing &= ~ 0x870F; -+ timing |= mwdma_bits[speed]; -+ } else { -+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */ -+ speed = adev->dma_mode - XFER_UDMA_0; -+ timing &= ~0x6000; -+ timing |= udma_bits[speed]; -+ } -+ pci_write_config_word(pdev, drive_pci, timing); -+} -+ -+/** -+ * sis_100_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * Handles UDMA66 and early UDMA100 devices. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ int drive_pci = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ u16 timing; -+ -+ const u16 udma_bits[] = { 0x8B00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100}; -+ -+ pci_read_config_word(pdev, drive_pci, &timing); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */ -+ } else { -+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */ -+ speed = adev->dma_mode - XFER_UDMA_0; -+ timing &= ~0x0F00; -+ timing |= udma_bits[speed]; -+ } -+ pci_write_config_word(pdev, drive_pci, timing); -+} -+ -+/** -+ * sis_133_early_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike -+ * the old ide/pci driver. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ int drive_pci = 0x40 + 4 * ap->hard_port_no + 2 * adev->devno; -+ u16 timing; -+ -+ const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100}; -+ -+ pci_read_config_word(pdev, drive_pci, &timing); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */ -+ } else { -+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */ -+ speed = adev->dma_mode - XFER_UDMA_0; -+ timing &= ~0x0F00; -+ timing |= udma_bits[speed]; -+ } -+ pci_write_config_word(pdev, drive_pci, timing); -+} -+ -+/** -+ * sis_133_set_dmamode - Initialize host controller PATA DMA timings -+ * @ap: Port whose timings we are configuring -+ * @adev: Device to program -+ * -+ * Set UDMA/MWDMA mode for device, in host controller PCI config space. -+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike -+ * the old ide/pci driver. -+ * -+ * LOCKING: -+ * None (inherited from caller). -+ */ -+ -+static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ int speed = adev->dma_mode - XFER_MW_DMA_0; -+ int port = 0x40; -+ u32 t1; -+ u32 reg54; -+ -+ /* bits 4- cycle time 8 - cvs time */ -+ const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 }; -+ const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 }; -+ -+ pci_read_config_dword(pdev, 0x54, ®54); -+ if (reg54 & 0x40000000) -+ port = 0x70; -+ port += 8 * ap->hard_port_no + 4 * adev->devno; -+ -+ pci_read_config_dword(pdev, port, &t1); -+ -+ if (adev->dma_mode < XFER_UDMA_0) { -+ t1 &= ~0x00000004; -+ /* FIXME: need data sheet to add MWDMA here. Also lacking on -+ ide/pci driver */ -+ } else { -+ speed = adev->dma_mode - XFER_UDMA_0; -+ /* if & 8 no UDMA133 - need info for ... */ -+ t1 &= ~0x00000FF0; -+ t1 |= 0x00000004; -+ if (t1 & 0x08) -+ t1 |= timing_u133[speed]; -+ else -+ t1 |= timing_u100[speed]; -+ } -+ pci_write_config_dword(pdev, port, t1); -+} -+ -+static struct scsi_host_template sis_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static const struct ata_port_operations sis_133_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sis_133_set_piomode, -+ .set_dmamode = sis_133_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sis_133_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations sis_133_early_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sis_100_set_piomode, -+ .set_dmamode = sis_133_early_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sis_66_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations sis_100_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sis_100_set_piomode, -+ .set_dmamode = sis_100_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sis_66_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations sis_66_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sis_old_set_piomode, -+ .set_dmamode = sis_66_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sis_66_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static const struct ata_port_operations sis_old_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sis_old_set_piomode, -+ .set_dmamode = sis_old_set_dmamode, -+ -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sis_old_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .eng_timeout = ata_eng_timeout, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop, -+}; -+ -+static struct ata_port_info sis_info = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, -+ .udma_mask = 0, -+ .port_ops = &sis_old_ops, -+}; -+static struct ata_port_info sis_info33 = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .mwdma_mask = 0x07, -+ .udma_mask = ATA_UDMA2, /* UDMA 33 */ -+ .port_ops = &sis_old_ops, -+}; -+static struct ata_port_info sis_info66 = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .udma_mask = ATA_UDMA4, /* UDMA 66 */ -+ .port_ops = &sis_66_ops, -+}; -+static struct ata_port_info sis_info100 = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .udma_mask = ATA_UDMA5, -+ .port_ops = &sis_100_ops, -+}; -+static struct ata_port_info sis_info100_early = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .udma_mask = ATA_UDMA5, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .port_ops = &sis_66_ops, -+}; -+static struct ata_port_info sis_info133 = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &sis_133_ops, -+}; -+static struct ata_port_info sis_info133_early = { -+ .sht = &sis_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, /* pio0-4 */ -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &sis_133_early_ops, -+}; -+ -+ -+static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis) -+{ -+ u16 regw; -+ u8 reg; -+ -+ if (sis->info == &sis_info133) { -+ pci_read_config_word(pdev, 0x50, ®w); -+ if (regw & 0x08) -+ pci_write_config_word(pdev, 0x50, regw & ~0x08); -+ pci_read_config_word(pdev, 0x52, ®w); -+ if (regw & 0x08) -+ pci_write_config_word(pdev, 0x52, regw & ~0x08); -+ return; -+ } -+ -+ if (sis->info == &sis_info133_early || sis->info == &sis_info100) { -+ /* Fix up latency */ -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); -+ /* Set compatibility bit */ -+ pci_read_config_byte(pdev, 0x49, ®); -+ if (!(reg & 0x01)) -+ pci_write_config_byte(pdev, 0x49, reg | 0x01); -+ return; -+ } -+ -+ if (sis->info == &sis_info66 || sis->info == &sis_info100_early) { -+ /* Fix up latency */ -+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); -+ /* Set compatibility bit */ -+ pci_read_config_byte(pdev, 0x52, ®); -+ if (!(reg & 0x04)) -+ pci_write_config_byte(pdev, 0x52, reg | 0x04); -+ return; -+ } -+ -+ if (sis->info == &sis_info33) { -+ pci_read_config_byte(pdev, PCI_CLASS_PROG, ®); -+ if (( reg & 0x0F ) != 0x00) -+ pci_write_config_byte(pdev, PCI_CLASS_PROG, reg & 0xF0); -+ /* Fall through to ATA16 fixup below */ -+ } -+ -+ if (sis->info == &sis_info || sis->info == &sis_info33) { -+ /* force per drive recovery and active timings -+ needed on ATA_33 and below chips */ -+ pci_read_config_byte(pdev, 0x52, ®); -+ if (!(reg & 0x08)) -+ pci_write_config_byte(pdev, 0x52, reg|0x08); -+ return; -+ } -+ -+ BUG(); -+} -+ -+/** -+ * sis_init_one - Register SiS ATA PCI device with kernel services -+ * @pdev: PCI device to register -+ * @ent: Entry in sis_pci_tbl matching with @pdev -+ * -+ * Called from kernel PCI layer. We probe for combined mode (sigh), -+ * and then hand over control to libata, for it to do the rest. -+ * -+ * LOCKING: -+ * Inherited from PCI layer (may sleep). -+ * -+ * RETURNS: -+ * Zero on success, or -ERRNO value. -+ */ -+ -+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ static int printed_version; -+ static struct ata_port_info *port_info[2]; -+ struct ata_port_info *port; -+ struct pci_dev *host; -+ struct sis_chipset *chipset = NULL; -+ -+ static struct sis_chipset sis_chipsets[] = { -+ { 0x0745, &sis_info100 }, -+ { 0x0735, &sis_info100 }, -+ { 0x0733, &sis_info100 }, -+ { 0x0635, &sis_info100 }, -+ { 0x0633, &sis_info100 }, -+ -+ { 0x0730, &sis_info100_early }, /* 100 with ATA 66 layout */ -+ { 0x0550, &sis_info100_early }, /* 100 with ATA 66 layout */ -+ -+ { 0x0640, &sis_info66 }, -+ { 0x0630, &sis_info66 }, -+ { 0x0620, &sis_info66 }, -+ { 0x0540, &sis_info66 }, -+ { 0x0530, &sis_info66 }, -+ -+ { 0x5600, &sis_info33 }, -+ { 0x5598, &sis_info33 }, -+ { 0x5597, &sis_info33 }, -+ { 0x5591, &sis_info33 }, -+ { 0x5582, &sis_info33 }, -+ { 0x5581, &sis_info33 }, -+ -+ { 0x5596, &sis_info }, -+ { 0x5571, &sis_info }, -+ { 0x5517, &sis_info }, -+ { 0x5511, &sis_info }, -+ -+ {0} -+ }; -+ static struct sis_chipset sis133_early = { -+ 0x0, &sis_info133_early -+ }; -+ static struct sis_chipset sis133 = { -+ 0x0, &sis_info133 -+ }; -+ static struct sis_chipset sis100_early = { -+ 0x0, &sis_info100_early -+ }; -+ static struct sis_chipset sis100 = { -+ 0x0, &sis_info100 -+ }; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, -+ "version " DRV_VERSION "\n"); -+ -+ /* We have to find the bridge first */ -+ -+ for (chipset = &sis_chipsets[0]; chipset->device; chipset++) { -+ host = pci_get_device(0x1039, chipset->device, NULL); -+ if (host != NULL) { -+ if (chipset->device == 0x630) { /* SIS630 */ -+ u8 host_rev; -+ pci_read_config_byte(host, PCI_REVISION_ID, &host_rev); -+ if (host_rev >= 0x30) /* 630 ET */ -+ chipset = &sis100_early; -+ } -+ break; -+ } -+ } -+ -+ /* Look for concealed bridges */ -+ if (host == NULL) { -+ /* Second check */ -+ u32 idemisc; -+ u16 trueid; -+ -+ /* Disable ID masking and register remapping then -+ see what the real ID is */ -+ -+ pci_read_config_dword(pdev, 0x54, &idemisc); -+ pci_write_config_dword(pdev, 0x54, idemisc & 0x7fffffff); -+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid); -+ pci_write_config_dword(pdev, 0x54, idemisc); -+ -+ switch(trueid) { -+ case 0x5518: /* SIS 962/963 */ -+ chipset = &sis133; -+ if ((idemisc & 0x40000000) == 0) { -+ pci_write_config_dword(pdev, 0x54, idemisc | 0x40000000); -+ printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n"); -+ } -+ break; -+ case 0x0180: /* SIS 965/965L */ -+ chipset = &sis133; -+ break; -+ case 0x1180: /* SIS 966/966L */ -+ chipset = &sis133; -+ break; -+ } -+ } -+ -+ /* Further check */ -+ if (chipset == NULL) { -+ struct pci_dev *lpc_bridge; -+ u16 trueid; -+ u8 prefctl; -+ u8 idecfg; -+ u8 sbrev; -+ -+ /* Try the second unmasking technique */ -+ pci_read_config_byte(pdev, 0x4a, &idecfg); -+ pci_write_config_byte(pdev, 0x4a, idecfg | 0x10); -+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid); -+ pci_write_config_byte(pdev, 0x4a, idecfg); -+ -+ switch(trueid) { -+ case 0x5517: -+ lpc_bridge = pci_get_slot(0x00, 0x10); /* Bus 0 Dev 2 Fn 0 */ -+ if (lpc_bridge == NULL) -+ break; -+ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); -+ pci_read_config_byte(pdev, 0x49, &prefctl); -+ pci_dev_put(lpc_bridge); -+ -+ if (sbrev == 0x10 && (prefctl & 0x80)) { -+ chipset = &sis133_early; -+ break; -+ } -+ chipset = &sis100; -+ break; -+ } -+ } -+ pci_dev_put(host); -+ -+ /* No chipset info, no support */ -+ if (chipset == NULL) -+ return -ENODEV; -+ -+ port = chipset->info; -+ port->private_data = chipset; -+ -+ sis_fixup(pdev, chipset); -+ -+ port_info[0] = port_info[1] = port; -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id sis_pci_tbl[] = { -+ { 0x1039, 0x5513, PCI_ANY_ID, PCI_ANY_ID, }, -+ { 0x1039, 0x5518, PCI_ANY_ID, PCI_ANY_ID, }, -+ { } /* terminate list */ -+}; -+ -+static struct pci_driver sis_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = sis_pci_tbl, -+ .probe = sis_init_one, -+ .remove = ata_pci_remove_one, -+}; -+ -+static int __init sis_init(void) -+{ -+ return pci_register_driver(&sis_pci_driver); -+} -+ -+static void __exit sis_exit(void) -+{ -+ pci_unregister_driver(&sis_pci_driver); -+} -+ -+ -+module_init(sis_init); -+module_exit(sis_exit); -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, sis_pci_tbl); -+MODULE_VERSION(DRV_VERSION); -+ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sl82c105.c linux-2.6.16-rc4/drivers/scsi/pata_sl82c105.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_sl82c105.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_sl82c105.c 2006-02-16 15:36:32.000000000 +0000 -@@ -0,0 +1,376 @@ -+/* -+ * pata_sl82c105.c - SL82C105 PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Based in part on linux/drivers/ide/pci/sl82c105.c -+ * SL82C105/Winbond 553 IDE driver -+ * -+ * and in part on the documentation and errata sheet -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_sl82c105" -+#define DRV_VERSION "0.1.1" -+ -+enum { -+ /* -+ * SL82C105 PCI config register 0x40 bits. -+ */ -+ CTRL_IDE_IRQB = (1 << 30), -+ CTRL_IDE_IRQA = (1 << 28), -+ CTRL_LEGIRQ = (1 << 11), -+ CTRL_P1F16 = (1 << 5), -+ CTRL_P1EN = (1 << 4), -+ CTRL_P0F16 = (1 << 1), -+ CTRL_P0EN = (1 << 0) -+}; -+ -+static void sl82c105_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits sl82c105_enable_bits[] = { -+ { 0x40, 1, 0x01, 0x01 }, -+ { 0x40, 1, 0x10, 0x10 } -+ }; -+ -+ if (ap->hard_port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ dev_printk(KERN_INFO, &pdev->dev, "port disabled. ignoring.\n"); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+ -+/** -+ * sl82c105_configure_piomode - set chip PIO timing -+ * @ap: ATA interface -+ * @adev: ATA device -+ * @pio: PIO mode -+ * -+ * Called to do the PIO mode setup. Our timing registers are shared -+ * so a configure_dmamode call will undo any work we do here and vice -+ * versa -+ */ -+ -+static void sl82c105_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static u16 pio_timing[5] = { -+ 0x50D, 0x407, 0x304, 0x242, 0x240 -+ }; -+ u16 dummy; -+ int timing = 0x44 + 8 * ap->hard_port_no + 4 * adev->devno; -+ -+ pci_write_config_word(pdev, timing, pio_timing[pio]); -+ /* Can we lose this oddity of the old driver */ -+ pci_read_config_word(pdev, timing, &dummy); -+} -+ -+/** -+ * sl82c105_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the PIO mode setup. Our timing registers are shared -+ * but we want to set the PIO timing by default. -+ */ -+ -+static void sl82c105_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ sl82c105_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); -+} -+ -+/** -+ * sl82c105_configure_dmamode - set DMA mode in chip -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Load DMA cycle times into the chip ready for a DMA transfer -+ * to occur. -+ */ -+ -+static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static u16 dma_timing[3] = { -+ 0x707, 0x201, 0x200 -+ }; -+ u16 dummy; -+ int timing = 0x44 + 8 * ap->hard_port_no + 4 * adev->devno; -+ int dma = adev->dma_mode - XFER_MW_DMA_0; -+ -+ pci_write_config_word(pdev, timing, dma_timing[dma]); -+ /* Can we lose this oddity of the old driver */ -+ pci_read_config_word(pdev, timing, &dummy); -+} -+ -+/** -+ * sl82c105_set_dmamode - set initial DMA mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Called to do the DMA mode setup. This replaces the PIO timings -+ * for the device in question. Set appropriate PIO timings not DMA -+ * timings at this point. -+ */ -+ -+static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ switch(adev->dma_mode) { -+ case XFER_MW_DMA_0: -+ sl82c105_configure_piomode(ap, adev, 1); -+ break; -+ case XFER_MW_DMA_1: -+ sl82c105_configure_piomode(ap, adev, 3); -+ break; -+ case XFER_MW_DMA_2: -+ sl82c105_configure_piomode(ap, adev, 3); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+/** -+ * sl82c105_reset_engine - Reset the DMA engine -+ * @ap: ATA interface -+ * -+ * The sl82c105 has some serious problems with the DMA engine -+ * when transfers don't run as expected or ATAPI is used. The -+ * recommended fix is to reset the engine each use using a chip -+ * test register. -+ */ -+ -+static void sl82c105_reset_engine(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u16 val; -+ -+ pci_read_config_word(pdev, 0x7E, &val); -+ pci_write_config_word(pdev, 0x7E, val | 4); -+ pci_write_config_word(pdev, 0x7E, val & ~4); -+} -+ -+/** -+ * sl82c105_bmdma_start - DMA engine begin -+ * @qc: ATA command -+ * -+ * Reset the DMA engine each use as recommended by the errata -+ * document. -+ * -+ * FIXME: if we switch clock at BMDMA start/end we might get better -+ * PIO performance on DMA capable devices. -+ */ -+ -+static void sl82c105_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ -+ sl82c105_reset_engine(ap); -+ -+ /* Set the clocks for DMA */ -+ sl82c105_configure_dmamode(ap, qc->dev); -+ /* Activate DMA */ -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * sl82c105_bmdma_end - DMA engine stop -+ * @qc: ATA command -+ * -+ * Reset the DMA engine each use as recommended by the errata -+ * document. -+ * -+ * This function is also called to turn off DMA when a timeout occurs -+ * during DMA operation. In both cases we need to reset the engine, -+ * so no actual eng_timeout handler is required. -+ * -+ * We assume bmdma_stop is always called if bmdma_start as called. If -+ * not then we may need to wrap qc_issue. -+ */ -+ -+static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ -+ ata_bmdma_stop(qc); -+ sl82c105_reset_engine(ap); -+ -+ /* This will redo the initial setup of the DMA device to matching -+ PIO timings */ -+ sl82c105_set_dmamode(ap, qc->dev); -+} -+ -+static struct scsi_host_template sl82c105_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations sl82c105_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = sl82c105_set_piomode, -+ .set_dmamode = sl82c105_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = sl82c105_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = sl82c105_bmdma_start, -+ .bmdma_stop = sl82c105_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * sl82c105_bridge_revision - find bridge version -+ * @pdev: PCI device for the ATA function -+ * -+ * Locates the PCI bridge associated with the ATA function and -+ * providing it is a Winbond 553 reports the revision. If it cannot -+ * find a revision or the right device it returns -1 -+ */ -+ -+static int sl82c105_bridge_revision(struct pci_dev *pdev) -+{ -+ struct pci_dev *bridge; -+ u8 rev; -+ -+ /* -+ * The bridge should be part of the same device, but function 0. -+ */ -+ bridge = pci_get_slot(pdev->bus, -+ PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); -+ if (!bridge) -+ return -1; -+ -+ /* -+ * Make sure it is a Winbond 553 and is an ISA bridge. -+ */ -+ if (bridge->vendor != PCI_VENDOR_ID_WINBOND || -+ bridge->device != PCI_DEVICE_ID_WINBOND_83C553 || -+ bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) { -+ pci_dev_put(bridge); -+ return -1; -+ } -+ /* -+ * We need to find function 0's revision, not function 1 -+ */ -+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev); -+ -+ pci_dev_put(bridge); -+ return rev; -+} -+ -+ -+static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info_dma = { -+ .sht = &sl82c105_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &sl82c105_port_ops -+ }; -+ static struct ata_port_info info_early = { -+ .sht = &sl82c105_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .port_ops = &sl82c105_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info_early, &info_early }; -+ u32 val; -+ int rev; -+ -+ rev = sl82c105_bridge_revision(dev); -+ -+ if (rev == -1) -+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n"); -+ else if (rev <= 5) -+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n"); -+ else { -+ port_info[0] = &info_dma; -+ port_info[1] = &info_dma; -+ } -+ -+ pci_read_config_dword(dev, 0x40, &val); -+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; -+ pci_write_config_dword(dev, 0x40, val); -+ -+ -+ return ata_pci_init_one(dev, port_info, 1); /* For now */ -+} -+ -+static struct pci_device_id sl82c105[] = { -+ { PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, }, -+}; -+ -+static struct pci_driver sl82c105_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = sl82c105, -+ .probe = sl82c105_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init sl82c105_init(void) -+{ -+ return pci_register_driver(&sl82c105_pci_driver); -+} -+ -+ -+static void __exit sl82c105_exit(void) -+{ -+ pci_unregister_driver(&sl82c105_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Sl82c105"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, sl82c105); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(sl82c105_init); -+module_exit(sl82c105_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_triflex.c linux-2.6.16-rc4/drivers/scsi/pata_triflex.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_triflex.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_triflex.c 2006-02-16 15:36:23.000000000 +0000 -@@ -0,0 +1,268 @@ -+/* -+ * pata_triflex.c - Compaq PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * based upon -+ * -+ * triflex.c -+ * -+ * IDE Chipset driver for the Compaq TriFlex IDE controller. -+ * -+ * Known to work with the Compaq Workstation 5x00 series. -+ * -+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P. -+ * Author: Torben Mathiasen <torben.mathiasen@hp.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Loosely based on the piix & svwks drivers. -+ * -+ * Documentation: -+ * Not publically available. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_triflex" -+#define DRV_VERSION "0.2.1" -+ -+static void triflex_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ static struct pci_bits triflex_enable_bits[] = { -+ { 0x80, 1, 0x01, 0x01 }, -+ { 0x80, 1, 0x02, 0x02 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = ATA_CBL_PATA40; -+ ata_port_probe(ap); -+ ata_bus_reset(ap); -+} -+ -+/** -+ * triflex_load_timing - timing configuration -+ * @ap: ATA interface -+ * @adev: Device on the bus -+ * @speed: speed to configure -+ * -+ * The Triflex has one set of timings per device per channel. This -+ * means we must do some switching. As the PIO and DMA timings don't -+ * match we have to do some reloading unlike PIIX devices where tuning -+ * tricks can avoid it. -+ */ -+ -+static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 timing = 0; -+ u32 triflex_timing, old_triflex_timing; -+ int channel_offset = ap->hard_port_no ? 0x74: 0x70; -+ unsigned int is_slave = (adev->devno != 0); -+ -+ -+ pci_read_config_dword(pdev, channel_offset, &old_triflex_timing); -+ triflex_timing = old_triflex_timing; -+ -+ switch(speed) -+ { -+ case XFER_MW_DMA_2: -+ timing = 0x0103;break; -+ case XFER_MW_DMA_1: -+ timing = 0x0203;break; -+ case XFER_MW_DMA_0: -+ timing = 0x0808;break; -+ case XFER_SW_DMA_2: -+ case XFER_SW_DMA_1: -+ case XFER_SW_DMA_0: -+ timing = 0x0F0F;break; -+ case XFER_PIO_4: -+ timing = 0x0202;break; -+ case XFER_PIO_3: -+ timing = 0x0204;break; -+ case XFER_PIO_2: -+ timing = 0x0404;break; -+ case XFER_PIO_1: -+ timing = 0x0508;break; -+ case XFER_PIO_0: -+ timing = 0x0808;break; -+ default: -+ BUG(); -+ } -+ triflex_timing &= ~ (0xFFFF << (16 * is_slave)); -+ triflex_timing |= (timing << (16 * is_slave)); -+ -+ if (triflex_timing != old_triflex_timing) -+ pci_write_config_dword(pdev, channel_offset, triflex_timing); -+} -+ -+/** -+ * triflex_set_piomode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * Use the timing loader to set up the PIO mode. We have to do this -+ * because DMA start/stop will only be called once DMA occurs. If there -+ * has been no DMA then the PIO timings are still needed. -+ */ -+static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ triflex_load_timing(ap, adev, adev->pio_mode); -+} -+ -+/** -+ * triflex_dma_start - DMA start callback -+ * @qc: Command in progress -+ * -+ * Usually drivers set the DMA timing at the point the set_dmamode call -+ * is made. Triflex however requires we load new timings on the -+ * transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc). -+ * We load the DMA timings just before starting DMA and then restore -+ * the PIO timing when the DMA is finished. -+ */ -+ -+static void triflex_bmdma_start(struct ata_queued_cmd *qc) -+{ -+ triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode); -+ ata_bmdma_start(qc); -+} -+ -+/** -+ * triflex_dma_stop - DMA stop callback -+ * @ap: ATA interface -+ * @adev: ATA device -+ * -+ * We loaded new timings in dma_start, as a result we need to restore -+ * the PIO timings in dma_stop so that the next command issue gets the -+ * right clock values. -+ */ -+ -+static void triflex_bmdma_stop(struct ata_queued_cmd *qc) -+{ -+ ata_bmdma_stop(qc); -+ triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode); -+} -+ -+static struct scsi_host_template triflex_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations triflex_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = triflex_set_piomode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = triflex_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = triflex_bmdma_start, -+ .bmdma_stop = triflex_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ static struct ata_port_info info = { -+ .sht = &triflex_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &triflex_port_ops -+ }; -+ static struct ata_port_info *port_info[2] = { &info, &info }; -+ static int printed_version; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); -+ -+ return ata_pci_init_one(dev, port_info, 2); -+} -+ -+static const struct pci_device_id triflex[] = { -+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -+ { 0, }, -+}; -+ -+static struct pci_driver triflex_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = triflex, -+ .probe = triflex_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init triflex_init(void) -+{ -+ return pci_register_driver(&triflex_pci_driver); -+} -+ -+ -+static void __exit triflex_exit(void) -+{ -+ pci_unregister_driver(&triflex_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for Compaq Triflex"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, triflex); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(triflex_init); -+module_exit(triflex_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pata_via.c linux-2.6.16-rc4/drivers/scsi/pata_via.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pata_via.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.16-rc4/drivers/scsi/pata_via.c 2006-02-16 15:28:17.000000000 +0000 -@@ -0,0 +1,547 @@ -+/* -+ * pata_via.c - VIA PATA for new ATA layer -+ * (C) 2005 Red Hat Inc -+ * Alan Cox <alan@redhat.com> -+ * -+ * Documentation -+ * Most chipset documentation available under NDA only -+ * -+ * VIA version guide -+ * VIA VT82C561 - early design, uses ata_generic currently -+ * VIA VT82C576 - MWDMA, 33Mhz -+ * VIA VT82C586 - MWDMA, 33Mhz -+ * VIA VT82C586a - Added UDMA to 33Mhz -+ * VIA VT82C586b - UDMA33 -+ * VIA VT82C596a - Nonfunctional UDMA66 -+ * VIA VT82C596b - Working UDMA66 -+ * VIA VT82C686 - Nonfunctional UDMA66 -+ * VIA VT82C686a - Working UDMA66 -+ * VIA VT82C686b - Updated to UDMA100 -+ * VIA VT8231 - UDMA100 -+ * VIA VT8233 - UDMA100 -+ * VIA VT8233a - UDMA133 -+ * VIA VT8233c - UDMA100 -+ * VIA VT8235 - UDMA133 -+ * VIA VT8237 - UDMA133 -+ * -+ * Most registers remain compatible across chips. Others start reserved -+ * and acquire sensible semantics if set to 1 (eg cable detect). A few -+ * exceptions exist, notably around the FIFO settings. -+ * -+ * One additional quirk of the VIA design is that like ALi they use few -+ * PCI IDs for a lot of chips. -+ * -+ * Based heavily on: -+ * -+ * Version 3.38 -+ * -+ * VIA IDE driver for Linux. Supported southbridges: -+ * -+ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, -+ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a, -+ * vt8235, vt8237 -+ * -+ * Copyright (c) 2000-2002 Vojtech Pavlik -+ * -+ * Based on the work of: -+ * Michel Aubry -+ * Jeff Garzik -+ * Andre Hedrick -+ -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/init.h> -+#include <linux/blkdev.h> -+#include <linux/delay.h> -+#include <scsi/scsi_host.h> -+#include <linux/libata.h> -+ -+#define DRV_NAME "pata_via" -+#define DRV_VERSION "0.1.4" -+ -+/* -+ * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx -+ * driver. -+ */ -+ -+enum { -+ VIA_UDMA = 0x007, -+ VIA_UDMA_NONE = 0x000, -+ VIA_UDMA_33 = 0x001, -+ VIA_UDMA_66 = 0x002, -+ VIA_UDMA_100 = 0x003, -+ VIA_UDMA_133 = 0x004, -+ VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */ -+ VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */ -+ VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */ -+ VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */ -+ VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */ -+ VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */ -+}; -+ -+/* -+ * VIA SouthBridge chips. -+ */ -+ -+static const struct via_isa_bridge { -+ const char *name; -+ u16 id; -+ u8 rev_min; -+ u8 rev_max; -+ u16 flags; -+} via_isa_bridges[] = { -+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, -+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, -+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, -+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 }, -+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, -+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 }, -+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, -+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 }, -+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, -+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 }, -+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, -+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO }, -+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ }, -+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO }, -+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, -+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, -+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, -+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, -+ { NULL } -+}; -+ -+/** -+ * via_cable_detect - cable detection -+ * @ap: ATA port -+ * -+ * Perform cable detection. Actually for the VIA case the BIOS -+ * already did this for us. We read the values provided by the -+ * BIOS. If you are using an 8235 in a non-PC configuration you -+ * may need to update this code. -+ * -+ * Hotplug also impacts on this. -+ */ -+ -+static int via_cable_detect(struct ata_port *ap) { -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ u32 ata66; -+ pci_read_config_dword(pdev, 0x50, &ata66); -+ /* Check both the drive cable reporting bits, we might not have -+ two drives */ -+ if (ata66 & (0x1010 << (16 * ap->hard_port_no))) -+ return ATA_CBL_PATA80; -+ else -+ return ATA_CBL_PATA40; -+} -+ -+/** -+ * via_phy_reset - reset for eary chip -+ * @ap: ATA port -+ * -+ * Handle the reset callback for the later chips with cable detect -+ */ -+ -+static void via_phy_reset(struct ata_port *ap) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ -+ /* Note: When we add VIA 6410 remember it doesn't have enable bits */ -+ static struct pci_bits via_enable_bits[] = { -+ { 0x40, 1, 0x02, 0x02 }, -+ { 0x40, 1, 0x01, 0x01 } -+ }; -+ -+ if (!pci_test_config_bits(pdev, &via_enable_bits[ap->hard_port_no])) { -+ ata_port_disable(ap); -+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); -+ return; -+ } -+ ap->cbl = via_cable_detect(ap); -+ ata_bus_reset(ap); -+ ata_port_probe(ap); -+} -+ -+/** -+ * via_do_set_mode - set initial PIO mode data -+ * @ap: ATA interface -+ * @adev: ATA device -+ * @mode: ATA mode being programmed -+ * @tdiv: Clocks per PCI clock -+ * @set_ast: Set to program address setup -+ * @udma_type: UDMA mode/format of registers -+ * -+ * Program the VIA registers for DMA and PIO modes. Uses the ata timing -+ * support in order to compute modes. -+ * -+ * FIXME: Hotplug will require we serialize multiple mode changes -+ * on the two channels. -+ */ -+ -+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type) -+{ -+ struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); -+ struct ata_device *peer = ata_dev_pair(ap, adev); -+ struct ata_timing t, p; -+ static int via_clock = 33000; /* Bus clock in kHZ - ought to be tunable one day */ -+ unsigned long T = 1000000000 / via_clock; -+ unsigned long UT = T/tdiv; -+ int ut; -+ int offset = 3 - (2*ap->hard_port_no) - adev->devno; -+ -+ printk("via_do_set_mode: Mode=%d ast broken=%c udma=%d mul=%d\n", -+ mode, "YN"[set_ast], udma_type, tdiv); -+ /* Calculate the timing values we require */ -+ ata_timing_compute(adev, adev->pio_mode, &t, T, UT); -+ -+ /* We share 8bit timing so we must merge the constraints */ -+ if (peer) { -+ if (peer->pio_mode) { -+ ata_timing_compute(peer, peer->pio_mode, &p, T, UT); -+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT); -+ } -+ if (peer->dma_mode) { -+ ata_timing_compute(peer, peer->dma_mode, &p, T, UT); -+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT); -+ } -+ } -+ -+ /* Address setup is programmable but breaks on UDMA133 setups */ -+ if (set_ast) { -+ u8 setup; /* 2 bits per drive */ -+ int shift = 2 * offset; -+ -+ pci_read_config_byte(pdev, 0x4C, &setup); -+ setup &= ~(3 << shift); -+ setup |= FIT(t.setup, 1, 4) << shift; -+ pci_write_config_byte(pdev, 0x4C, setup); -+ } -+ -+ /* Load the PIO mode bits */ -+ pci_write_config_byte(pdev, 0x4F - ap->hard_port_no, -+ ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1)); -+ pci_write_config_byte(pdev, 0x48 + offset, -+ ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1)); -+ -+ /* Load the UDMA bits according to type */ -+ switch(udma_type) { -+ default: -+ /* BUG() ? */ -+ /* fall through */ -+ case 33: -+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03; -+ break; -+ case 66: -+ ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f; -+ break; -+ case 100: -+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; -+ break; -+ case 133: -+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; -+ break; -+ } -+ /* Set UDMA unless device is not UDMA capable */ -+ if (udma_type) -+ pci_write_config_byte(pdev, 0x50 + offset, ut); -+} -+ -+static void via_set_piomode(struct ata_port *ap, struct ata_device *adev) -+{ -+ const struct via_isa_bridge *config = ap->host_set->private_data; -+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1; -+ int mode = config->flags & VIA_UDMA; -+ static u8 tclock[5] = { 1, 1, 2, 3, 4 }; -+ static u8 udma[5] = { 0, 33, 66, 100, 133 }; -+ -+ via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]); -+} -+ -+static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) -+{ -+ const struct via_isa_bridge *config = ap->host_set->private_data; -+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1; -+ int mode = config->flags & VIA_UDMA; -+ static u8 tclock[5] = { 1, 1, 2, 3, 4 }; -+ static u8 udma[5] = { 0, 33, 66, 100, 133 }; -+ -+ via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]); -+} -+ -+static struct scsi_host_template via_sht = { -+ .module = THIS_MODULE, -+ .name = DRV_NAME, -+ .ioctl = ata_scsi_ioctl, -+ .queuecommand = ata_scsi_queuecmd, -+ .eh_strategy_handler = ata_scsi_error, -+ .can_queue = ATA_DEF_QUEUE, -+ .this_id = ATA_SHT_THIS_ID, -+ .sg_tablesize = LIBATA_MAX_PRD, -+ .max_sectors = ATA_MAX_SECTORS, -+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN, -+ .emulated = ATA_SHT_EMULATED, -+ .use_clustering = ATA_SHT_USE_CLUSTERING, -+ .proc_name = DRV_NAME, -+ .dma_boundary = ATA_DMA_BOUNDARY, -+ .slave_configure = ata_scsi_slave_config, -+ .bios_param = ata_std_bios_param, -+// .ordered_flush = 1, -+}; -+ -+static struct ata_port_operations via_port_ops = { -+ .port_disable = ata_port_disable, -+ .set_piomode = via_set_piomode, -+ .set_dmamode = via_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = via_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+static struct ata_port_operations via_port_ops_noirq = { -+ .port_disable = ata_port_disable, -+ .set_piomode = via_set_piomode, -+ .set_dmamode = via_set_dmamode, -+ .tf_load = ata_tf_load, -+ .tf_read = ata_tf_read, -+ .check_status = ata_check_status, -+ .exec_command = ata_exec_command, -+ .dev_select = ata_std_dev_select, -+ -+ .phy_reset = via_phy_reset, -+ -+ .bmdma_setup = ata_bmdma_setup, -+ .bmdma_start = ata_bmdma_start, -+ .bmdma_stop = ata_bmdma_stop, -+ .bmdma_status = ata_bmdma_status, -+ -+ .qc_prep = ata_qc_prep, -+ .qc_issue = ata_qc_issue_prot, -+ .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer_noirq, -+ -+ .irq_handler = ata_interrupt, -+ .irq_clear = ata_bmdma_irq_clear, -+ -+ .port_start = ata_port_start, -+ .port_stop = ata_port_stop, -+ .host_stop = ata_host_stop -+}; -+ -+/** -+ * via_init_one - discovery callback -+ * @pdev: PCI device ID -+ * @id: PCI table info -+ * -+ * A VIA IDE interface has been discovered. Figure out what revision -+ * and perform configuration work before handing it to the ATA layer -+ */ -+ -+static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ /* Early VIA without UDMA support */ -+ static struct ata_port_info via_mwdma_info = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &via_port_ops -+ }; -+ /* Ditto with IRQ masking required */ -+ static struct ata_port_info via_mwdma_info_borked = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_IRQ_MASK, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .port_ops = &via_port_ops_noirq, -+ }; -+ /* VIA UDMA 33 devices (and borked 66) */ -+ static struct ata_port_info via_udma33_info = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x7, -+ .port_ops = &via_port_ops -+ }; -+ /* VIA UDMA 66 devices */ -+ static struct ata_port_info via_udma66_info = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x1f, -+ .port_ops = &via_port_ops -+ }; -+ /* VIA UDMA 100 devices */ -+ static struct ata_port_info via_udma100_info = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, -+ .port_ops = &via_port_ops -+ }; -+ /* UDMA133 with bad AST (All current 133) */ -+ static struct ata_port_info via_udma133_info = { -+ .sht = &via_sht, -+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, -+ .pio_mask = 0x1f, -+ .mwdma_mask = 0x07, -+ .udma_mask = 0x3f, /* 0x7F but need to fix north bridge */ -+ .port_ops = &via_port_ops -+ }; -+ struct ata_port_info *port_info[2], *type; -+ struct pci_dev *isa = NULL; -+ const struct via_isa_bridge *config; -+ static int printed_version; -+ u8 t; -+ u8 enable; -+ u32 timing; -+ -+ if (!printed_version++) -+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); -+ -+ /* To find out how the IDE will behave and what features we -+ actually have to look at the bridge not the IDE controller */ -+ for (config = via_isa_bridges; config->id; config++) -+ if ((isa = pci_get_device(PCI_VENDOR_ID_VIA + -+ !!(config->flags & VIA_BAD_ID), -+ config->id, NULL))) { -+ -+ pci_read_config_byte(isa, PCI_REVISION_ID, &t); -+ if (t >= config->rev_min && -+ t <= config->rev_max) -+ break; -+ pci_dev_put(isa); -+ } -+ -+ if (!config->id) { -+ printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n"); -+ return -ENODEV; -+ } -+ -+ /* 0x40 low bits indicate enabled channels */ -+ pci_read_config_byte(pdev, 0x40 , &enable); -+ enable &= 3; -+ if (enable == 0) { -+ pci_dev_put(isa); -+ return -ENODEV; -+ } -+ -+ /* Initialise the FIFO for the enabled channels. */ -+ if (config->flags & VIA_SET_FIFO) { -+ u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; -+ u8 fifo; -+ -+ pci_read_config_byte(pdev, 0x43, &fifo); -+ -+ /* Clear PREQ# until DDACK# for errata */ -+ if (config->flags & VIA_BAD_PREQ) -+ fifo &= 0x7F; -+ else -+ fifo &= 0x9f; -+ /* Turn on FIFO for enabled channels */ -+ fifo |= fifo_setting[enable]; -+ pci_write_config_byte(pdev, 0x43, fifo); -+ } -+ /* Clock set up */ -+ switch(config->flags & VIA_UDMA) { -+ case VIA_UDMA_NONE: -+ if (config->flags & VIA_NO_UNMASK) -+ type = &via_mwdma_info_borked; -+ else -+ type = &via_mwdma_info; -+ break; -+ case VIA_UDMA_33: -+ type = &via_udma33_info; -+ break; -+ case VIA_UDMA_66: -+ type = &via_udma66_info; -+ /* The 66 MHz devices require we enable the clock */ -+ pci_read_config_dword(pdev, 0x50, &timing); -+ timing |= 0x80008; -+ pci_write_config_dword(pdev, 0x50, timing); -+ break; -+ case VIA_UDMA_100: -+ type = &via_udma100_info; -+ break; -+ case VIA_UDMA_133: -+ type = &via_udma133_info; -+ break; -+ default: -+ type = NULL; -+ BUG(); -+ break; -+ } -+ -+ if (config->flags & VIA_BAD_CLK66) { -+ /* Disable the 66MHz clock on problem devices */ -+ pci_read_config_dword(pdev, 0x50, &timing); -+ timing &= ~0x80008; -+ pci_write_config_dword(pdev, 0x50, timing); -+ } -+ -+ /* We have established the device type, now fire it up */ -+ type->private_data = (void *)config; -+ -+ port_info[0] = port_info[1] = type; -+ return ata_pci_init_one(pdev, port_info, 2); -+} -+ -+static const struct pci_device_id via[] = { -+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, }, -+}; -+ -+static struct pci_driver via_pci_driver = { -+ .name = DRV_NAME, -+ .id_table = via, -+ .probe = via_init_one, -+ .remove = ata_pci_remove_one -+}; -+ -+static int __init via_init(void) -+{ -+ return pci_register_driver(&via_pci_driver); -+} -+ -+ -+static void __exit via_exit(void) -+{ -+ pci_unregister_driver(&via_pci_driver); -+} -+ -+ -+MODULE_AUTHOR("Alan Cox"); -+MODULE_DESCRIPTION("low-level driver for VIA PATA"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(pci, via); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(via_init); -+module_exit(via_exit); -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/pdc_adma.c linux-2.6.16-rc4/drivers/scsi/pdc_adma.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/pdc_adma.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/pdc_adma.c 2006-02-23 13:15:50.480287896 +0000 -@@ -322,7 +322,7 @@ - = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4); - i += 4; - -- VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", nelem, -+ VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4, - (unsigned long)addr, len); - } - return i; -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_mv.c linux-2.6.16-rc4/drivers/scsi/sata_mv.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_mv.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_mv.c 2006-02-20 11:28:03.000000000 +0000 -@@ -389,6 +389,7 @@ - - .qc_prep = mv_qc_prep, - .qc_issue = mv_qc_issue, -+ .data_xfer = ata_mmio_data_xfer, - - .eng_timeout = mv_eng_timeout, - -@@ -416,6 +417,7 @@ - - .qc_prep = mv_qc_prep, - .qc_issue = mv_qc_issue, -+ .data_xfer = ata_mmio_data_xfer, - - .eng_timeout = mv_eng_timeout, - -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_nv.c linux-2.6.16-rc4/drivers/scsi/sata_nv.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_nv.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_nv.c 2006-01-21 17:08:58.000000000 +0000 -@@ -258,6 +258,7 @@ - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .eng_timeout = ata_eng_timeout, -+ .data_xfer = ata_pio_data_xfer, - .irq_handler = nv_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .scr_read = nv_scr_read, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_promise.c linux-2.6.16-rc4/drivers/scsi/sata_promise.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_promise.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_promise.c 2006-02-06 12:36:12.000000000 +0000 -@@ -130,6 +130,7 @@ - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, - .eng_timeout = pdc_eng_timeout, -+ .data_xfer = ata_mmio_data_xfer, - .irq_handler = pdc_interrupt, - .irq_clear = pdc_irq_clear, - -@@ -152,6 +153,7 @@ - - .qc_prep = pdc_qc_prep, - .qc_issue = pdc_qc_issue_prot, -+ .data_xfer = ata_mmio_data_xfer, - .eng_timeout = pdc_eng_timeout, - .irq_handler = pdc_interrupt, - .irq_clear = pdc_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_qstor.c linux-2.6.16-rc4/drivers/scsi/sata_qstor.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_qstor.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_qstor.c 2006-01-21 17:09:57.000000000 +0000 -@@ -158,6 +158,7 @@ - .phy_reset = qs_phy_reset, - .qc_prep = qs_qc_prep, - .qc_issue = qs_qc_issue, -+ .data_xfer = ata_mmio_data_xfer, - .eng_timeout = qs_eng_timeout, - .irq_handler = qs_intr, - .irq_clear = qs_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sil24.c linux-2.6.16-rc4/drivers/scsi/sata_sil24.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sil24.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_sil24.c 2006-01-21 17:10:52.000000000 +0000 -@@ -309,6 +309,7 @@ - - .qc_prep = sil24_qc_prep, - .qc_issue = sil24_qc_issue, -+ .data_xfer = ata_mmio_data_xfer, - - .eng_timeout = sil24_eng_timeout, - -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sil.c linux-2.6.16-rc4/drivers/scsi/sata_sil.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sil.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_sil.c 2006-02-14 17:23:28.000000000 +0000 -@@ -165,6 +165,7 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_mmio_data_xfer, - .eng_timeout = ata_eng_timeout, - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sis.c linux-2.6.16-rc4/drivers/scsi/sata_sis.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sis.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_sis.c 2006-01-21 17:11:23.000000000 +0000 -@@ -115,6 +115,7 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, - .eng_timeout = ata_eng_timeout, - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_svw.c linux-2.6.16-rc4/drivers/scsi/sata_svw.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_svw.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_svw.c 2006-02-06 12:30:23.000000000 +0000 -@@ -320,6 +320,7 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_mmio_data_xfer, - .eng_timeout = ata_eng_timeout, - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sx4.c linux-2.6.16-rc4/drivers/scsi/sata_sx4.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_sx4.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_sx4.c 2006-01-21 17:12:01.000000000 +0000 -@@ -206,6 +206,7 @@ - .phy_reset = pdc_20621_phy_reset, - .qc_prep = pdc20621_qc_prep, - .qc_issue = pdc20621_qc_issue_prot, -+ .data_xfer = ata_mmio_data_xfer, - .eng_timeout = pdc_eng_timeout, - .irq_handler = pdc20621_interrupt, - .irq_clear = pdc20621_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_uli.c linux-2.6.16-rc4/drivers/scsi/sata_uli.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_uli.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_uli.c 2006-01-21 17:12:24.000000000 +0000 -@@ -106,6 +106,7 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, - - .eng_timeout = ata_eng_timeout, - -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_via.c linux-2.6.16-rc4/drivers/scsi/sata_via.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_via.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_via.c 2006-01-21 17:12:51.000000000 +0000 -@@ -126,6 +126,7 @@ - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, - - .eng_timeout = ata_eng_timeout, - -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/drivers/scsi/sata_vsc.c linux-2.6.16-rc4/drivers/scsi/sata_vsc.c ---- linux.vanilla-2.6.16-rc4/drivers/scsi/sata_vsc.c 2006-02-20 11:22:25.000000000 +0000 -+++ linux-2.6.16-rc4/drivers/scsi/sata_vsc.c 2006-02-20 11:28:11.000000000 +0000 -@@ -280,6 +280,7 @@ - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, -+ .data_xfer = ata_pio_data_xfer, - .eng_timeout = ata_eng_timeout, - .irq_handler = vsc_sata_interrupt, - .irq_clear = ata_bmdma_irq_clear, -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/include/linux/ata.h linux-2.6.16-rc4/include/linux/ata.h ---- linux.vanilla-2.6.16-rc4/include/linux/ata.h 2006-02-20 11:22:26.000000000 +0000 -+++ linux-2.6.16-rc4/include/linux/ata.h 2006-02-15 14:39:41.000000000 +0000 -@@ -134,6 +134,8 @@ - ATA_CMD_PIO_READ_EXT = 0x24, - ATA_CMD_PIO_WRITE = 0x30, - ATA_CMD_PIO_WRITE_EXT = 0x34, -+ ATA_CMD_READ_NATIVE_MAX = 0xF8, -+ ATA_CMD_READ_NATIVE_MAX_EXT = 0x27, - ATA_CMD_READ_MULTI = 0xC4, - ATA_CMD_READ_MULTI_EXT = 0x29, - ATA_CMD_WRITE_MULTI = 0xC5, -@@ -247,18 +249,22 @@ - }; - - #define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0) -+#define ata_id_is_cfa(id) ((id)[0] == 0x848A) - #define ata_id_is_sata(id) ((id)[93] == 0) - #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6)) - #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5)) -+#define ata_id_hpa_enabled(id) ((id)[85] & (1 << 10)) - #define ata_id_has_fua(id) ((id)[84] & (1 << 6)) - #define ata_id_has_flush(id) ((id)[83] & (1 << 12)) - #define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13)) - #define ata_id_has_lba48(id) ((id)[83] & (1 << 10)) -+#define ata_id_has_hpa(id) ((id)[82] & (1 << 10)) - #define ata_id_has_wcache(id) ((id)[82] & (1 << 5)) - #define ata_id_has_pm(id) ((id)[82] & (1 << 3)) - #define ata_id_has_lba(id) ((id)[49] & (1 << 9)) - #define ata_id_has_dma(id) ((id)[49] & (1 << 8)) - #define ata_id_removeable(id) ((id)[0] & (1 << 7)) -+#define ata_id_has_dword_io(id) ((id)[50] & (1 << 0)) - #define ata_id_u32(id,n) \ - (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) - #define ata_id_u64(id,n) \ -diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.16-rc4/include/linux/libata.h linux-2.6.16-rc4/include/linux/libata.h ---- linux.vanilla-2.6.16-rc4/include/linux/libata.h 2006-02-20 11:22:26.000000000 +0000 -+++ linux-2.6.16-rc4/include/linux/libata.h 2006-02-23 13:28:56.634774248 +0000 -@@ -41,7 +41,7 @@ - #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ - #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ - #undef ATA_NDEBUG /* define to disable quick runtime checks */ --#undef ATA_ENABLE_PATA /* define to enable PATA support in some -+#define ATA_ENABLE_PATA /* define to enable PATA support in some - * low-level drivers */ - #undef ATAPI_ENABLE_DMADIR /* enables ATAPI DMADIR bridge support */ - -@@ -101,6 +101,7 @@ - ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ - ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ - ATA_DFLAG_LBA = (1 << 3), /* device supports LBA */ -+ ATA_DFLAG_HPA = (1 << 4), /* device has an HPA */ - - ATA_DEV_UNKNOWN = 0, /* unknown device */ - ATA_DEV_ATA = 1, /* ATA device */ -@@ -133,6 +134,8 @@ - ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ - ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ - ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, -+ -+ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host_set only */ - - /* various lengths of time */ - ATA_TMOUT_EDD = 5 * HZ, /* heuristic */ -@@ -197,6 +200,7 @@ - - /* forward declarations */ - struct scsi_device; -+struct ata_host_set; - struct ata_port_operations; - struct ata_port; - struct ata_queued_cmd; -@@ -237,8 +241,10 @@ - unsigned long irq; - unsigned int irq_flags; - unsigned long host_flags; -+ unsigned long host_set_flags; - void __iomem *mmio_base; - void *private_data; -+ struct ata_host_set *host_set; /* Return not input value */ - }; - - struct ata_host_set { -@@ -250,6 +256,9 @@ - void *private_data; - const struct ata_port_operations *ops; - struct ata_port * ports[0]; -+ unsigned long host_set_flags; -+ int simplex_claimed; /* Keep seperate in case we -+ ever need to do this locked */ - }; - - struct ata_queued_cmd { -@@ -369,6 +378,7 @@ - - void (*set_piomode) (struct ata_port *, struct ata_device *); - void (*set_dmamode) (struct ata_port *, struct ata_device *); -+ unsigned int (*mode_filter) (const struct ata_port *, struct ata_device *, unsigned int, int); - - void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf); - void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); -@@ -379,12 +389,15 @@ - void (*dev_select)(struct ata_port *ap, unsigned int device); - - void (*phy_reset) (struct ata_port *ap); -+ void (*set_mode) (struct ata_port *ap); - void (*post_set_mode) (struct ata_port *ap); - - int (*check_atapi_dma) (struct ata_queued_cmd *qc); - - void (*bmdma_setup) (struct ata_queued_cmd *qc); - void (*bmdma_start) (struct ata_queued_cmd *qc); -+ -+ void (*data_xfer) (struct ata_port *, struct ata_device *, unsigned char *, unsigned int, int); - - void (*qc_prep) (struct ata_queued_cmd *qc); - int (*qc_issue) (struct ata_queued_cmd *qc); -@@ -443,8 +456,9 @@ - extern void ata_pci_remove_one (struct pci_dev *pdev); - extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state); - extern int ata_pci_device_resume(struct pci_dev *pdev); -+extern int ata_pci_clear_simplex(struct pci_dev *pdev); - #endif /* CONFIG_PCI */ --extern int ata_device_add(const struct ata_probe_ent *ent); -+extern int ata_device_add(struct ata_probe_ent *ent); - extern void ata_host_set_remove(struct ata_host_set *host_set); - extern int ata_scsi_detect(struct scsi_host_template *sht); - extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); -@@ -491,6 +505,15 @@ - extern void ata_bmdma_irq_clear(struct ata_port *ap); - extern void ata_qc_complete(struct ata_queued_cmd *qc); - extern void ata_eng_timeout(struct ata_port *ap); -+extern void ata_mmio_data_xfer(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, -+ unsigned int buflen, int write_data); -+extern void ata_pio_data_xfer(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, -+ unsigned int buflen, int write_data); -+extern void ata_mmio_data_xfer_noirq(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, -+ unsigned int buflen, int do_write); -+extern void ata_pio_data_xfer_noirq(struct ata_port *ap, struct ata_device *adev, unsigned char *buf, -+ unsigned int buflen, int do_write); -+ - extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)); -@@ -498,6 +521,8 @@ - struct block_device *bdev, - sector_t capacity, int geom[]); - extern int ata_scsi_slave_config(struct scsi_device *sdev); -+extern struct ata_device *ata_dev_pair(struct ata_port *ap, -+ struct ata_device *adev); - - /* - * Timing helpers diff --git a/packages/linux/ixp4xx-kernel_2.6.16.bb b/packages/linux/ixp4xx-kernel_2.6.16.bb index 7d48711d8b..66d1c38e42 100644 --- a/packages/linux/ixp4xx-kernel_2.6.16.bb +++ b/packages/linux/ixp4xx-kernel_2.6.16.bb @@ -3,22 +3,21 @@ # Increment PR_CONFIG for changes to the ixp4xx-kernel specific # defconfig (do *NOT* increment anything in here for changes # to other kernel configs!) -PR_CONFIG = "2" +PR_CONFIG = "1" # # Increment the number below (i.e. the digits after PR) when # making changes within this file or for changes to the patches # applied to the kernel. -PR = "r2.${PR_CONFIG}" +PR = "r3.${PR_CONFIG}" include ixp4xx-kernel.inc -# RPSRC = "http://www.rpsys.net/openzaurus/patches" - # IXP4XX_PATCHES - full list of patches to apply IXP4XX_PATCHES = "" -IXP4XX_PATCHES += "file://patch-2.6.16-rc4-ide2;patch=1" +IXP4XX_PATCHES += "file://patch-2.6.16-rc6-ide1;patch=1" IXP4XX_PATCHES += "file://leds-class.patch;patch=1" +IXP4XX_PATCHES += "file://linux-2.6.16-i2c.patch;patch=1" IXP4XX_PATCHES += "file://copypage-xscale.patch;patch=1" # IXP4XX_PATCHES += "file://06-remove-extraversion.patch;patch=1" IXP4XX_PATCHES += "file://10-ixp4xx-fix-irq.patch;patch=1" @@ -26,9 +25,8 @@ IXP4XX_PATCHES += "file://11-mtdpart-redboot-config-byteswap.patch;patch=1" IXP4XX_PATCHES += "file://15-jffs2-endian-config.patch;patch=1" IXP4XX_PATCHES += "file://951-ixp4xx-leds-cpu-activity.patch;patch=1" IXP4XX_PATCHES += "file://40-rtc-class.patch;patch=1" -IXP4XX_PATCHES += "file://45-eeprom-notifier.patch;patch=1" +IXP4XX_PATCHES += "file://45-eeprom-new-notifier.patch;patch=1" IXP4XX_PATCHES += "file://48-setup-byteswap-cmdline.patch;patch=1" -IXP4XX_PATCHES += "file://50-i2c-bus-ixp4xx-hwmon.patch;patch=1" IXP4XX_PATCHES += "file://50-hwmon-ad741x.patch;patch=1" IXP4XX_PATCHES += "file://65-loft-config.patch;patch=1" IXP4XX_PATCHES += "file://75-dsmg600.patch;patch=1" @@ -36,8 +34,8 @@ IXP4XX_PATCHES += "file://83-nas100d-memory-fixup.patch;patch=1" IXP4XX_PATCHES += "file://84-nas100d-cmdline.patch;patch=1" IXP4XX_PATCHES += "file://85-timer.patch;patch=1" IXP4XX_PATCHES += "file://91-maclist.patch;patch=1" -IXP4XX_PATCHES += "file://92-nas100d-maclist.patch;patch=1" -IXP4XX_PATCHES += "file://92-nslu2-maclist.patch;patch=1" +IXP4XX_PATCHES += "file://92-nas100d-mac.patch;patch=1" +IXP4XX_PATCHES += "file://92-nslu2-mac.patch;patch=1" IXP4XX_PATCHES += "file://94-nslu2-setup.patch;patch=1" IXP4XX_PATCHES += "file://94-loft-setup.patch;patch=1" IXP4XX_PATCHES += "file://96-pata-ixp4xx.patch;patch=1" |