diff options
author | Corentin Chary <corentincj@iksaif.net> | 2011-11-26 04:59:59 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2012-03-20 12:02:05 -0400 |
commit | 5dea7a2094d5e60fe8f8ec4277d22d7ad6fa8c26 (patch) | |
tree | 116cff47022d348786be668d8c8c4b44c254c54a /drivers/platform/x86/samsung-laptop.c | |
parent | a6df48943a408b493d1aa141791d614a529d484e (diff) |
samsung-laptop: move code into init/exit functions
Create _init()/_exit() function for each subsystem, remove
the local struct samsung_laptop * and only keep a
struct platform_device * that can only be used in samsung_init()
and samsung_exit().
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform/x86/samsung-laptop.c')
-rw-r--r-- | drivers/platform/x86/samsung-laptop.c | 609 |
1 files changed, 360 insertions, 249 deletions
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index c2a74bfc017c..1dd81d148cb7 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
@@ -226,14 +226,14 @@ struct samsung_laptop { | |||
226 | 226 | ||
227 | struct mutex sabi_mutex; | 227 | struct mutex sabi_mutex; |
228 | 228 | ||
229 | struct platform_device *pdev; | 229 | struct platform_device *platform_device; |
230 | struct backlight_device *backlight_device; | 230 | struct backlight_device *backlight_device; |
231 | struct rfkill *rfk; | 231 | struct rfkill *rfk; |
232 | 232 | ||
233 | bool has_stepping_quirk; | 233 | bool has_stepping_quirk; |
234 | }; | 234 | }; |
235 | 235 | ||
236 | static struct samsung_laptop *samsung; | 236 | |
237 | 237 | ||
238 | static bool force; | 238 | static bool force; |
239 | module_param(force, bool, 0); | 239 | module_param(force, bool, 0); |
@@ -244,7 +244,8 @@ static bool debug; | |||
244 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 244 | module_param(debug, bool, S_IRUGO | S_IWUSR); |
245 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | 245 | MODULE_PARM_DESC(debug, "Debug enabled or not"); |
246 | 246 | ||
247 | static int sabi_get_command(u8 command, struct sabi_retval *sretval) | 247 | static int sabi_get_command(struct samsung_laptop *samsung, |
248 | u8 command, struct sabi_retval *sretval) | ||
248 | { | 249 | { |
249 | const struct sabi_config *config = samsung->config; | 250 | const struct sabi_config *config = samsung->config; |
250 | int retval = 0; | 251 | int retval = 0; |
@@ -291,7 +292,8 @@ exit: | |||
291 | 292 | ||
292 | } | 293 | } |
293 | 294 | ||
294 | static int sabi_set_command(u8 command, u8 data) | 295 | static int sabi_set_command(struct samsung_laptop *samsung, |
296 | u8 command, u8 data) | ||
295 | { | 297 | { |
296 | const struct sabi_config *config = samsung->config; | 298 | const struct sabi_config *config = samsung->config; |
297 | int retval = 0; | 299 | int retval = 0; |
@@ -326,53 +328,53 @@ static int sabi_set_command(u8 command, u8 data) | |||
326 | return retval; | 328 | return retval; |
327 | } | 329 | } |
328 | 330 | ||
329 | static void test_backlight(void) | 331 | static void test_backlight(struct samsung_laptop *samsung) |
330 | { | 332 | { |
331 | const struct sabi_commands *commands = &samsung->config->commands; | 333 | const struct sabi_commands *commands = &samsung->config->commands; |
332 | struct sabi_retval sretval; | 334 | struct sabi_retval sretval; |
333 | 335 | ||
334 | sabi_get_command(commands->get_backlight, &sretval); | 336 | sabi_get_command(samsung, commands->get_backlight, &sretval); |
335 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | 337 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); |
336 | 338 | ||
337 | sabi_set_command(commands->set_backlight, 0); | 339 | sabi_set_command(samsung, commands->set_backlight, 0); |
338 | printk(KERN_DEBUG "backlight should be off\n"); | 340 | printk(KERN_DEBUG "backlight should be off\n"); |
339 | 341 | ||
340 | sabi_get_command(commands->get_backlight, &sretval); | 342 | sabi_get_command(samsung, commands->get_backlight, &sretval); |
341 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | 343 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); |
342 | 344 | ||
343 | msleep(1000); | 345 | msleep(1000); |
344 | 346 | ||
345 | sabi_set_command(commands->set_backlight, 1); | 347 | sabi_set_command(samsung, commands->set_backlight, 1); |
346 | printk(KERN_DEBUG "backlight should be on\n"); | 348 | printk(KERN_DEBUG "backlight should be on\n"); |
347 | 349 | ||
348 | sabi_get_command(commands->get_backlight, &sretval); | 350 | sabi_get_command(samsung, commands->get_backlight, &sretval); |
349 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | 351 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); |
350 | } | 352 | } |
351 | 353 | ||
352 | static void test_wireless(void) | 354 | static void test_wireless(struct samsung_laptop *samsung) |
353 | { | 355 | { |
354 | const struct sabi_commands *commands = &samsung->config->commands; | 356 | const struct sabi_commands *commands = &samsung->config->commands; |
355 | struct sabi_retval sretval; | 357 | struct sabi_retval sretval; |
356 | 358 | ||
357 | sabi_get_command(commands->get_wireless_button, &sretval); | 359 | sabi_get_command(samsung, commands->get_wireless_button, &sretval); |
358 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | 360 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); |
359 | 361 | ||
360 | sabi_set_command(commands->set_wireless_button, 0); | 362 | sabi_set_command(samsung, commands->set_wireless_button, 0); |
361 | printk(KERN_DEBUG "wireless led should be off\n"); | 363 | printk(KERN_DEBUG "wireless led should be off\n"); |
362 | 364 | ||
363 | sabi_get_command(commands->get_wireless_button, &sretval); | 365 | sabi_get_command(samsung, commands->get_wireless_button, &sretval); |
364 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | 366 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); |
365 | 367 | ||
366 | msleep(1000); | 368 | msleep(1000); |
367 | 369 | ||
368 | sabi_set_command(commands->set_wireless_button, 1); | 370 | sabi_set_command(samsung, commands->set_wireless_button, 1); |
369 | printk(KERN_DEBUG "wireless led should be on\n"); | 371 | printk(KERN_DEBUG "wireless led should be on\n"); |
370 | 372 | ||
371 | sabi_get_command(commands->get_wireless_button, &sretval); | 373 | sabi_get_command(samsung, commands->get_wireless_button, &sretval); |
372 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | 374 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); |
373 | } | 375 | } |
374 | 376 | ||
375 | static u8 read_brightness(void) | 377 | static int read_brightness(struct samsung_laptop *samsung) |
376 | { | 378 | { |
377 | const struct sabi_config *config = samsung->config; | 379 | const struct sabi_config *config = samsung->config; |
378 | const struct sabi_commands *commands = &samsung->config->commands; | 380 | const struct sabi_commands *commands = &samsung->config->commands; |
@@ -380,7 +382,7 @@ static u8 read_brightness(void) | |||
380 | int user_brightness = 0; | 382 | int user_brightness = 0; |
381 | int retval; | 383 | int retval; |
382 | 384 | ||
383 | retval = sabi_get_command(commands->get_brightness, | 385 | retval = sabi_get_command(samsung, commands->get_brightness, |
384 | &sretval); | 386 | &sretval); |
385 | if (!retval) { | 387 | if (!retval) { |
386 | user_brightness = sretval.retval[0]; | 388 | user_brightness = sretval.retval[0]; |
@@ -392,7 +394,7 @@ static u8 read_brightness(void) | |||
392 | return user_brightness; | 394 | return user_brightness; |
393 | } | 395 | } |
394 | 396 | ||
395 | static void set_brightness(u8 user_brightness) | 397 | static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness) |
396 | { | 398 | { |
397 | const struct sabi_config *config = samsung->config; | 399 | const struct sabi_config *config = samsung->config; |
398 | const struct sabi_commands *commands = &samsung->config->commands; | 400 | const struct sabi_commands *commands = &samsung->config->commands; |
@@ -403,25 +405,27 @@ static void set_brightness(u8 user_brightness) | |||
403 | * short circuit if the specified level is what's already set | 405 | * short circuit if the specified level is what's already set |
404 | * to prevent the screen from flickering needlessly | 406 | * to prevent the screen from flickering needlessly |
405 | */ | 407 | */ |
406 | if (user_brightness == read_brightness()) | 408 | if (user_brightness == read_brightness(samsung)) |
407 | return; | 409 | return; |
408 | 410 | ||
409 | sabi_set_command(commands->set_brightness, 0); | 411 | sabi_set_command(samsung, commands->set_brightness, 0); |
410 | } | 412 | } |
411 | 413 | ||
412 | sabi_set_command(commands->set_brightness, user_level); | 414 | sabi_set_command(samsung, commands->set_brightness, user_level); |
413 | } | 415 | } |
414 | 416 | ||
415 | static int get_brightness(struct backlight_device *bd) | 417 | static int get_brightness(struct backlight_device *bd) |
416 | { | 418 | { |
417 | return (int)read_brightness(); | 419 | struct samsung_laptop *samsung = bl_get_data(bd); |
420 | |||
421 | return read_brightness(samsung); | ||
418 | } | 422 | } |
419 | 423 | ||
420 | static void check_for_stepping_quirk(void) | 424 | static void check_for_stepping_quirk(struct samsung_laptop *samsung) |
421 | { | 425 | { |
422 | u8 initial_level; | 426 | int initial_level; |
423 | u8 check_level; | 427 | int check_level; |
424 | u8 orig_level = read_brightness(); | 428 | int orig_level = read_brightness(samsung); |
425 | 429 | ||
426 | /* | 430 | /* |
427 | * Some laptops exhibit the strange behaviour of stepping toward | 431 | * Some laptops exhibit the strange behaviour of stepping toward |
@@ -431,9 +435,9 @@ static void check_for_stepping_quirk(void) | |||
431 | */ | 435 | */ |
432 | 436 | ||
433 | if (orig_level == 0) | 437 | if (orig_level == 0) |
434 | set_brightness(1); | 438 | set_brightness(samsung, 1); |
435 | 439 | ||
436 | initial_level = read_brightness(); | 440 | initial_level = read_brightness(samsung); |
437 | 441 | ||
438 | if (initial_level <= 2) | 442 | if (initial_level <= 2) |
439 | check_level = initial_level + 2; | 443 | check_level = initial_level + 2; |
@@ -441,26 +445,28 @@ static void check_for_stepping_quirk(void) | |||
441 | check_level = initial_level - 2; | 445 | check_level = initial_level - 2; |
442 | 446 | ||
443 | samsung->has_stepping_quirk = false; | 447 | samsung->has_stepping_quirk = false; |
444 | set_brightness(check_level); | 448 | set_brightness(samsung, check_level); |
445 | 449 | ||
446 | if (read_brightness() != check_level) { | 450 | if (read_brightness(samsung) != check_level) { |
447 | samsung->has_stepping_quirk = true; | 451 | samsung->has_stepping_quirk = true; |
448 | pr_info("enabled workaround for brightness stepping quirk\n"); | 452 | pr_info("enabled workaround for brightness stepping quirk\n"); |
449 | } | 453 | } |
450 | 454 | ||
451 | set_brightness(orig_level); | 455 | set_brightness(samsung, orig_level); |
452 | } | 456 | } |
453 | 457 | ||
454 | static int update_status(struct backlight_device *bd) | 458 | static int update_status(struct backlight_device *bd) |
455 | { | 459 | { |
460 | struct samsung_laptop *samsung = bl_get_data(bd); | ||
456 | const struct sabi_commands *commands = &samsung->config->commands; | 461 | const struct sabi_commands *commands = &samsung->config->commands; |
457 | 462 | ||
458 | set_brightness(bd->props.brightness); | 463 | set_brightness(samsung, bd->props.brightness); |
459 | 464 | ||
460 | if (bd->props.power == FB_BLANK_UNBLANK) | 465 | if (bd->props.power == FB_BLANK_UNBLANK) |
461 | sabi_set_command(commands->set_backlight, 1); | 466 | sabi_set_command(samsung, commands->set_backlight, 1); |
462 | else | 467 | else |
463 | sabi_set_command(commands->set_backlight, 0); | 468 | sabi_set_command(samsung, commands->set_backlight, 0); |
469 | |||
464 | return 0; | 470 | return 0; |
465 | } | 471 | } |
466 | 472 | ||
@@ -471,6 +477,7 @@ static const struct backlight_ops backlight_ops = { | |||
471 | 477 | ||
472 | static int rfkill_set(void *data, bool blocked) | 478 | static int rfkill_set(void *data, bool blocked) |
473 | { | 479 | { |
480 | struct samsung_laptop *samsung = data; | ||
474 | const struct sabi_commands *commands = &samsung->config->commands; | 481 | const struct sabi_commands *commands = &samsung->config->commands; |
475 | 482 | ||
476 | /* Do something with blocked...*/ | 483 | /* Do something with blocked...*/ |
@@ -479,9 +486,9 @@ static int rfkill_set(void *data, bool blocked) | |||
479 | * blocked == true is off | 486 | * blocked == true is off |
480 | */ | 487 | */ |
481 | if (blocked) | 488 | if (blocked) |
482 | sabi_set_command(commands->set_wireless_button, 0); | 489 | sabi_set_command(samsung, commands->set_wireless_button, 0); |
483 | else | 490 | else |
484 | sabi_set_command(commands->set_wireless_button, 1); | 491 | sabi_set_command(samsung, commands->set_wireless_button, 1); |
485 | 492 | ||
486 | return 0; | 493 | return 0; |
487 | } | 494 | } |
@@ -490,40 +497,18 @@ static struct rfkill_ops rfkill_ops = { | |||
490 | .set_block = rfkill_set, | 497 | .set_block = rfkill_set, |
491 | }; | 498 | }; |
492 | 499 | ||
493 | static int init_wireless(struct platform_device *pdev) | ||
494 | { | ||
495 | int retval; | ||
496 | |||
497 | samsung->rfk = rfkill_alloc("samsung-wifi", &samsung->pdev->dev, RFKILL_TYPE_WLAN, | ||
498 | &rfkill_ops, NULL); | ||
499 | if (!samsung->rfk) | ||
500 | return -ENOMEM; | ||
501 | |||
502 | retval = rfkill_register(samsung->rfk); | ||
503 | if (retval) { | ||
504 | rfkill_destroy(samsung->rfk); | ||
505 | return -ENODEV; | ||
506 | } | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static void destroy_wireless(void) | ||
512 | { | ||
513 | rfkill_unregister(samsung->rfk); | ||
514 | rfkill_destroy(samsung->rfk); | ||
515 | } | ||
516 | |||
517 | static ssize_t get_performance_level(struct device *dev, | 500 | static ssize_t get_performance_level(struct device *dev, |
518 | struct device_attribute *attr, char *buf) | 501 | struct device_attribute *attr, char *buf) |
519 | { | 502 | { |
503 | struct samsung_laptop *samsung = dev_get_drvdata(dev); | ||
520 | const struct sabi_config *config = samsung->config; | 504 | const struct sabi_config *config = samsung->config; |
505 | const struct sabi_commands *commands = &config->commands; | ||
521 | struct sabi_retval sretval; | 506 | struct sabi_retval sretval; |
522 | int retval; | 507 | int retval; |
523 | int i; | 508 | int i; |
524 | 509 | ||
525 | /* Read the state */ | 510 | /* Read the state */ |
526 | retval = sabi_get_command(config->commands.get_performance_level, | 511 | retval = sabi_get_command(samsung, commands->get_performance_level, |
527 | &sretval); | 512 | &sretval); |
528 | if (retval) | 513 | if (retval) |
529 | return retval; | 514 | return retval; |
@@ -540,32 +525,285 @@ static ssize_t set_performance_level(struct device *dev, | |||
540 | struct device_attribute *attr, const char *buf, | 525 | struct device_attribute *attr, const char *buf, |
541 | size_t count) | 526 | size_t count) |
542 | { | 527 | { |
528 | struct samsung_laptop *samsung = dev_get_drvdata(dev); | ||
543 | const struct sabi_config *config = samsung->config; | 529 | const struct sabi_config *config = samsung->config; |
530 | const struct sabi_commands *commands = &config->commands; | ||
531 | int i; | ||
544 | 532 | ||
545 | if (count >= 1) { | 533 | if (count < 1) |
546 | int i; | 534 | return count; |
547 | for (i = 0; config->performance_levels[i].name; ++i) { | 535 | |
548 | const struct sabi_performance_level *level = | 536 | for (i = 0; config->performance_levels[i].name; ++i) { |
549 | &config->performance_levels[i]; | 537 | const struct sabi_performance_level *level = |
550 | if (!strncasecmp(level->name, buf, strlen(level->name))) { | 538 | &config->performance_levels[i]; |
551 | sabi_set_command(config->commands.set_performance_level, | 539 | if (!strncasecmp(level->name, buf, strlen(level->name))) { |
552 | level->value); | 540 | sabi_set_command(samsung, |
553 | break; | 541 | commands->set_performance_level, |
554 | } | 542 | level->value); |
543 | break; | ||
555 | } | 544 | } |
556 | if (!config->performance_levels[i].name) | ||
557 | return -EINVAL; | ||
558 | } | 545 | } |
546 | |||
547 | if (!config->performance_levels[i].name) | ||
548 | return -EINVAL; | ||
549 | |||
559 | return count; | 550 | return count; |
560 | } | 551 | } |
552 | |||
561 | static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, | 553 | static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, |
562 | get_performance_level, set_performance_level); | 554 | get_performance_level, set_performance_level); |
563 | 555 | ||
564 | 556 | ||
557 | static int find_signature(void __iomem *memcheck, const char *testStr) | ||
558 | { | ||
559 | int i = 0; | ||
560 | int loca; | ||
561 | |||
562 | for (loca = 0; loca < 0xffff; loca++) { | ||
563 | char temp = readb(memcheck + loca); | ||
564 | |||
565 | if (temp == testStr[i]) { | ||
566 | if (i == strlen(testStr)-1) | ||
567 | break; | ||
568 | ++i; | ||
569 | } else { | ||
570 | i = 0; | ||
571 | } | ||
572 | } | ||
573 | return loca; | ||
574 | } | ||
575 | |||
576 | static void samsung_rfkill_exit(struct samsung_laptop *samsung) | ||
577 | { | ||
578 | if (samsung->rfk) { | ||
579 | rfkill_unregister(samsung->rfk); | ||
580 | rfkill_destroy(samsung->rfk); | ||
581 | samsung->rfk = NULL; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static int __init samsung_rfkill_init(struct samsung_laptop *samsung) | ||
586 | { | ||
587 | int retval; | ||
588 | |||
589 | samsung->rfk = rfkill_alloc("samsung-wifi", | ||
590 | &samsung->platform_device->dev, | ||
591 | RFKILL_TYPE_WLAN, | ||
592 | &rfkill_ops, samsung); | ||
593 | if (!samsung->rfk) | ||
594 | return -ENOMEM; | ||
595 | |||
596 | retval = rfkill_register(samsung->rfk); | ||
597 | if (retval) { | ||
598 | rfkill_destroy(samsung->rfk); | ||
599 | samsung->rfk = NULL; | ||
600 | return -ENODEV; | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static void samsung_backlight_exit(struct samsung_laptop *samsung) | ||
607 | { | ||
608 | if (samsung->backlight_device) { | ||
609 | backlight_device_unregister(samsung->backlight_device); | ||
610 | samsung->backlight_device = NULL; | ||
611 | } | ||
612 | } | ||
613 | |||
614 | static int __init samsung_backlight_init(struct samsung_laptop *samsung) | ||
615 | { | ||
616 | struct backlight_device *bd; | ||
617 | struct backlight_properties props; | ||
618 | |||
619 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
620 | props.type = BACKLIGHT_PLATFORM; | ||
621 | props.max_brightness = samsung->config->max_brightness - | ||
622 | samsung->config->min_brightness; | ||
623 | |||
624 | bd = backlight_device_register("samsung", | ||
625 | &samsung->platform_device->dev, | ||
626 | samsung, &backlight_ops, | ||
627 | &props); | ||
628 | if (IS_ERR(bd)) | ||
629 | return PTR_ERR(bd); | ||
630 | |||
631 | samsung->backlight_device = bd; | ||
632 | samsung->backlight_device->props.brightness = read_brightness(samsung); | ||
633 | samsung->backlight_device->props.power = FB_BLANK_UNBLANK; | ||
634 | backlight_update_status(samsung->backlight_device); | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static void samsung_sysfs_exit(struct samsung_laptop *samsung) | ||
640 | { | ||
641 | device_remove_file(&samsung->platform_device->dev, | ||
642 | &dev_attr_performance_level); | ||
643 | } | ||
644 | |||
645 | static int __init samsung_sysfs_init(struct samsung_laptop *samsung) | ||
646 | { | ||
647 | return device_create_file(&samsung->platform_device->dev, | ||
648 | &dev_attr_performance_level); | ||
649 | } | ||
650 | |||
651 | static void samsung_sabi_exit(struct samsung_laptop *samsung) | ||
652 | { | ||
653 | const struct sabi_config *config = samsung->config; | ||
654 | |||
655 | /* Turn off "Linux" mode in the BIOS */ | ||
656 | if (config && config->commands.set_linux != 0xff) | ||
657 | sabi_set_command(samsung, config->commands.set_linux, 0x80); | ||
658 | |||
659 | if (samsung->sabi_iface) { | ||
660 | iounmap(samsung->sabi_iface); | ||
661 | samsung->sabi_iface = NULL; | ||
662 | } | ||
663 | if (samsung->f0000_segment) { | ||
664 | iounmap(samsung->f0000_segment); | ||
665 | samsung->f0000_segment = NULL; | ||
666 | } | ||
667 | |||
668 | samsung->config = NULL; | ||
669 | } | ||
670 | |||
671 | static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca) | ||
672 | { | ||
673 | const struct sabi_config *config = samsung->config; | ||
674 | |||
675 | printk(KERN_DEBUG "This computer supports SABI==%x\n", | ||
676 | loca + 0xf0000 - 6); | ||
677 | printk(KERN_DEBUG "SABI header:\n"); | ||
678 | printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", | ||
679 | readw(samsung->sabi + config->header_offsets.port)); | ||
680 | printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", | ||
681 | readb(samsung->sabi + config->header_offsets.iface_func)); | ||
682 | printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", | ||
683 | readb(samsung->sabi + config->header_offsets.en_mem)); | ||
684 | printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", | ||
685 | readb(samsung->sabi + config->header_offsets.re_mem)); | ||
686 | printk(KERN_DEBUG " SABI data offset = 0x%04x\n", | ||
687 | readw(samsung->sabi + config->header_offsets.data_offset)); | ||
688 | printk(KERN_DEBUG " SABI data segment = 0x%04x\n", | ||
689 | readw(samsung->sabi + config->header_offsets.data_segment)); | ||
690 | } | ||
691 | |||
692 | static void __init samsung_sabi_selftest(struct samsung_laptop *samsung, | ||
693 | unsigned int ifaceP) | ||
694 | { | ||
695 | const struct sabi_config *config = samsung->config; | ||
696 | struct sabi_retval sretval; | ||
697 | |||
698 | printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); | ||
699 | printk(KERN_DEBUG "sabi_iface = %p\n", samsung->sabi_iface); | ||
700 | |||
701 | test_backlight(samsung); | ||
702 | test_wireless(samsung); | ||
703 | |||
704 | sabi_get_command(samsung, config->commands.get_brightness, &sretval); | ||
705 | printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); | ||
706 | } | ||
707 | |||
708 | static int __init samsung_sabi_init(struct samsung_laptop *samsung) | ||
709 | { | ||
710 | const struct sabi_config *config = NULL; | ||
711 | const struct sabi_commands *commands; | ||
712 | unsigned int ifaceP; | ||
713 | int ret = 0; | ||
714 | int i; | ||
715 | int loca; | ||
716 | |||
717 | samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff); | ||
718 | if (!samsung->f0000_segment) { | ||
719 | pr_err("Can't map the segment at 0xf0000\n"); | ||
720 | ret = -EINVAL; | ||
721 | goto exit; | ||
722 | } | ||
723 | |||
724 | /* Try to find one of the signatures in memory to find the header */ | ||
725 | for (i = 0; sabi_configs[i].test_string != 0; ++i) { | ||
726 | samsung->config = &sabi_configs[i]; | ||
727 | loca = find_signature(samsung->f0000_segment, | ||
728 | samsung->config->test_string); | ||
729 | if (loca != 0xffff) | ||
730 | break; | ||
731 | } | ||
732 | |||
733 | if (loca == 0xffff) { | ||
734 | pr_err("This computer does not support SABI\n"); | ||
735 | ret = -ENODEV; | ||
736 | goto exit; | ||
737 | } | ||
738 | |||
739 | config = samsung->config; | ||
740 | commands = &config->commands; | ||
741 | |||
742 | /* point to the SMI port Number */ | ||
743 | loca += 1; | ||
744 | samsung->sabi = (samsung->f0000_segment + loca); | ||
745 | |||
746 | if (debug) | ||
747 | samsung_sabi_infos(samsung, loca); | ||
748 | |||
749 | /* Get a pointer to the SABI Interface */ | ||
750 | ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4; | ||
751 | ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff; | ||
752 | samsung->sabi_iface = ioremap_nocache(ifaceP, 16); | ||
753 | if (!samsung->sabi_iface) { | ||
754 | pr_err("Can't remap %x\n", ifaceP); | ||
755 | ret = -EINVAL; | ||
756 | goto exit; | ||
757 | } | ||
758 | |||
759 | if (debug) | ||
760 | samsung_sabi_selftest(samsung, ifaceP); | ||
761 | |||
762 | /* Turn on "Linux" mode in the BIOS */ | ||
763 | if (commands->set_linux != 0xff) { | ||
764 | int retval = sabi_set_command(samsung, | ||
765 | commands->set_linux, 0x81); | ||
766 | if (retval) { | ||
767 | pr_warn("Linux mode was not set!\n"); | ||
768 | ret = -ENODEV; | ||
769 | goto exit; | ||
770 | } | ||
771 | } | ||
772 | |||
773 | /* Check for stepping quirk */ | ||
774 | check_for_stepping_quirk(samsung); | ||
775 | |||
776 | exit: | ||
777 | if (ret) | ||
778 | samsung_sabi_exit(samsung); | ||
779 | |||
780 | return ret; | ||
781 | } | ||
782 | |||
783 | static void samsung_platform_exit(struct samsung_laptop *samsung) | ||
784 | { | ||
785 | if (samsung->platform_device) { | ||
786 | platform_device_unregister(samsung->platform_device); | ||
787 | samsung->platform_device = NULL; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | static int __init samsung_platform_init(struct samsung_laptop *samsung) | ||
792 | { | ||
793 | struct platform_device *pdev; | ||
794 | |||
795 | pdev = platform_device_register_simple("samsung", -1, NULL, 0); | ||
796 | if (IS_ERR(pdev)) | ||
797 | return PTR_ERR(pdev); | ||
798 | |||
799 | samsung->platform_device = pdev; | ||
800 | platform_set_drvdata(samsung->platform_device, samsung); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
565 | static int __init dmi_check_cb(const struct dmi_system_id *id) | 804 | static int __init dmi_check_cb(const struct dmi_system_id *id) |
566 | { | 805 | { |
567 | pr_info("found laptop model '%s'\n", | 806 | pr_info("found laptop model '%s'\n", id->ident); |
568 | id->ident); | ||
569 | return 1; | 807 | return 1; |
570 | } | 808 | } |
571 | 809 | ||
@@ -806,36 +1044,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
806 | }; | 1044 | }; |
807 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | 1045 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); |
808 | 1046 | ||
809 | static int find_signature(void __iomem *memcheck, const char *testStr) | 1047 | static struct platform_device *samsung_platform_device; |
810 | { | ||
811 | int i = 0; | ||
812 | int loca; | ||
813 | |||
814 | for (loca = 0; loca < 0xffff; loca++) { | ||
815 | char temp = readb(memcheck + loca); | ||
816 | |||
817 | if (temp == testStr[i]) { | ||
818 | if (i == strlen(testStr)-1) | ||
819 | break; | ||
820 | ++i; | ||
821 | } else { | ||
822 | i = 0; | ||
823 | } | ||
824 | } | ||
825 | return loca; | ||
826 | } | ||
827 | 1048 | ||
828 | static int __init samsung_init(void) | 1049 | static int __init samsung_init(void) |
829 | { | 1050 | { |
830 | const struct sabi_config *config = NULL; | 1051 | struct samsung_laptop *samsung; |
831 | const struct sabi_commands *commands; | 1052 | int ret; |
832 | struct backlight_device *bd; | ||
833 | struct backlight_properties props; | ||
834 | struct sabi_retval sretval; | ||
835 | unsigned int ifaceP; | ||
836 | int i; | ||
837 | int loca; | ||
838 | int retval; | ||
839 | 1053 | ||
840 | if (!force && !dmi_check_system(samsung_dmi_table)) | 1054 | if (!force && !dmi_check_system(samsung_dmi_table)) |
841 | return -ENODEV; | 1055 | return -ENODEV; |
@@ -846,159 +1060,56 @@ static int __init samsung_init(void) | |||
846 | 1060 | ||
847 | mutex_init(&samsung->sabi_mutex); | 1061 | mutex_init(&samsung->sabi_mutex); |
848 | 1062 | ||
849 | samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff); | 1063 | ret = samsung_platform_init(samsung); |
850 | if (!samsung->f0000_segment) { | 1064 | if (ret) |
851 | pr_err("Can't map the segment at 0xf0000\n"); | 1065 | goto error_platform; |
852 | goto error_cant_map; | 1066 | |
853 | } | 1067 | ret = samsung_sabi_init(samsung); |
854 | 1068 | if (ret) | |
855 | /* Try to find one of the signatures in memory to find the header */ | 1069 | goto error_sabi; |
856 | for (i = 0; sabi_configs[i].test_string != 0; ++i) { | 1070 | |
857 | samsung->config = &sabi_configs[i]; | 1071 | ret = samsung_sysfs_init(samsung); |
858 | loca = find_signature(samsung->f0000_segment, | 1072 | if (ret) |
859 | samsung->config->test_string); | 1073 | goto error_sysfs; |
860 | if (loca != 0xffff) | 1074 | |
861 | break; | 1075 | ret = samsung_backlight_init(samsung); |
862 | } | 1076 | if (ret) |
863 | 1077 | goto error_backlight; | |
864 | if (loca == 0xffff) { | 1078 | |
865 | pr_err("This computer does not support SABI\n"); | 1079 | ret = samsung_rfkill_init(samsung); |
866 | goto error_no_signature; | 1080 | if (ret) |
867 | } | 1081 | goto error_rfkill; |
868 | 1082 | ||
869 | config = samsung->config; | 1083 | samsung_platform_device = samsung->platform_device; |
870 | commands = &config->commands; | 1084 | return ret; |
871 | 1085 | ||
872 | /* point to the SMI port Number */ | 1086 | error_rfkill: |
873 | loca += 1; | 1087 | samsung_backlight_exit(samsung); |
874 | samsung->sabi = (samsung->f0000_segment + loca); | 1088 | error_backlight: |
875 | 1089 | samsung_sysfs_exit(samsung); | |
876 | if (debug) { | 1090 | error_sysfs: |
877 | printk(KERN_DEBUG "This computer supports SABI==%x\n", | 1091 | samsung_sabi_exit(samsung); |
878 | loca + 0xf0000 - 6); | 1092 | error_sabi: |
879 | printk(KERN_DEBUG "SABI header:\n"); | 1093 | samsung_platform_exit(samsung); |
880 | printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", | 1094 | error_platform: |
881 | readw(samsung->sabi + | ||
882 | config->header_offsets.port)); | ||
883 | printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", | ||
884 | readb(samsung->sabi + | ||
885 | config->header_offsets.iface_func)); | ||
886 | printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", | ||
887 | readb(samsung->sabi + | ||
888 | config->header_offsets.en_mem)); | ||
889 | printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", | ||
890 | readb(samsung->sabi + | ||
891 | config->header_offsets.re_mem)); | ||
892 | printk(KERN_DEBUG " SABI data offset = 0x%04x\n", | ||
893 | readw(samsung->sabi + | ||
894 | config->header_offsets.data_offset)); | ||
895 | printk(KERN_DEBUG " SABI data segment = 0x%04x\n", | ||
896 | readw(samsung->sabi + | ||
897 | config->header_offsets.data_segment)); | ||
898 | } | ||
899 | |||
900 | /* Get a pointer to the SABI Interface */ | ||
901 | ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4; | ||
902 | ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff; | ||
903 | samsung->sabi_iface = ioremap_nocache(ifaceP, 16); | ||
904 | if (!samsung->sabi_iface) { | ||
905 | pr_err("Can't remap %x\n", ifaceP); | ||
906 | goto error_no_signature; | ||
907 | } | ||
908 | if (debug) { | ||
909 | printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); | ||
910 | printk(KERN_DEBUG "sabi_iface = %p\n", samsung->sabi_iface); | ||
911 | |||
912 | test_backlight(); | ||
913 | test_wireless(); | ||
914 | |||
915 | retval = sabi_get_command(commands->get_brightness, | ||
916 | &sretval); | ||
917 | printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); | ||
918 | } | ||
919 | |||
920 | /* Turn on "Linux" mode in the BIOS */ | ||
921 | if (commands->set_linux != 0xff) { | ||
922 | retval = sabi_set_command(commands->set_linux, | ||
923 | 0x81); | ||
924 | if (retval) { | ||
925 | pr_warn("Linux mode was not set!\n"); | ||
926 | goto error_no_platform; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | /* Check for stepping quirk */ | ||
931 | check_for_stepping_quirk(); | ||
932 | |||
933 | /* knock up a platform device to hang stuff off of */ | ||
934 | samsung->pdev = platform_device_register_simple("samsung", -1, NULL, 0); | ||
935 | if (IS_ERR(samsung->pdev)) | ||
936 | goto error_no_platform; | ||
937 | |||
938 | /* create a backlight device to talk to this one */ | ||
939 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
940 | props.type = BACKLIGHT_PLATFORM; | ||
941 | props.max_brightness = config->max_brightness - | ||
942 | config->min_brightness; | ||
943 | bd = backlight_device_register("samsung", &samsung->pdev->dev, | ||
944 | NULL, &backlight_ops, | ||
945 | &props); | ||
946 | if (IS_ERR(bd)) | ||
947 | goto error_no_backlight; | ||
948 | |||
949 | samsung->backlight_device = bd; | ||
950 | samsung->backlight_device->props.brightness = read_brightness(); | ||
951 | samsung->backlight_device->props.power = FB_BLANK_UNBLANK; | ||
952 | backlight_update_status(samsung->backlight_device); | ||
953 | |||
954 | retval = init_wireless(samsung->pdev); | ||
955 | if (retval) | ||
956 | goto error_no_rfk; | ||
957 | |||
958 | retval = device_create_file(&samsung->pdev->dev, | ||
959 | &dev_attr_performance_level); | ||
960 | if (retval) | ||
961 | goto error_file_create; | ||
962 | |||
963 | return 0; | ||
964 | |||
965 | error_file_create: | ||
966 | destroy_wireless(); | ||
967 | |||
968 | error_no_rfk: | ||
969 | backlight_device_unregister(samsung->backlight_device); | ||
970 | |||
971 | error_no_backlight: | ||
972 | platform_device_unregister(samsung->pdev); | ||
973 | |||
974 | error_no_platform: | ||
975 | iounmap(samsung->sabi_iface); | ||
976 | |||
977 | error_no_signature: | ||
978 | iounmap(samsung->f0000_segment); | ||
979 | |||
980 | error_cant_map: | ||
981 | kfree(samsung); | 1095 | kfree(samsung); |
982 | samsung = NULL; | 1096 | return ret; |
983 | return -EINVAL; | ||
984 | } | 1097 | } |
985 | 1098 | ||
986 | static void __exit samsung_exit(void) | 1099 | static void __exit samsung_exit(void) |
987 | { | 1100 | { |
988 | const struct sabi_commands *commands = &samsung->config->commands; | 1101 | struct samsung_laptop *samsung; |
1102 | |||
1103 | samsung = platform_get_drvdata(samsung_platform_device); | ||
1104 | |||
1105 | samsung_rfkill_exit(samsung); | ||
1106 | samsung_backlight_exit(samsung); | ||
1107 | samsung_sysfs_exit(samsung); | ||
1108 | samsung_sabi_exit(samsung); | ||
1109 | samsung_platform_exit(samsung); | ||
989 | 1110 | ||
990 | /* Turn off "Linux" mode in the BIOS */ | ||
991 | if (commands->set_linux != 0xff) | ||
992 | sabi_set_command(commands->set_linux, 0x80); | ||
993 | |||
994 | device_remove_file(&samsung->pdev->dev, &dev_attr_performance_level); | ||
995 | backlight_device_unregister(samsung->backlight_device); | ||
996 | destroy_wireless(); | ||
997 | iounmap(samsung->sabi_iface); | ||
998 | iounmap(samsung->f0000_segment); | ||
999 | platform_device_unregister(samsung->pdev); | ||
1000 | kfree(samsung); | 1111 | kfree(samsung); |
1001 | samsung = NULL; | 1112 | samsung_platform_device = NULL; |
1002 | } | 1113 | } |
1003 | 1114 | ||
1004 | module_init(samsung_init); | 1115 | module_init(samsung_init); |