Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 17431928194b36a0f88082df875e2e036da7fddf 672 lines 18 kB view raw
1/* 2 * acerhdf - A driver which monitors the temperature 3 * of the aspire one netbook, turns on/off the fan 4 * as soon as the upper/lower threshold is reached. 5 * 6 * (C) 2009 - Peter Feuerer peter (a) piie.net 7 * http://piie.net 8 * 2009 Borislav Petkov <petkovbb@gmail.com> 9 * 10 * Inspired by and many thanks to: 11 * o acerfand - Rachel Greenham 12 * o acer_ec.pl - Michael Kurz michi.kurz (at) googlemail.com 13 * - Petr Tomasek tomasek (#) etf,cuni,cz 14 * - Carlos Corbacho cathectic (at) gmail.com 15 * o lkml - Matthew Garrett 16 * - Borislav Petkov 17 * - Andreas Mohr 18 * 19 * This program is free software; you can redistribute it and/or modify 20 * it under the terms of the GNU General Public License as published by 21 * the Free Software Foundation; either version 2 of the License, or 22 * (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program; if not, write to the Free Software 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32 */ 33 34#define pr_fmt(fmt) "acerhdf: " fmt 35 36#include <linux/kernel.h> 37#include <linux/module.h> 38#include <linux/fs.h> 39#include <linux/dmi.h> 40#include <acpi/acpi_drivers.h> 41#include <linux/sched.h> 42#include <linux/thermal.h> 43#include <linux/platform_device.h> 44 45/* 46 * The driver is started with "kernel mode off" by default. That means, the BIOS 47 * is still in control of the fan. In this mode the driver allows to read the 48 * temperature of the cpu and a userspace tool may take over control of the fan. 49 * If the driver is switched to "kernel mode" (e.g. via module parameter) the 50 * driver is in full control of the fan. If you want the module to be started in 51 * kernel mode by default, define the following: 52 */ 53#undef START_IN_KERNEL_MODE 54 55#define DRV_VER "0.5.22" 56 57/* 58 * According to the Atom N270 datasheet, 59 * (http://download.intel.com/design/processor/datashts/320032.pdf) the 60 * CPU's optimal operating limits denoted in junction temperature as 61 * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So, 62 * assume 89°C is critical temperature. 63 */ 64#define ACERHDF_TEMP_CRIT 89000 65#define ACERHDF_FAN_OFF 0 66#define ACERHDF_FAN_AUTO 1 67 68/* 69 * No matter what value the user puts into the fanon variable, turn on the fan 70 * at 80 degree Celsius to prevent hardware damage 71 */ 72#define ACERHDF_MAX_FANON 80000 73 74/* 75 * Maximum interval between two temperature checks is 15 seconds, as the die 76 * can get hot really fast under heavy load (plus we shouldn't forget about 77 * possible impact of _external_ aggressive sources such as heaters, sun etc.) 78 */ 79#define ACERHDF_MAX_INTERVAL 15 80 81#ifdef START_IN_KERNEL_MODE 82static int kernelmode = 1; 83#else 84static int kernelmode; 85#endif 86 87static unsigned int interval = 10; 88static unsigned int fanon = 63000; 89static unsigned int fanoff = 58000; 90static unsigned int verbose; 91static unsigned int fanstate = ACERHDF_FAN_AUTO; 92static char force_bios[16]; 93static char force_product[16]; 94static unsigned int prev_interval; 95struct thermal_zone_device *thz_dev; 96struct thermal_cooling_device *cl_dev; 97struct platform_device *acerhdf_dev; 98 99module_param(kernelmode, uint, 0); 100MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off"); 101module_param(interval, uint, 0600); 102MODULE_PARM_DESC(interval, "Polling interval of temperature check"); 103module_param(fanon, uint, 0600); 104MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature"); 105module_param(fanoff, uint, 0600); 106MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature"); 107module_param(verbose, uint, 0600); 108MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); 109module_param_string(force_bios, force_bios, 16, 0); 110MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); 111module_param_string(force_product, force_product, 16, 0); 112MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); 113 114/* 115 * cmd_off: to switch the fan completely off 116 * chk_off: to check if the fan is off 117 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then 118 * the fan speed depending on the temperature 119 */ 120struct fancmd { 121 u8 cmd_off; 122 u8 chk_off; 123 u8 cmd_auto; 124}; 125 126/* BIOS settings */ 127struct bios_settings_t { 128 const char *vendor; 129 const char *product; 130 const char *version; 131 unsigned char fanreg; 132 unsigned char tempreg; 133 struct fancmd cmd; 134}; 135 136/* Register addresses and values for different BIOS versions */ 137static const struct bios_settings_t bios_tbl[] = { 138 /* AOA110 */ 139 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, 140 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, 141 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 142 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 143 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 144 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 145 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} }, 146 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} }, 147 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} }, 148 /* AOA150 */ 149 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} }, 150 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} }, 151 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} }, 152 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} }, 153 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} }, 154 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} }, 155 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} }, 156 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, 157 /* Acer 1410 */ 158 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 159 {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 160 /* Acer 1810xx */ 161 {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 162 {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 163 {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 164 {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 165 /* Gateway */ 166 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, 167 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, 168 {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 169 {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 170 {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 171 /* Packard Bell */ 172 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, 173 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 174 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, 175 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 176 {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 177 {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 178 /* pewpew-terminator */ 179 {"", "", "", 0, 0, {0, 0, 0} } 180}; 181 182static const struct bios_settings_t *bios_cfg __read_mostly; 183 184static int acerhdf_get_temp(int *temp) 185{ 186 u8 read_temp; 187 188 if (ec_read(bios_cfg->tempreg, &read_temp)) 189 return -EINVAL; 190 191 *temp = read_temp * 1000; 192 193 return 0; 194} 195 196static int acerhdf_get_fanstate(int *state) 197{ 198 u8 fan; 199 200 if (ec_read(bios_cfg->fanreg, &fan)) 201 return -EINVAL; 202 203 if (fan != bios_cfg->cmd.chk_off) 204 *state = ACERHDF_FAN_AUTO; 205 else 206 *state = ACERHDF_FAN_OFF; 207 208 return 0; 209} 210 211static void acerhdf_change_fanstate(int state) 212{ 213 unsigned char cmd; 214 215 if (verbose) 216 pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ? 217 "OFF" : "ON"); 218 219 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) { 220 pr_err("invalid fan state %d requested, setting to auto!\n", 221 state); 222 state = ACERHDF_FAN_AUTO; 223 } 224 225 cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off 226 : bios_cfg->cmd.cmd_auto; 227 fanstate = state; 228 229 ec_write(bios_cfg->fanreg, cmd); 230} 231 232static void acerhdf_check_param(struct thermal_zone_device *thermal) 233{ 234 if (fanon > ACERHDF_MAX_FANON) { 235 pr_err("fanon temperature too high, set to %d\n", 236 ACERHDF_MAX_FANON); 237 fanon = ACERHDF_MAX_FANON; 238 } 239 240 if (kernelmode && prev_interval != interval) { 241 if (interval > ACERHDF_MAX_INTERVAL) { 242 pr_err("interval too high, set to %d\n", 243 ACERHDF_MAX_INTERVAL); 244 interval = ACERHDF_MAX_INTERVAL; 245 } 246 if (verbose) 247 pr_notice("interval changed to: %d\n", 248 interval); 249 thermal->polling_delay = interval*1000; 250 prev_interval = interval; 251 } 252} 253 254/* 255 * This is the thermal zone callback which does the delayed polling of the fan 256 * state. We do check /sysfs-originating settings here in acerhdf_check_param() 257 * as late as the polling interval is since we can't do that in the respective 258 * accessors of the module parameters. 259 */ 260static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, 261 unsigned long *t) 262{ 263 int temp, err = 0; 264 265 acerhdf_check_param(thermal); 266 267 err = acerhdf_get_temp(&temp); 268 if (err) 269 return err; 270 271 if (verbose) 272 pr_notice("temp %d\n", temp); 273 274 *t = temp; 275 return 0; 276} 277 278static int acerhdf_bind(struct thermal_zone_device *thermal, 279 struct thermal_cooling_device *cdev) 280{ 281 /* if the cooling device is the one from acerhdf bind it */ 282 if (cdev != cl_dev) 283 return 0; 284 285 if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) { 286 pr_err("error binding cooling dev\n"); 287 return -EINVAL; 288 } 289 return 0; 290} 291 292static int acerhdf_unbind(struct thermal_zone_device *thermal, 293 struct thermal_cooling_device *cdev) 294{ 295 if (cdev != cl_dev) 296 return 0; 297 298 if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) { 299 pr_err("error unbinding cooling dev\n"); 300 return -EINVAL; 301 } 302 return 0; 303} 304 305static inline void acerhdf_revert_to_bios_mode(void) 306{ 307 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 308 kernelmode = 0; 309 if (thz_dev) 310 thz_dev->polling_delay = 0; 311 pr_notice("kernel mode fan control OFF\n"); 312} 313static inline void acerhdf_enable_kernelmode(void) 314{ 315 kernelmode = 1; 316 317 thz_dev->polling_delay = interval*1000; 318 thermal_zone_device_update(thz_dev); 319 pr_notice("kernel mode fan control ON\n"); 320} 321 322static int acerhdf_get_mode(struct thermal_zone_device *thermal, 323 enum thermal_device_mode *mode) 324{ 325 if (verbose) 326 pr_notice("kernel mode fan control %d\n", kernelmode); 327 328 *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED 329 : THERMAL_DEVICE_DISABLED; 330 331 return 0; 332} 333 334/* 335 * set operation mode; 336 * enabled: the thermal layer of the kernel takes care about 337 * the temperature and the fan. 338 * disabled: the BIOS takes control of the fan. 339 */ 340static int acerhdf_set_mode(struct thermal_zone_device *thermal, 341 enum thermal_device_mode mode) 342{ 343 if (mode == THERMAL_DEVICE_DISABLED && kernelmode) 344 acerhdf_revert_to_bios_mode(); 345 else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) 346 acerhdf_enable_kernelmode(); 347 348 return 0; 349} 350 351static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip, 352 enum thermal_trip_type *type) 353{ 354 if (trip == 0) 355 *type = THERMAL_TRIP_ACTIVE; 356 357 return 0; 358} 359 360static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip, 361 unsigned long *temp) 362{ 363 if (trip == 0) 364 *temp = fanon; 365 366 return 0; 367} 368 369static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal, 370 unsigned long *temperature) 371{ 372 *temperature = ACERHDF_TEMP_CRIT; 373 return 0; 374} 375 376/* bind callback functions to thermalzone */ 377struct thermal_zone_device_ops acerhdf_dev_ops = { 378 .bind = acerhdf_bind, 379 .unbind = acerhdf_unbind, 380 .get_temp = acerhdf_get_ec_temp, 381 .get_mode = acerhdf_get_mode, 382 .set_mode = acerhdf_set_mode, 383 .get_trip_type = acerhdf_get_trip_type, 384 .get_trip_temp = acerhdf_get_trip_temp, 385 .get_crit_temp = acerhdf_get_crit_temp, 386}; 387 388 389/* 390 * cooling device callback functions 391 * get maximal fan cooling state 392 */ 393static int acerhdf_get_max_state(struct thermal_cooling_device *cdev, 394 unsigned long *state) 395{ 396 *state = 1; 397 398 return 0; 399} 400 401static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev, 402 unsigned long *state) 403{ 404 int err = 0, tmp; 405 406 err = acerhdf_get_fanstate(&tmp); 407 if (err) 408 return err; 409 410 *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0; 411 return 0; 412} 413 414/* change current fan state - is overwritten when running in kernel mode */ 415static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev, 416 unsigned long state) 417{ 418 int cur_temp, cur_state, err = 0; 419 420 if (!kernelmode) 421 return 0; 422 423 err = acerhdf_get_temp(&cur_temp); 424 if (err) { 425 pr_err("error reading temperature, hand off control to BIOS\n"); 426 goto err_out; 427 } 428 429 err = acerhdf_get_fanstate(&cur_state); 430 if (err) { 431 pr_err("error reading fan state, hand off control to BIOS\n"); 432 goto err_out; 433 } 434 435 if (state == 0) { 436 /* turn fan off only if below fanoff temperature */ 437 if ((cur_state == ACERHDF_FAN_AUTO) && 438 (cur_temp < fanoff)) 439 acerhdf_change_fanstate(ACERHDF_FAN_OFF); 440 } else { 441 if (cur_state == ACERHDF_FAN_OFF) 442 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 443 } 444 return 0; 445 446err_out: 447 acerhdf_revert_to_bios_mode(); 448 return -EINVAL; 449} 450 451/* bind fan callbacks to fan device */ 452struct thermal_cooling_device_ops acerhdf_cooling_ops = { 453 .get_max_state = acerhdf_get_max_state, 454 .get_cur_state = acerhdf_get_cur_state, 455 .set_cur_state = acerhdf_set_cur_state, 456}; 457 458/* suspend / resume functionality */ 459static int acerhdf_suspend(struct device *dev) 460{ 461 if (kernelmode) 462 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 463 464 if (verbose) 465 pr_notice("going suspend\n"); 466 467 return 0; 468} 469 470static int __devinit acerhdf_probe(struct platform_device *device) 471{ 472 return 0; 473} 474 475static int acerhdf_remove(struct platform_device *device) 476{ 477 return 0; 478} 479 480static const struct dev_pm_ops acerhdf_pm_ops = { 481 .suspend = acerhdf_suspend, 482 .freeze = acerhdf_suspend, 483}; 484 485static struct platform_driver acerhdf_driver = { 486 .driver = { 487 .name = "acerhdf", 488 .owner = THIS_MODULE, 489 .pm = &acerhdf_pm_ops, 490 }, 491 .probe = acerhdf_probe, 492 .remove = acerhdf_remove, 493}; 494 495/* checks if str begins with start */ 496static int str_starts_with(const char *str, const char *start) 497{ 498 unsigned long str_len = 0, start_len = 0; 499 500 str_len = strlen(str); 501 start_len = strlen(start); 502 503 if (str_len >= start_len && 504 !strncmp(str, start, start_len)) 505 return 1; 506 507 return 0; 508} 509 510/* check hardware */ 511static int acerhdf_check_hardware(void) 512{ 513 char const *vendor, *version, *product; 514 const struct bios_settings_t *bt = NULL; 515 516 /* get BIOS data */ 517 vendor = dmi_get_system_info(DMI_SYS_VENDOR); 518 version = dmi_get_system_info(DMI_BIOS_VERSION); 519 product = dmi_get_system_info(DMI_PRODUCT_NAME); 520 521 522 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); 523 524 if (force_bios[0]) { 525 version = force_bios; 526 pr_info("forcing BIOS version: %s\n", version); 527 kernelmode = 0; 528 } 529 530 if (force_product[0]) { 531 product = force_product; 532 pr_info("forcing BIOS product: %s\n", product); 533 kernelmode = 0; 534 } 535 536 if (verbose) 537 pr_info("BIOS info: %s %s, product: %s\n", 538 vendor, version, product); 539 540 /* search BIOS version and vendor in BIOS settings table */ 541 for (bt = bios_tbl; bt->vendor[0]; bt++) { 542 /* 543 * check if actual hardware BIOS vendor, product and version 544 * IDs start with the strings of BIOS table entry 545 */ 546 if (str_starts_with(vendor, bt->vendor) && 547 str_starts_with(product, bt->product) && 548 str_starts_with(version, bt->version)) { 549 bios_cfg = bt; 550 break; 551 } 552 } 553 554 if (!bios_cfg) { 555 pr_err("unknown (unsupported) BIOS version %s/%s/%s, " 556 "please report, aborting!\n", vendor, product, version); 557 return -EINVAL; 558 } 559 560 /* 561 * if started with kernel mode off, prevent the kernel from switching 562 * off the fan 563 */ 564 if (!kernelmode) { 565 pr_notice("Fan control off, to enable do:\n"); 566 pr_notice("echo -n \"enabled\" > " 567 "/sys/class/thermal/thermal_zone0/mode\n"); 568 } 569 570 return 0; 571} 572 573static int acerhdf_register_platform(void) 574{ 575 int err = 0; 576 577 err = platform_driver_register(&acerhdf_driver); 578 if (err) 579 return err; 580 581 acerhdf_dev = platform_device_alloc("acerhdf", -1); 582 platform_device_add(acerhdf_dev); 583 584 return 0; 585} 586 587static void acerhdf_unregister_platform(void) 588{ 589 if (!acerhdf_dev) 590 return; 591 592 platform_device_del(acerhdf_dev); 593 platform_driver_unregister(&acerhdf_driver); 594} 595 596static int acerhdf_register_thermal(void) 597{ 598 cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, 599 &acerhdf_cooling_ops); 600 601 if (IS_ERR(cl_dev)) 602 return -EINVAL; 603 604 thz_dev = thermal_zone_device_register("acerhdf", 1, NULL, 605 &acerhdf_dev_ops, 0, 0, 0, 606 (kernelmode) ? interval*1000 : 0); 607 if (IS_ERR(thz_dev)) 608 return -EINVAL; 609 610 return 0; 611} 612 613static void acerhdf_unregister_thermal(void) 614{ 615 if (cl_dev) { 616 thermal_cooling_device_unregister(cl_dev); 617 cl_dev = NULL; 618 } 619 620 if (thz_dev) { 621 thermal_zone_device_unregister(thz_dev); 622 thz_dev = NULL; 623 } 624} 625 626static int __init acerhdf_init(void) 627{ 628 int err = 0; 629 630 err = acerhdf_check_hardware(); 631 if (err) 632 goto out_err; 633 634 err = acerhdf_register_platform(); 635 if (err) 636 goto err_unreg; 637 638 err = acerhdf_register_thermal(); 639 if (err) 640 goto err_unreg; 641 642 return 0; 643 644err_unreg: 645 acerhdf_unregister_thermal(); 646 acerhdf_unregister_platform(); 647 648out_err: 649 return -ENODEV; 650} 651 652static void __exit acerhdf_exit(void) 653{ 654 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 655 acerhdf_unregister_thermal(); 656 acerhdf_unregister_platform(); 657} 658 659MODULE_LICENSE("GPL"); 660MODULE_AUTHOR("Peter Feuerer"); 661MODULE_DESCRIPTION("Aspire One temperature and fan driver"); 662MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); 663MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); 664MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); 665MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 666MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); 667MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); 668MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); 669MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); 670 671module_init(acerhdf_init); 672module_exit(acerhdf_exit);