Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/hwmon/hwmon.c
15109 views
1
/*
2
hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
3
4
This file defines the sysfs class "hwmon", for use by sensors drivers.
5
6
Copyright (C) 2005 Mark M. Hoffman <[email protected]>
7
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; version 2 of the License.
11
*/
12
13
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15
#include <linux/module.h>
16
#include <linux/device.h>
17
#include <linux/err.h>
18
#include <linux/kdev_t.h>
19
#include <linux/idr.h>
20
#include <linux/hwmon.h>
21
#include <linux/gfp.h>
22
#include <linux/spinlock.h>
23
#include <linux/pci.h>
24
25
#define HWMON_ID_PREFIX "hwmon"
26
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
27
28
static struct class *hwmon_class;
29
30
static DEFINE_IDR(hwmon_idr);
31
static DEFINE_SPINLOCK(idr_lock);
32
33
/**
34
* hwmon_device_register - register w/ hwmon
35
* @dev: the device to register
36
*
37
* hwmon_device_unregister() must be called when the device is no
38
* longer needed.
39
*
40
* Returns the pointer to the new device.
41
*/
42
struct device *hwmon_device_register(struct device *dev)
43
{
44
struct device *hwdev;
45
int id, err;
46
47
again:
48
if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0))
49
return ERR_PTR(-ENOMEM);
50
51
spin_lock(&idr_lock);
52
err = idr_get_new(&hwmon_idr, NULL, &id);
53
spin_unlock(&idr_lock);
54
55
if (unlikely(err == -EAGAIN))
56
goto again;
57
else if (unlikely(err))
58
return ERR_PTR(err);
59
60
id = id & MAX_ID_MASK;
61
hwdev = device_create(hwmon_class, dev, MKDEV(0, 0), NULL,
62
HWMON_ID_FORMAT, id);
63
64
if (IS_ERR(hwdev)) {
65
spin_lock(&idr_lock);
66
idr_remove(&hwmon_idr, id);
67
spin_unlock(&idr_lock);
68
}
69
70
return hwdev;
71
}
72
73
/**
74
* hwmon_device_unregister - removes the previously registered class device
75
*
76
* @dev: the class device to destroy
77
*/
78
void hwmon_device_unregister(struct device *dev)
79
{
80
int id;
81
82
if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) {
83
device_unregister(dev);
84
spin_lock(&idr_lock);
85
idr_remove(&hwmon_idr, id);
86
spin_unlock(&idr_lock);
87
} else
88
dev_dbg(dev->parent,
89
"hwmon_device_unregister() failed: bad class ID!\n");
90
}
91
92
static void __init hwmon_pci_quirks(void)
93
{
94
#if defined CONFIG_X86 && defined CONFIG_PCI
95
struct pci_dev *sb;
96
u16 base;
97
u8 enable;
98
99
/* Open access to 0x295-0x296 on MSI MS-7031 */
100
sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
101
if (sb &&
102
(sb->subsystem_vendor == 0x1462 && /* MSI */
103
sb->subsystem_device == 0x0031)) { /* MS-7031 */
104
105
pci_read_config_byte(sb, 0x48, &enable);
106
pci_read_config_word(sb, 0x64, &base);
107
108
if (base == 0 && !(enable & BIT(2))) {
109
dev_info(&sb->dev,
110
"Opening wide generic port at 0x295\n");
111
pci_write_config_word(sb, 0x64, 0x295);
112
pci_write_config_byte(sb, 0x48, enable | BIT(2));
113
}
114
}
115
#endif
116
}
117
118
static int __init hwmon_init(void)
119
{
120
hwmon_pci_quirks();
121
122
hwmon_class = class_create(THIS_MODULE, "hwmon");
123
if (IS_ERR(hwmon_class)) {
124
pr_err("couldn't create sysfs class\n");
125
return PTR_ERR(hwmon_class);
126
}
127
return 0;
128
}
129
130
static void __exit hwmon_exit(void)
131
{
132
class_destroy(hwmon_class);
133
}
134
135
subsys_initcall(hwmon_init);
136
module_exit(hwmon_exit);
137
138
EXPORT_SYMBOL_GPL(hwmon_device_register);
139
EXPORT_SYMBOL_GPL(hwmon_device_unregister);
140
141
MODULE_AUTHOR("Mark M. Hoffman <[email protected]>");
142
MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
143
MODULE_LICENSE("GPL");
144
145
146