Blame view

kernel/linux-rt-4.4.41/drivers/acpi/acpi_cmos_rtc.c 2.13 KB
5113f6f70   김현기   kernel add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  /*
   * ACPI support for CMOS RTC Address Space access
   *
   * Copyright (C) 2013, Intel Corporation
   * Authors: Lan Tianyu <tianyu.lan@intel.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.
   */
  
  #include <linux/acpi.h>
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <asm-generic/rtc.h>
  
  #include "internal.h"
  
  ACPI_MODULE_NAME("cmos rtc");
  
  static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
  	{ "PNP0B00" },
  	{ "PNP0B01" },
  	{ "PNP0B02" },
  	{}
  };
  
  static acpi_status
  acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
  		      u32 bits, u64 *value64,
  		      void *handler_context, void *region_context)
  {
  	int i;
  	u8 *value = (u8 *)value64;
  
  	if (address > 0xff || !value64)
  		return AE_BAD_PARAMETER;
  
  	if (function != ACPI_WRITE && function != ACPI_READ)
  		return AE_BAD_PARAMETER;
  
  	spin_lock_irq(&rtc_lock);
  
  	for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
  		if (function == ACPI_READ)
  			*value = CMOS_READ(address);
  		else
  			CMOS_WRITE(*value, address);
  
  	spin_unlock_irq(&rtc_lock);
  
  	return AE_OK;
  }
  
  static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
  		const struct acpi_device_id *id)
  {
  	acpi_status status;
  
  	status = acpi_install_address_space_handler(adev->handle,
  			ACPI_ADR_SPACE_CMOS,
  			&acpi_cmos_rtc_space_handler,
  			NULL, NULL);
  	if (ACPI_FAILURE(status)) {
  		pr_err(PREFIX "Error installing CMOS-RTC region handler
  ");
  		return -ENODEV;
  	}
  
  	return 1;
  }
  
  static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
  {
  	if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
  			ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
  		pr_err(PREFIX "Error removing CMOS-RTC region handler
  ");
  }
  
  static struct acpi_scan_handler cmos_rtc_handler = {
  	.ids = acpi_cmos_rtc_ids,
  	.attach = acpi_install_cmos_rtc_space_handler,
  	.detach = acpi_remove_cmos_rtc_space_handler,
  };
  
  void __init acpi_cmos_rtc_init(void)
  {
  	acpi_scan_add_handler(&cmos_rtc_handler);
  }