compat: only define thermal backports if CONFIG_THERMAL is enabled
[openwrt/staging/blogic.git] / backport / compat / backport-4.3.c
1 /*
2 * Copyright (c) 2015 Hauke Mehrtens <hauke@hauke-m.de>
3 * Copyright (c) 2015 - 2016 Intel Deutschland GmbH
4 *
5 * Backport functionality introduced in Linux 4.3.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12 #include <linux/version.h>
13 #include <linux/seq_file.h>
14 #include <linux/export.h>
15 #include <linux/printk.h>
16 #include <linux/thermal.h>
17 #include <linux/slab.h>
18
19 #ifdef CONFIG_THERMAL
20 #if LINUX_VERSION_IS_GEQ(3,8,0)
21 struct backport_thermal_ops_wrapper {
22 old_thermal_zone_device_ops_t ops;
23 struct thermal_zone_device_ops *driver_ops;
24 };
25
26 static int backport_thermal_get_temp(struct thermal_zone_device *dev,
27 unsigned long *temp)
28 {
29 struct backport_thermal_ops_wrapper *wrapper =
30 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
31 int _temp, ret;
32
33 ret = wrapper->driver_ops->get_temp(dev, &_temp);
34 if (!ret)
35 *temp = (unsigned long)_temp;
36
37 return ret;
38 }
39
40 static int backport_thermal_get_trip_temp(struct thermal_zone_device *dev,
41 int i, unsigned long *temp)
42 {
43 struct backport_thermal_ops_wrapper *wrapper =
44 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
45 int _temp, ret;
46
47 ret = wrapper->driver_ops->get_trip_temp(dev, i, &_temp);
48 if (!ret)
49 *temp = (unsigned long)_temp;
50
51 return ret;
52 }
53
54 static int backport_thermal_set_trip_temp(struct thermal_zone_device *dev,
55 int i, unsigned long temp)
56 {
57 struct backport_thermal_ops_wrapper *wrapper =
58 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
59
60 return wrapper->driver_ops->set_trip_temp(dev, i, (int)temp);
61 }
62
63 static int backport_thermal_get_trip_hyst(struct thermal_zone_device *dev,
64 int i, unsigned long *temp)
65 {
66 struct backport_thermal_ops_wrapper *wrapper =
67 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
68 int _temp, ret;
69
70 ret = wrapper->driver_ops->get_trip_hyst(dev, i, &_temp);
71 if (!ret)
72 *temp = (unsigned long)_temp;
73
74 return ret;
75 }
76
77 static int backport_thermal_set_trip_hyst(struct thermal_zone_device *dev,
78 int i, unsigned long temp)
79 {
80 struct backport_thermal_ops_wrapper *wrapper =
81 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
82
83 return wrapper->driver_ops->set_trip_hyst(dev, i, (int)temp);
84 }
85
86 static int backport_thermal_get_crit_temp(struct thermal_zone_device *dev,
87 unsigned long *temp)
88 {
89 struct backport_thermal_ops_wrapper *wrapper =
90 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
91 int _temp, ret;
92
93 ret = wrapper->driver_ops->get_crit_temp(dev, &_temp);
94 if (!ret)
95 *temp = (unsigned long)_temp;
96
97 return ret;
98 }
99
100 #if LINUX_VERSION_IS_GEQ(3, 19, 0)
101 static int backport_thermal_set_emul_temp(struct thermal_zone_device *dev,
102 unsigned long temp)
103 {
104 struct backport_thermal_ops_wrapper *wrapper =
105 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
106
107 return wrapper->driver_ops->set_emul_temp(dev, (int)temp);
108 }
109 #endif /* LINUX_VERSION_IS_GEQ(3, 19, 0) */
110
111 struct thermal_zone_device *backport_thermal_zone_device_register(
112 const char *type, int trips, int mask, void *devdata,
113 struct thermal_zone_device_ops *ops,
114 const struct thermal_zone_params *tzp,
115 int passive_delay, int polling_delay)
116 {
117 struct backport_thermal_ops_wrapper *wrapper = kzalloc(sizeof(*wrapper), GFP_KERNEL);
118 struct thermal_zone_device *ret;
119
120 if (!wrapper)
121 return NULL;
122
123 wrapper->driver_ops = ops;
124
125 #define copy(_op) \
126 wrapper->ops._op = ops->_op
127
128 copy(bind);
129 copy(unbind);
130 copy(get_mode);
131 copy(set_mode);
132 copy(get_trip_type);
133 copy(get_trend);
134 copy(notify);
135
136 /* Assign the backport ops to the old struct to get the
137 * correct types. But only assign if the registrant defined
138 * the ops.
139 */
140 #define assign_ops(_op) \
141 if (ops->_op) \
142 wrapper->ops._op = backport_thermal_##_op
143
144 assign_ops(get_temp);
145 assign_ops(get_trip_temp);
146 assign_ops(set_trip_temp);
147 assign_ops(get_trip_hyst);
148 assign_ops(set_trip_hyst);
149 assign_ops(get_crit_temp);
150 #if LINUX_VERSION_IS_GEQ(3, 19, 0)
151 assign_ops(set_emul_temp);
152 #endif /* LINUX_VERSION_IS_GEQ(3, 19, 0) */
153 #undef assign_ops
154
155 ret = old_thermal_zone_device_register(type, trips, mask, devdata,
156 &wrapper->ops, tzp, passive_delay,
157 polling_delay);
158 if (!ret)
159 kfree(wrapper);
160 return ret;
161 }
162 EXPORT_SYMBOL_GPL(backport_thermal_zone_device_register);
163
164 void backport_thermal_zone_device_unregister(struct thermal_zone_device *dev)
165 {
166 struct backport_thermal_ops_wrapper *wrapper =
167 container_of(dev->ops, struct backport_thermal_ops_wrapper, ops);
168
169 old_thermal_zone_device_unregister(dev);
170 kfree(wrapper);
171 }
172 EXPORT_SYMBOL_GPL(backport_thermal_zone_device_unregister);
173
174 #endif /* >= 3.8.0 */
175 #endif /* CONFIG_THERMAL */
176
177 static void seq_set_overflow(struct seq_file *m)
178 {
179 m->count = m->size;
180 }
181
182 /* A complete analogue of print_hex_dump() */
183 void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
184 int rowsize, int groupsize, const void *buf, size_t len,
185 bool ascii)
186 {
187 const u8 *ptr = buf;
188 int i, linelen, remaining = len;
189 int ret;
190
191 if (rowsize != 16 && rowsize != 32)
192 rowsize = 16;
193
194 for (i = 0; i < len && !seq_has_overflowed(m); i += rowsize) {
195 linelen = min(remaining, rowsize);
196 remaining -= rowsize;
197
198 switch (prefix_type) {
199 case DUMP_PREFIX_ADDRESS:
200 seq_printf(m, "%s%p: ", prefix_str, ptr + i);
201 break;
202 case DUMP_PREFIX_OFFSET:
203 seq_printf(m, "%s%.8x: ", prefix_str, i);
204 break;
205 default:
206 seq_printf(m, "%s", prefix_str);
207 break;
208 }
209
210 ret = hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
211 m->buf + m->count, m->size - m->count,
212 ascii);
213 if (ret >= m->size - m->count) {
214 seq_set_overflow(m);
215 } else {
216 m->count += ret;
217 seq_putc(m, '\n');
218 }
219 }
220 }
221 EXPORT_SYMBOL_GPL(seq_hex_dump);
222
223 ssize_t strscpy(char *dest, const char *src, size_t count)
224 {
225 long res = 0;
226
227 if (count == 0)
228 return -E2BIG;
229
230 while (count) {
231 char c;
232
233 c = src[res];
234 dest[res] = c;
235 if (!c)
236 return res;
237 res++;
238 count--;
239 }
240
241 /* Hit buffer length without finding a NUL; force NUL-termination. */
242 if (res)
243 dest[res-1] = '\0';
244
245 return -E2BIG;
246 }
247 EXPORT_SYMBOL_GPL(strscpy);