diff options
| -rw-r--r-- | drivers/hwmon/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/hwmon/fschmd.c | 214 |
2 files changed, 161 insertions, 60 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9a22816b37dd..41e3f861c472 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
| @@ -343,11 +343,12 @@ config SENSORS_FSCPOS | |||
| 343 | will be called fscpos. | 343 | will be called fscpos. |
| 344 | 344 | ||
| 345 | config SENSORS_FSCHMD | 345 | config SENSORS_FSCHMD |
| 346 | tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" | 346 | tristate "Fujitsu Siemens Computers sensor chips" |
| 347 | depends on X86 && I2C | 347 | depends on X86 && I2C |
| 348 | help | 348 | help |
| 349 | If you say yes here you get support for various Fujitsu Siemens | 349 | If you say yes here you get support for the following Fujitsu |
| 350 | Computers sensor chips, including support for the integrated | 350 | Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, |
| 351 | Heimdall, Heracles and Syleus including support for the integrated | ||
| 351 | watchdog. | 352 | watchdog. |
| 352 | 353 | ||
| 353 | This is a merged driver for FSC sensor chips replacing the fscpos, | 354 | This is a merged driver for FSC sensor chips replacing the fscpos, |
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index b557f2ebd9ae..ac515bd6b1e7 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* fschmd.c | 1 | /* fschmd.c |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> | 3 | * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| 21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, | 21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, |
| 22 | * Scylla, Heracles and Heimdall chips | 22 | * Scylla, Heracles, Heimdall and Syleus chips |
| 23 | * | 23 | * |
| 24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 | 24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 |
| 25 | * (candidate) fschmd drivers: | 25 | * (candidate) fschmd drivers: |
| @@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
| 56 | module_param(nowayout, int, 0); | 56 | module_param(nowayout, int, 0); |
| 57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
| 58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
| 59 | I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | 59 | I2C_CLIENT_INSMOD_6(fscpos, fscher, fscscy, fschrc, fschmd, fscsyl); |
| 60 | 60 | ||
| 61 | /* | 61 | /* |
| 62 | * The FSCHMD registers and other defines | 62 | * The FSCHMD registers and other defines |
| @@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
| 75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 | 75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 |
| 76 | 76 | ||
| 77 | /* watchdog */ | 77 | /* watchdog */ |
| 78 | #define FSCHMD_REG_WDOG_PRESET 0x28 | 78 | static const u8 FSCHMD_REG_WDOG_CONTROL[6] = |
| 79 | #define FSCHMD_REG_WDOG_STATE 0x23 | 79 | { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28 }; |
| 80 | #define FSCHMD_REG_WDOG_CONTROL 0x21 | 80 | static const u8 FSCHMD_REG_WDOG_STATE[6] = |
| 81 | { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29 }; | ||
| 82 | static const u8 FSCHMD_REG_WDOG_PRESET[6] = | ||
| 83 | { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a }; | ||
| 81 | 84 | ||
| 82 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 | 85 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 |
| 83 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ | 86 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ |
| @@ -87,70 +90,88 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
| 87 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 | 90 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 |
| 88 | 91 | ||
| 89 | /* voltages, weird order is to keep the same order as the old drivers */ | 92 | /* voltages, weird order is to keep the same order as the old drivers */ |
| 90 | static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; | 93 | static const u8 FSCHMD_REG_VOLT[6][6] = { |
| 94 | { 0x45, 0x42, 0x48 }, /* pos */ | ||
| 95 | { 0x45, 0x42, 0x48 }, /* her */ | ||
| 96 | { 0x45, 0x42, 0x48 }, /* scy */ | ||
| 97 | { 0x45, 0x42, 0x48 }, /* hrc */ | ||
| 98 | { 0x45, 0x42, 0x48 }, /* hmd */ | ||
| 99 | { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ | ||
| 100 | }; | ||
| 101 | |||
| 102 | static const int FSCHMD_NO_VOLT_SENSORS[6] = { 3, 3, 3, 3, 3, 6 }; | ||
| 91 | 103 | ||
| 92 | /* minimum pwm at which the fan is driven (pwm can by increased depending on | 104 | /* minimum pwm at which the fan is driven (pwm can by increased depending on |
| 93 | the temp. Notice that for the scy some fans share there minimum speed. | 105 | the temp. Notice that for the scy some fans share there minimum speed. |
| 94 | Also notice that with the scy the sensor order is different than with the | 106 | Also notice that with the scy the sensor order is different than with the |
| 95 | other chips, this order was in the 2.4 driver and kept for consistency. */ | 107 | other chips, this order was in the 2.4 driver and kept for consistency. */ |
| 96 | static const u8 FSCHMD_REG_FAN_MIN[5][6] = { | 108 | static const u8 FSCHMD_REG_FAN_MIN[6][7] = { |
| 97 | { 0x55, 0x65 }, /* pos */ | 109 | { 0x55, 0x65 }, /* pos */ |
| 98 | { 0x55, 0x65, 0xb5 }, /* her */ | 110 | { 0x55, 0x65, 0xb5 }, /* her */ |
| 99 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ | 111 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ |
| 100 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ | 112 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ |
| 101 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ | 113 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ |
| 114 | { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ | ||
| 102 | }; | 115 | }; |
| 103 | 116 | ||
| 104 | /* actual fan speed */ | 117 | /* actual fan speed */ |
| 105 | static const u8 FSCHMD_REG_FAN_ACT[5][6] = { | 118 | static const u8 FSCHMD_REG_FAN_ACT[6][7] = { |
| 106 | { 0x0e, 0x6b, 0xab }, /* pos */ | 119 | { 0x0e, 0x6b, 0xab }, /* pos */ |
| 107 | { 0x0e, 0x6b, 0xbb }, /* her */ | 120 | { 0x0e, 0x6b, 0xbb }, /* her */ |
| 108 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ | 121 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ |
| 109 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ | 122 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ |
| 110 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ | 123 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ |
| 124 | { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ | ||
| 111 | }; | 125 | }; |
| 112 | 126 | ||
| 113 | /* fan status registers */ | 127 | /* fan status registers */ |
| 114 | static const u8 FSCHMD_REG_FAN_STATE[5][6] = { | 128 | static const u8 FSCHMD_REG_FAN_STATE[6][7] = { |
| 115 | { 0x0d, 0x62, 0xa2 }, /* pos */ | 129 | { 0x0d, 0x62, 0xa2 }, /* pos */ |
| 116 | { 0x0d, 0x62, 0xb2 }, /* her */ | 130 | { 0x0d, 0x62, 0xb2 }, /* her */ |
| 117 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ | 131 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ |
| 118 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ | 132 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ |
| 119 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ | 133 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ |
| 134 | { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ | ||
| 120 | }; | 135 | }; |
| 121 | 136 | ||
| 122 | /* fan ripple / divider registers */ | 137 | /* fan ripple / divider registers */ |
| 123 | static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { | 138 | static const u8 FSCHMD_REG_FAN_RIPPLE[6][7] = { |
| 124 | { 0x0f, 0x6f, 0xaf }, /* pos */ | 139 | { 0x0f, 0x6f, 0xaf }, /* pos */ |
| 125 | { 0x0f, 0x6f, 0xbf }, /* her */ | 140 | { 0x0f, 0x6f, 0xbf }, /* her */ |
| 126 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ | 141 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ |
| 127 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ | 142 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ |
| 128 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ | 143 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ |
| 144 | { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ | ||
| 129 | }; | 145 | }; |
| 130 | 146 | ||
| 131 | static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; | 147 | static const int FSCHMD_NO_FAN_SENSORS[6] = { 3, 3, 6, 4, 5, 7 }; |
| 132 | 148 | ||
| 133 | /* Fan status register bitmasks */ | 149 | /* Fan status register bitmasks */ |
| 134 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ | 150 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ |
| 135 | #define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */ | 151 | #define FSCHMD_FAN_NOT_PRESENT 0x08 |
| 152 | #define FSCHMD_FAN_DISABLED 0x80 | ||
| 136 | 153 | ||
| 137 | 154 | ||
| 138 | /* actual temperature registers */ | 155 | /* actual temperature registers */ |
| 139 | static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { | 156 | static const u8 FSCHMD_REG_TEMP_ACT[6][11] = { |
| 140 | { 0x64, 0x32, 0x35 }, /* pos */ | 157 | { 0x64, 0x32, 0x35 }, /* pos */ |
| 141 | { 0x64, 0x32, 0x35 }, /* her */ | 158 | { 0x64, 0x32, 0x35 }, /* her */ |
| 142 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ | 159 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ |
| 143 | { 0x64, 0x32, 0x35 }, /* hrc */ | 160 | { 0x64, 0x32, 0x35 }, /* hrc */ |
| 144 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ | 161 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ |
| 162 | { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ | ||
| 163 | 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, | ||
| 145 | }; | 164 | }; |
| 146 | 165 | ||
| 147 | /* temperature state registers */ | 166 | /* temperature state registers */ |
| 148 | static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | 167 | static const u8 FSCHMD_REG_TEMP_STATE[6][11] = { |
| 149 | { 0x71, 0x81, 0x91 }, /* pos */ | 168 | { 0x71, 0x81, 0x91 }, /* pos */ |
| 150 | { 0x71, 0x81, 0x91 }, /* her */ | 169 | { 0x71, 0x81, 0x91 }, /* her */ |
| 151 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ | 170 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ |
| 152 | { 0x71, 0x81, 0x91 }, /* hrc */ | 171 | { 0x71, 0x81, 0x91 }, /* hrc */ |
| 153 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ | 172 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ |
| 173 | { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ | ||
| 174 | 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, | ||
| 154 | }; | 175 | }; |
| 155 | 176 | ||
| 156 | /* temperature high limit registers, FSC does not document these. Proven to be | 177 | /* temperature high limit registers, FSC does not document these. Proven to be |
| @@ -158,24 +179,30 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | |||
| 158 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers | 179 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers |
| 159 | at these addresses, but doesn't want to confirm they are the same as with | 180 | at these addresses, but doesn't want to confirm they are the same as with |
| 160 | the fscher?? */ | 181 | the fscher?? */ |
| 161 | static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { | 182 | static const u8 FSCHMD_REG_TEMP_LIMIT[6][11] = { |
| 162 | { 0, 0, 0 }, /* pos */ | 183 | { 0, 0, 0 }, /* pos */ |
| 163 | { 0x76, 0x86, 0x96 }, /* her */ | 184 | { 0x76, 0x86, 0x96 }, /* her */ |
| 164 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ | 185 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ |
| 165 | { 0x76, 0x86, 0x96 }, /* hrc */ | 186 | { 0x76, 0x86, 0x96 }, /* hrc */ |
| 166 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ | 187 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ |
| 188 | { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ | ||
| 189 | 0xba, 0xca, 0xda, 0xea, 0xfa }, | ||
| 167 | }; | 190 | }; |
| 168 | 191 | ||
| 169 | /* These were found through experimenting with an fscher, currently they are | 192 | /* These were found through experimenting with an fscher, currently they are |
| 170 | not used, but we keep them around for future reference. | 193 | not used, but we keep them around for future reference. |
| 194 | On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), | ||
| 195 | AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence | ||
| 196 | the fan speed. | ||
| 171 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; | 197 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; |
| 172 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ | 198 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ |
| 173 | 199 | ||
| 174 | static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; | 200 | static const int FSCHMD_NO_TEMP_SENSORS[6] = { 3, 3, 4, 3, 5, 11 }; |
| 175 | 201 | ||
| 176 | /* temp status register bitmasks */ | 202 | /* temp status register bitmasks */ |
| 177 | #define FSCHMD_TEMP_WORKING 0x01 | 203 | #define FSCHMD_TEMP_WORKING 0x01 |
| 178 | #define FSCHMD_TEMP_ALERT 0x02 | 204 | #define FSCHMD_TEMP_ALERT 0x02 |
| 205 | #define FSCHMD_TEMP_DISABLED 0x80 | ||
| 179 | /* there only really is an alarm if the sensor is working and alert == 1 */ | 206 | /* there only really is an alarm if the sensor is working and alert == 1 */ |
| 180 | #define FSCHMD_TEMP_ALARM_MASK \ | 207 | #define FSCHMD_TEMP_ALARM_MASK \ |
| 181 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) | 208 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) |
| @@ -201,6 +228,7 @@ static const struct i2c_device_id fschmd_id[] = { | |||
| 201 | { "fscscy", fscscy }, | 228 | { "fscscy", fscscy }, |
| 202 | { "fschrc", fschrc }, | 229 | { "fschrc", fschrc }, |
| 203 | { "fschmd", fschmd }, | 230 | { "fschmd", fschmd }, |
| 231 | { "fscsyl", fscsyl }, | ||
| 204 | { } | 232 | { } |
| 205 | }; | 233 | }; |
| 206 | MODULE_DEVICE_TABLE(i2c, fschmd_id); | 234 | MODULE_DEVICE_TABLE(i2c, fschmd_id); |
| @@ -242,14 +270,14 @@ struct fschmd_data { | |||
| 242 | u8 watchdog_control; /* watchdog control register */ | 270 | u8 watchdog_control; /* watchdog control register */ |
| 243 | u8 watchdog_state; /* watchdog status register */ | 271 | u8 watchdog_state; /* watchdog status register */ |
| 244 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ | 272 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ |
| 245 | u8 volt[3]; /* 12, 5, battery voltage */ | 273 | u8 volt[6]; /* voltage */ |
| 246 | u8 temp_act[5]; /* temperature */ | 274 | u8 temp_act[11]; /* temperature */ |
| 247 | u8 temp_status[5]; /* status of sensor */ | 275 | u8 temp_status[11]; /* status of sensor */ |
| 248 | u8 temp_max[5]; /* high temp limit, notice: undocumented! */ | 276 | u8 temp_max[11]; /* high temp limit, notice: undocumented! */ |
| 249 | u8 fan_act[6]; /* fans revolutions per second */ | 277 | u8 fan_act[7]; /* fans revolutions per second */ |
| 250 | u8 fan_status[6]; /* fan status */ | 278 | u8 fan_status[7]; /* fan status */ |
| 251 | u8 fan_min[6]; /* fan min value for rps */ | 279 | u8 fan_min[7]; /* fan min value for rps */ |
| 252 | u8 fan_ripple[6]; /* divider for rps */ | 280 | u8 fan_ripple[7]; /* divider for rps */ |
| 253 | }; | 281 | }; |
| 254 | 282 | ||
| 255 | /* Global variables to hold information read from special DMI tables, which are | 283 | /* Global variables to hold information read from special DMI tables, which are |
| @@ -257,8 +285,8 @@ struct fschmd_data { | |||
| 257 | protect these with a lock as they are only modified from our attach function | 285 | protect these with a lock as they are only modified from our attach function |
| 258 | which always gets called with the i2c-core lock held and never accessed | 286 | which always gets called with the i2c-core lock held and never accessed |
| 259 | before the attach function is done with them. */ | 287 | before the attach function is done with them. */ |
| 260 | static int dmi_mult[3] = { 490, 200, 100 }; | 288 | static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; |
| 261 | static int dmi_offset[3] = { 0, 0, 0 }; | 289 | static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; |
| 262 | static int dmi_vref = -1; | 290 | static int dmi_vref = -1; |
| 263 | 291 | ||
| 264 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that | 292 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that |
| @@ -450,10 +478,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev, | |||
| 450 | struct device_attribute *devattr, char *buf) | 478 | struct device_attribute *devattr, char *buf) |
| 451 | { | 479 | { |
| 452 | int index = to_sensor_dev_attr(devattr)->index; | 480 | int index = to_sensor_dev_attr(devattr)->index; |
| 453 | int val = fschmd_update_device(dev)->fan_min[index]; | 481 | struct fschmd_data *data = fschmd_update_device(dev); |
| 482 | int val = data->fan_min[index]; | ||
| 454 | 483 | ||
| 455 | /* 0 = allow turning off, 1-255 = 50-100% */ | 484 | /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
| 456 | if (val) | 485 | if (val || data->kind == fscsyl - 1) |
| 457 | val = val / 2 + 128; | 486 | val = val / 2 + 128; |
| 458 | 487 | ||
| 459 | return sprintf(buf, "%d\n", val); | 488 | return sprintf(buf, "%d\n", val); |
| @@ -466,8 +495,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, | |||
| 466 | struct fschmd_data *data = dev_get_drvdata(dev); | 495 | struct fschmd_data *data = dev_get_drvdata(dev); |
| 467 | unsigned long v = simple_strtoul(buf, NULL, 10); | 496 | unsigned long v = simple_strtoul(buf, NULL, 10); |
| 468 | 497 | ||
| 469 | /* register: 0 = allow turning off, 1-255 = 50-100% */ | 498 | /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
| 470 | if (v) { | 499 | if (v || data->kind == fscsyl - 1) { |
| 471 | v = SENSORS_LIMIT(v, 128, 255); | 500 | v = SENSORS_LIMIT(v, 128, 255); |
| 472 | v = (v - 128) * 2 + 1; | 501 | v = (v - 128) * 2 + 1; |
| 473 | } | 502 | } |
| @@ -522,11 +551,15 @@ static ssize_t store_alert_led(struct device *dev, | |||
| 522 | return count; | 551 | return count; |
| 523 | } | 552 | } |
| 524 | 553 | ||
| 554 | static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); | ||
| 555 | |||
| 525 | static struct sensor_device_attribute fschmd_attr[] = { | 556 | static struct sensor_device_attribute fschmd_attr[] = { |
| 526 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), | 557 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), |
| 527 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), | 558 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), |
| 528 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), | 559 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), |
| 529 | SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), | 560 | SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3), |
| 561 | SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4), | ||
| 562 | SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5), | ||
| 530 | }; | 563 | }; |
| 531 | 564 | ||
| 532 | static struct sensor_device_attribute fschmd_temp_attr[] = { | 565 | static struct sensor_device_attribute fschmd_temp_attr[] = { |
| @@ -550,6 +583,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = { | |||
| 550 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), | 583 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), |
| 551 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), | 584 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), |
| 552 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), | 585 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), |
| 586 | SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5), | ||
| 587 | SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5), | ||
| 588 | SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5), | ||
| 589 | SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5), | ||
| 590 | SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6), | ||
| 591 | SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6), | ||
| 592 | SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6), | ||
| 593 | SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6), | ||
| 594 | SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7), | ||
| 595 | SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7), | ||
| 596 | SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7), | ||
| 597 | SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7), | ||
| 598 | SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8), | ||
| 599 | SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8), | ||
| 600 | SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8), | ||
| 601 | SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8), | ||
| 602 | SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9), | ||
| 603 | SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9), | ||
| 604 | SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9), | ||
| 605 | SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9), | ||
| 606 | SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10), | ||
| 607 | SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10), | ||
| 608 | SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10), | ||
| 609 | SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10), | ||
| 553 | }; | 610 | }; |
| 554 | 611 | ||
| 555 | static struct sensor_device_attribute fschmd_fan_attr[] = { | 612 | static struct sensor_device_attribute fschmd_fan_attr[] = { |
| @@ -589,6 +646,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { | |||
| 589 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), | 646 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), |
| 590 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | 647 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, |
| 591 | store_pwm_auto_point1_pwm, 5), | 648 | store_pwm_auto_point1_pwm, 5), |
| 649 | SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6), | ||
| 650 | SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6), | ||
| 651 | SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6), | ||
| 652 | SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6), | ||
| 653 | SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | ||
| 654 | store_pwm_auto_point1_pwm, 6), | ||
| 592 | }; | 655 | }; |
| 593 | 656 | ||
| 594 | 657 | ||
| @@ -624,10 +687,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout) | |||
| 624 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); | 687 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); |
| 625 | 688 | ||
| 626 | /* Write new timeout value */ | 689 | /* Write new timeout value */ |
| 627 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET, | 690 | i2c_smbus_write_byte_data(data->client, |
| 628 | data->watchdog_preset); | 691 | FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); |
| 629 | /* Write new control register, do not trigger! */ | 692 | /* Write new control register, do not trigger! */ |
| 630 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 693 | i2c_smbus_write_byte_data(data->client, |
| 694 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
| 631 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); | 695 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); |
| 632 | 696 | ||
| 633 | ret = data->watchdog_preset * resolution; | 697 | ret = data->watchdog_preset * resolution; |
| @@ -662,8 +726,9 @@ static int watchdog_trigger(struct fschmd_data *data) | |||
| 662 | } | 726 | } |
| 663 | 727 | ||
| 664 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; | 728 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; |
| 665 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 729 | i2c_smbus_write_byte_data(data->client, |
| 666 | data->watchdog_control); | 730 | FSCHMD_REG_WDOG_CONTROL[data->kind], |
| 731 | data->watchdog_control); | ||
| 667 | leave: | 732 | leave: |
| 668 | mutex_unlock(&data->watchdog_lock); | 733 | mutex_unlock(&data->watchdog_lock); |
| 669 | return ret; | 734 | return ret; |
| @@ -682,7 +747,8 @@ static int watchdog_stop(struct fschmd_data *data) | |||
| 682 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; | 747 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; |
| 683 | /* Don't store the stop flag in our watchdog control register copy, as | 748 | /* Don't store the stop flag in our watchdog control register copy, as |
| 684 | its a write only bit (read always returns 0) */ | 749 | its a write only bit (read always returns 0) */ |
| 685 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 750 | i2c_smbus_write_byte_data(data->client, |
| 751 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
| 686 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); | 752 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); |
| 687 | leave: | 753 | leave: |
| 688 | mutex_unlock(&data->watchdog_lock); | 754 | mutex_unlock(&data->watchdog_lock); |
| @@ -912,6 +978,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) | |||
| 912 | dmi_mult[i] = mult[i] * 10; | 978 | dmi_mult[i] = mult[i] * 10; |
| 913 | dmi_offset[i] = offset[i] * 10; | 979 | dmi_offset[i] = offset[i] * 10; |
| 914 | } | 980 | } |
| 981 | /* According to the docs there should be separate dmi entries | ||
| 982 | for the mult's and offsets of in3-5 of the syl, but on | ||
| 983 | my test machine these are not present */ | ||
| 984 | dmi_mult[3] = dmi_mult[2]; | ||
| 985 | dmi_mult[4] = dmi_mult[1]; | ||
| 986 | dmi_mult[5] = dmi_mult[2]; | ||
| 987 | dmi_offset[3] = dmi_offset[2]; | ||
| 988 | dmi_offset[4] = dmi_offset[1]; | ||
| 989 | dmi_offset[5] = dmi_offset[2]; | ||
| 915 | dmi_vref = vref; | 990 | dmi_vref = vref; |
| 916 | } | 991 | } |
| 917 | } | 992 | } |
| @@ -920,8 +995,6 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
| 920 | struct i2c_board_info *info) | 995 | struct i2c_board_info *info) |
| 921 | { | 996 | { |
| 922 | struct i2c_adapter *adapter = client->adapter; | 997 | struct i2c_adapter *adapter = client->adapter; |
| 923 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", | ||
| 924 | "fschrc", "fschmd" }; | ||
| 925 | 998 | ||
| 926 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 999 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
| 927 | return -ENODEV; | 1000 | return -ENODEV; |
| @@ -948,11 +1021,13 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
| 948 | kind = fschrc; | 1021 | kind = fschrc; |
| 949 | else if (!strcmp(id, "HMD")) | 1022 | else if (!strcmp(id, "HMD")) |
| 950 | kind = fschmd; | 1023 | kind = fschmd; |
| 1024 | else if (!strcmp(id, "SYL")) | ||
| 1025 | kind = fscsyl; | ||
| 951 | else | 1026 | else |
| 952 | return -ENODEV; | 1027 | return -ENODEV; |
| 953 | } | 1028 | } |
| 954 | 1029 | ||
| 955 | strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); | 1030 | strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE); |
| 956 | 1031 | ||
| 957 | return 0; | 1032 | return 0; |
| 958 | } | 1033 | } |
| @@ -961,8 +1036,8 @@ static int fschmd_probe(struct i2c_client *client, | |||
| 961 | const struct i2c_device_id *id) | 1036 | const struct i2c_device_id *id) |
| 962 | { | 1037 | { |
| 963 | struct fschmd_data *data; | 1038 | struct fschmd_data *data; |
| 964 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | 1039 | const char * const names[6] = { "Poseidon", "Hermes", "Scylla", |
| 965 | "Heracles", "Heimdall" }; | 1040 | "Heracles", "Heimdall", "Syleus" }; |
| 966 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; | 1041 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; |
| 967 | int i, err; | 1042 | int i, err; |
| 968 | enum chips kind = id->driver_data; | 1043 | enum chips kind = id->driver_data; |
| @@ -1000,21 +1075,25 @@ static int fschmd_probe(struct i2c_client *client, | |||
| 1000 | } | 1075 | } |
| 1001 | } | 1076 | } |
| 1002 | 1077 | ||
| 1078 | /* i2c kind goes from 1-6, we want from 0-5 to address arrays */ | ||
| 1079 | data->kind = kind - 1; | ||
| 1080 | |||
| 1003 | /* Read in some never changing registers */ | 1081 | /* Read in some never changing registers */ |
| 1004 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); | 1082 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); |
| 1005 | data->global_control = i2c_smbus_read_byte_data(client, | 1083 | data->global_control = i2c_smbus_read_byte_data(client, |
| 1006 | FSCHMD_REG_CONTROL); | 1084 | FSCHMD_REG_CONTROL); |
| 1007 | data->watchdog_control = i2c_smbus_read_byte_data(client, | 1085 | data->watchdog_control = i2c_smbus_read_byte_data(client, |
| 1008 | FSCHMD_REG_WDOG_CONTROL); | 1086 | FSCHMD_REG_WDOG_CONTROL[data->kind]); |
| 1009 | data->watchdog_state = i2c_smbus_read_byte_data(client, | 1087 | data->watchdog_state = i2c_smbus_read_byte_data(client, |
| 1010 | FSCHMD_REG_WDOG_STATE); | 1088 | FSCHMD_REG_WDOG_STATE[data->kind]); |
| 1011 | data->watchdog_preset = i2c_smbus_read_byte_data(client, | 1089 | data->watchdog_preset = i2c_smbus_read_byte_data(client, |
| 1012 | FSCHMD_REG_WDOG_PRESET); | 1090 | FSCHMD_REG_WDOG_PRESET[data->kind]); |
| 1013 | 1091 | ||
| 1014 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ | 1092 | err = device_create_file(&client->dev, &dev_attr_alert_led); |
| 1015 | data->kind = kind - 1; | 1093 | if (err) |
| 1094 | goto exit_detach; | ||
| 1016 | 1095 | ||
| 1017 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { | 1096 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { |
| 1018 | err = device_create_file(&client->dev, | 1097 | err = device_create_file(&client->dev, |
| 1019 | &fschmd_attr[i].dev_attr); | 1098 | &fschmd_attr[i].dev_attr); |
| 1020 | if (err) | 1099 | if (err) |
| @@ -1027,6 +1106,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
| 1027 | show_temp_max) | 1106 | show_temp_max) |
| 1028 | continue; | 1107 | continue; |
| 1029 | 1108 | ||
| 1109 | if (kind == fscsyl) { | ||
| 1110 | if (i % 4 == 0) | ||
| 1111 | data->temp_status[i / 4] = | ||
| 1112 | i2c_smbus_read_byte_data(client, | ||
| 1113 | FSCHMD_REG_TEMP_STATE | ||
| 1114 | [data->kind][i / 4]); | ||
| 1115 | if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED) | ||
| 1116 | continue; | ||
| 1117 | } | ||
| 1118 | |||
| 1030 | err = device_create_file(&client->dev, | 1119 | err = device_create_file(&client->dev, |
| 1031 | &fschmd_temp_attr[i].dev_attr); | 1120 | &fschmd_temp_attr[i].dev_attr); |
| 1032 | if (err) | 1121 | if (err) |
| @@ -1040,6 +1129,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
| 1040 | "pwm3_auto_point1_pwm")) | 1129 | "pwm3_auto_point1_pwm")) |
| 1041 | continue; | 1130 | continue; |
| 1042 | 1131 | ||
| 1132 | if (kind == fscsyl) { | ||
| 1133 | if (i % 5 == 0) | ||
| 1134 | data->fan_status[i / 5] = | ||
| 1135 | i2c_smbus_read_byte_data(client, | ||
| 1136 | FSCHMD_REG_FAN_STATE | ||
| 1137 | [data->kind][i / 5]); | ||
| 1138 | if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED) | ||
| 1139 | continue; | ||
| 1140 | } | ||
| 1141 | |||
| 1043 | err = device_create_file(&client->dev, | 1142 | err = device_create_file(&client->dev, |
| 1044 | &fschmd_fan_attr[i].dev_attr); | 1143 | &fschmd_fan_attr[i].dev_attr); |
| 1045 | if (err) | 1144 | if (err) |
| @@ -1126,7 +1225,8 @@ static int fschmd_remove(struct i2c_client *client) | |||
| 1126 | if (data->hwmon_dev) | 1225 | if (data->hwmon_dev) |
| 1127 | hwmon_device_unregister(data->hwmon_dev); | 1226 | hwmon_device_unregister(data->hwmon_dev); |
| 1128 | 1227 | ||
| 1129 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) | 1228 | device_remove_file(&client->dev, &dev_attr_alert_led); |
| 1229 | for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++) | ||
| 1130 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); | 1230 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); |
| 1131 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) | 1231 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) |
| 1132 | device_remove_file(&client->dev, | 1232 | device_remove_file(&client->dev, |
| @@ -1171,7 +1271,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
| 1171 | data->temp_act[i] < data->temp_max[i]) | 1271 | data->temp_act[i] < data->temp_max[i]) |
| 1172 | i2c_smbus_write_byte_data(client, | 1272 | i2c_smbus_write_byte_data(client, |
| 1173 | FSCHMD_REG_TEMP_STATE[data->kind][i], | 1273 | FSCHMD_REG_TEMP_STATE[data->kind][i], |
| 1174 | FSCHMD_TEMP_ALERT); | 1274 | data->temp_status[i]); |
| 1175 | } | 1275 | } |
| 1176 | 1276 | ||
| 1177 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { | 1277 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { |
| @@ -1193,12 +1293,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
| 1193 | data->fan_act[i]) | 1293 | data->fan_act[i]) |
| 1194 | i2c_smbus_write_byte_data(client, | 1294 | i2c_smbus_write_byte_data(client, |
| 1195 | FSCHMD_REG_FAN_STATE[data->kind][i], | 1295 | FSCHMD_REG_FAN_STATE[data->kind][i], |
| 1196 | FSCHMD_FAN_ALARM); | 1296 | data->fan_status[i]); |
| 1197 | } | 1297 | } |
| 1198 | 1298 | ||
| 1199 | for (i = 0; i < 3; i++) | 1299 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) |
| 1200 | data->volt[i] = i2c_smbus_read_byte_data(client, | 1300 | data->volt[i] = i2c_smbus_read_byte_data(client, |
| 1201 | FSCHMD_REG_VOLT[i]); | 1301 | FSCHMD_REG_VOLT[data->kind][i]); |
| 1202 | 1302 | ||
| 1203 | data->last_updated = jiffies; | 1303 | data->last_updated = jiffies; |
| 1204 | data->valid = 1; | 1304 | data->valid = 1; |
| @@ -1220,8 +1320,8 @@ static void __exit fschmd_exit(void) | |||
| 1220 | } | 1320 | } |
| 1221 | 1321 | ||
| 1222 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | 1322 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
| 1223 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " | 1323 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall and " |
| 1224 | "Heimdall driver"); | 1324 | "Syleus driver"); |
| 1225 | MODULE_LICENSE("GPL"); | 1325 | MODULE_LICENSE("GPL"); |
| 1226 | 1326 | ||
| 1227 | module_init(fschmd_init); | 1327 | module_init(fschmd_init); |
