Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/asmc/asmc.c
102379 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2007, 2008 Rui Paulo <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
* POSSIBILITY OF SUCH DAMAGE.
27
*
28
*/
29
30
/*
31
* Driver for Apple's System Management Console (SMC).
32
* SMC can be found on the MacBook, MacBook Pro and Mac Mini.
33
*
34
* Inspired by the Linux applesmc driver.
35
*/
36
37
#include "opt_asmc.h"
38
39
#include <sys/param.h>
40
#include <sys/bus.h>
41
#include <sys/conf.h>
42
#include <sys/endian.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/malloc.h>
46
#include <sys/module.h>
47
#include <sys/mutex.h>
48
#include <sys/sysctl.h>
49
#include <sys/systm.h>
50
#include <sys/taskqueue.h>
51
#include <sys/rman.h>
52
53
#include <machine/resource.h>
54
55
#include <contrib/dev/acpica/include/acpi.h>
56
57
#include <dev/acpica/acpivar.h>
58
#include <dev/asmc/asmcvar.h>
59
60
/*
61
* Device interface.
62
*/
63
static int asmc_probe(device_t dev);
64
static int asmc_attach(device_t dev);
65
static int asmc_detach(device_t dev);
66
static int asmc_resume(device_t dev);
67
68
/*
69
* SMC functions.
70
*/
71
static int asmc_init(device_t dev);
72
static int asmc_command(device_t dev, uint8_t command);
73
static int asmc_wait(device_t dev, uint8_t val);
74
static int asmc_wait_ack(device_t dev, uint8_t val, int amount);
75
static int asmc_key_write(device_t dev, const char *key, uint8_t *buf,
76
uint8_t len);
77
static int asmc_key_read(device_t dev, const char *key, uint8_t *buf,
78
uint8_t);
79
static int asmc_fan_count(device_t dev);
80
static int asmc_fan_getvalue(device_t dev, const char *key, int fan);
81
static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
82
static int asmc_temp_getvalue(device_t dev, const char *key);
83
static int asmc_sms_read(device_t, const char *key, int16_t *val);
84
static void asmc_sms_calibrate(device_t dev);
85
static int asmc_sms_intrfast(void *arg);
86
static void asmc_sms_printintr(device_t dev, uint8_t);
87
static void asmc_sms_task(void *arg, int pending);
88
#ifdef ASMC_DEBUG
89
void asmc_dumpall(device_t);
90
static int asmc_key_dump(device_t, int);
91
#endif
92
93
/*
94
* Model functions.
95
*/
96
static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
97
static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
98
static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
99
static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
100
static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
101
static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
102
static int asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS);
103
static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
104
static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
105
static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
106
static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
107
static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
108
static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
109
static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
110
static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS);
111
112
struct asmc_model {
113
const char *smc_model; /* smbios.system.product env var. */
114
const char *smc_desc; /* driver description */
115
116
/* Helper functions */
117
int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
118
int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
119
int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
120
int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
121
int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
122
int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
123
int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
124
int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
125
int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
126
int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
127
int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
128
int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
129
130
const char *smc_temps[ASMC_TEMP_MAX];
131
const char *smc_tempnames[ASMC_TEMP_MAX];
132
const char *smc_tempdescs[ASMC_TEMP_MAX];
133
};
134
135
static const struct asmc_model *asmc_match(device_t dev);
136
137
#define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \
138
asmc_mb_sysctl_sms_z
139
140
#define ASMC_SMS_FUNCS_DISABLED NULL, NULL, NULL
141
142
#define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \
143
asmc_mb_sysctl_fanminspeed, \
144
asmc_mb_sysctl_fanmaxspeed, \
145
asmc_mb_sysctl_fantargetspeed
146
147
#define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \
148
asmc_mb_sysctl_fanminspeed, \
149
asmc_mb_sysctl_fanmaxspeed, \
150
asmc_mb_sysctl_fantargetspeed
151
152
#define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
153
asmc_mbp_sysctl_light_right, \
154
asmc_mbp_sysctl_light_control
155
156
#define ASMC_LIGHT_FUNCS_10BYTE \
157
asmc_mbp_sysctl_light_left_10byte, \
158
NULL, \
159
asmc_mbp_sysctl_light_control
160
161
#define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL
162
163
static const struct asmc_model asmc_models[] = {
164
{
165
"MacBook1,1", "Apple SMC MacBook Core Duo",
166
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
167
ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
168
},
169
170
{
171
"MacBook2,1", "Apple SMC MacBook Core 2 Duo",
172
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
173
ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
174
},
175
176
{
177
"MacBook3,1", "Apple SMC MacBook Core 2 Duo",
178
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
179
ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
180
},
181
182
{
183
"MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)",
184
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED,
185
ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS
186
},
187
188
{
189
"MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
190
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
191
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
192
},
193
194
{
195
"MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
196
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
197
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
198
},
199
200
{
201
"MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
202
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
203
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
204
},
205
206
{
207
"MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
208
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
209
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
210
},
211
212
{
213
"MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
214
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
215
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
216
},
217
218
{
219
"MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
220
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
221
ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
222
},
223
224
{
225
"MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
226
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
227
ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
228
},
229
230
{
231
"MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
232
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
233
ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS
234
},
235
236
{
237
"MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)",
238
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
239
ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS
240
},
241
242
{
243
"MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)",
244
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
245
ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS
246
},
247
248
{
249
"MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)",
250
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
251
ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS
252
},
253
254
{
255
"MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
256
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
257
ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS
258
},
259
260
{
261
"MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)",
262
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
263
ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS
264
},
265
266
{
267
"MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)",
268
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
269
ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS
270
},
271
272
{
273
"MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
274
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
275
ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS
276
},
277
278
{
279
"MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
280
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
281
ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS
282
},
283
284
{
285
"MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)",
286
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
287
ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS
288
},
289
290
{
291
"MacBookPro11,5",
292
"Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch, AMD GPU)",
293
ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
294
ASMC_MBP115_TEMPS, ASMC_MBP115_TEMPNAMES, ASMC_MBP115_TEMPDESCS
295
},
296
297
/* The Mac Mini has no SMS */
298
{
299
"Macmini1,1", "Apple SMC Mac Mini",
300
ASMC_SMS_FUNCS_DISABLED,
301
ASMC_FAN_FUNCS,
302
ASMC_LIGHT_FUNCS_DISABLED,
303
ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
304
},
305
306
/* The Mac Mini 2,1 has no SMS */
307
{
308
"Macmini2,1", "Apple SMC Mac Mini 2,1",
309
ASMC_SMS_FUNCS_DISABLED,
310
ASMC_FAN_FUNCS,
311
ASMC_LIGHT_FUNCS_DISABLED,
312
ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS
313
},
314
315
/* The Mac Mini 3,1 has no SMS */
316
{
317
"Macmini3,1", "Apple SMC Mac Mini 3,1",
318
ASMC_SMS_FUNCS_DISABLED,
319
ASMC_FAN_FUNCS,
320
ASMC_LIGHT_FUNCS_DISABLED,
321
ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
322
},
323
324
/* The Mac Mini 4,1 (Mid-2010) has no SMS */
325
{
326
"Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)",
327
ASMC_SMS_FUNCS_DISABLED,
328
ASMC_FAN_FUNCS,
329
ASMC_LIGHT_FUNCS_DISABLED,
330
ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS
331
},
332
333
/* The Mac Mini 5,1 has no SMS */
334
/* - same sensors as Mac Mini 5,2 */
335
{
336
"Macmini5,1", "Apple SMC Mac Mini 5,1",
337
ASMC_SMS_FUNCS_DISABLED,
338
ASMC_FAN_FUNCS2,
339
ASMC_LIGHT_FUNCS_DISABLED,
340
ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
341
},
342
343
/* The Mac Mini 5,2 has no SMS */
344
{
345
"Macmini5,2", "Apple SMC Mac Mini 5,2",
346
ASMC_SMS_FUNCS_DISABLED,
347
ASMC_FAN_FUNCS2,
348
ASMC_LIGHT_FUNCS_DISABLED,
349
ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
350
},
351
352
/* The Mac Mini 5,3 has no SMS */
353
/* - same sensors as Mac Mini 5,2 */
354
{
355
"Macmini5,3", "Apple SMC Mac Mini 5,3",
356
ASMC_SMS_FUNCS_DISABLED,
357
ASMC_FAN_FUNCS2,
358
ASMC_LIGHT_FUNCS_DISABLED,
359
ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
360
},
361
362
/* The Mac Mini 6,1 has no SMS */
363
{
364
"Macmini6,1", "Apple SMC Mac Mini 6,1",
365
ASMC_SMS_FUNCS_DISABLED,
366
ASMC_FAN_FUNCS2,
367
ASMC_LIGHT_FUNCS_DISABLED,
368
ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS
369
},
370
371
/* The Mac Mini 6,2 has no SMS */
372
{
373
"Macmini6,2", "Apple SMC Mac Mini 6,2",
374
ASMC_SMS_FUNCS_DISABLED,
375
ASMC_FAN_FUNCS2,
376
ASMC_LIGHT_FUNCS_DISABLED,
377
ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS
378
},
379
380
/* The Mac Mini 7,1 has no SMS */
381
{
382
"Macmini7,1", "Apple SMC Mac Mini 7,1",
383
ASMC_SMS_FUNCS_DISABLED,
384
ASMC_FAN_FUNCS2,
385
ASMC_LIGHT_FUNCS_DISABLED,
386
ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS
387
},
388
389
/* Idem for the Mac Pro "Quad Core" (original) */
390
{
391
"MacPro1,1", "Apple SMC Mac Pro (Quad Core)",
392
ASMC_SMS_FUNCS_DISABLED,
393
ASMC_FAN_FUNCS,
394
ASMC_LIGHT_FUNCS_DISABLED,
395
ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS
396
},
397
398
/* Idem for the Mac Pro (8-core) */
399
{
400
"MacPro2", "Apple SMC Mac Pro (8-core)",
401
ASMC_SMS_FUNCS_DISABLED,
402
ASMC_FAN_FUNCS,
403
ASMC_LIGHT_FUNCS_DISABLED,
404
ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS
405
},
406
407
/* Idem for the MacPro 2010*/
408
{
409
"MacPro5,1", "Apple SMC MacPro (2010)",
410
ASMC_SMS_FUNCS_DISABLED,
411
ASMC_FAN_FUNCS,
412
ASMC_LIGHT_FUNCS_DISABLED,
413
ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
414
},
415
416
/* Idem for the Mac Pro 2013 (cylinder) */
417
{
418
"MacPro6,1", "Apple SMC Mac Pro (2013)",
419
ASMC_SMS_FUNCS_DISABLED,
420
ASMC_FAN_FUNCS2,
421
ASMC_LIGHT_FUNCS_DISABLED,
422
ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS
423
},
424
425
{
426
"MacBookAir1,1", "Apple SMC MacBook Air",
427
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
428
ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
429
},
430
431
{
432
"MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
433
ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
434
ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
435
},
436
437
{
438
"MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)",
439
ASMC_SMS_FUNCS_DISABLED,
440
ASMC_FAN_FUNCS2,
441
ASMC_LIGHT_FUNCS,
442
ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
443
},
444
445
{
446
"MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)",
447
ASMC_SMS_FUNCS_DISABLED,
448
ASMC_FAN_FUNCS2,
449
ASMC_LIGHT_FUNCS,
450
ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
451
},
452
453
{
454
"MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
455
ASMC_SMS_FUNCS_DISABLED,
456
ASMC_FAN_FUNCS2,
457
ASMC_LIGHT_FUNCS,
458
ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
459
},
460
461
{
462
"MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
463
ASMC_SMS_FUNCS_DISABLED,
464
ASMC_FAN_FUNCS2,
465
ASMC_LIGHT_FUNCS,
466
ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
467
},
468
{
469
"MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)",
470
ASMC_SMS_FUNCS_DISABLED,
471
ASMC_FAN_FUNCS2,
472
ASMC_LIGHT_FUNCS_10BYTE,
473
ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
474
},
475
{
476
"MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)",
477
ASMC_SMS_FUNCS_DISABLED,
478
ASMC_FAN_FUNCS2,
479
ASMC_LIGHT_FUNCS_10BYTE,
480
ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
481
},
482
{
483
"MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)",
484
ASMC_SMS_FUNCS_DISABLED,
485
ASMC_FAN_FUNCS2,
486
ASMC_LIGHT_FUNCS,
487
ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
488
},
489
{
490
"MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)",
491
ASMC_SMS_FUNCS_DISABLED,
492
ASMC_FAN_FUNCS2,
493
ASMC_LIGHT_FUNCS,
494
ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
495
},
496
{ NULL, NULL }
497
};
498
499
#undef ASMC_SMS_FUNCS
500
#undef ASMC_SMS_FUNCS_DISABLED
501
#undef ASMC_FAN_FUNCS
502
#undef ASMC_FAN_FUNCS2
503
#undef ASMC_LIGHT_FUNCS
504
505
/*
506
* Driver methods.
507
*/
508
static device_method_t asmc_methods[] = {
509
DEVMETHOD(device_probe, asmc_probe),
510
DEVMETHOD(device_attach, asmc_attach),
511
DEVMETHOD(device_detach, asmc_detach),
512
DEVMETHOD(device_resume, asmc_resume),
513
{ 0, 0 }
514
};
515
516
static driver_t asmc_driver = {
517
"asmc",
518
asmc_methods,
519
sizeof(struct asmc_softc)
520
};
521
522
/*
523
* Debugging
524
*/
525
#define _COMPONENT ACPI_OEM
526
ACPI_MODULE_NAME("ASMC")
527
#ifdef ASMC_DEBUG
528
#define ASMC_DPRINTF(str) device_printf(dev, str)
529
#else
530
#define ASMC_DPRINTF(str)
531
#endif
532
533
/* NB: can't be const */
534
static char *asmc_ids[] = { "APP0001", NULL };
535
536
static unsigned int light_control = 0;
537
538
DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL);
539
MODULE_DEPEND(asmc, acpi, 1, 1, 1);
540
541
static const struct asmc_model *
542
asmc_match(device_t dev)
543
{
544
int i;
545
char *model;
546
547
model = kern_getenv("smbios.system.product");
548
if (model == NULL)
549
return (NULL);
550
551
for (i = 0; asmc_models[i].smc_model; i++) {
552
if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) {
553
freeenv(model);
554
return (&asmc_models[i]);
555
}
556
}
557
freeenv(model);
558
559
return (NULL);
560
}
561
562
static int
563
asmc_probe(device_t dev)
564
{
565
const struct asmc_model *model;
566
int rv;
567
568
if (resource_disabled("asmc", 0))
569
return (ENXIO);
570
rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL);
571
if (rv > 0)
572
return (rv);
573
574
model = asmc_match(dev);
575
if (!model) {
576
device_printf(dev, "model not recognized\n");
577
return (ENXIO);
578
}
579
device_set_desc(dev, model->smc_desc);
580
581
return (rv);
582
}
583
584
static int
585
asmc_attach(device_t dev)
586
{
587
int i, j;
588
int ret;
589
char name[2];
590
struct asmc_softc *sc = device_get_softc(dev);
591
struct sysctl_ctx_list *sysctlctx;
592
struct sysctl_oid *sysctlnode;
593
const struct asmc_model *model;
594
595
sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
596
&sc->sc_rid_port, RF_ACTIVE);
597
if (sc->sc_ioport == NULL) {
598
device_printf(dev, "unable to allocate IO port\n");
599
return (ENOMEM);
600
}
601
602
sysctlctx = device_get_sysctl_ctx(dev);
603
sysctlnode = device_get_sysctl_tree(dev);
604
605
model = asmc_match(dev);
606
607
mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
608
609
sc->sc_model = model;
610
asmc_init(dev);
611
612
/*
613
* dev.asmc.n.fan.* tree.
614
*/
615
sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
616
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
617
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
618
619
for (i = 1; i <= sc->sc_nfan; i++) {
620
j = i - 1;
621
name[0] = '0' + j;
622
name[1] = 0;
623
sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
624
SYSCTL_CHILDREN(sc->sc_fan_tree[0]),
625
OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
626
"Fan Subtree");
627
628
SYSCTL_ADD_PROC(sysctlctx,
629
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
630
OID_AUTO, "id",
631
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
632
dev, j, model->smc_fan_id, "I",
633
"Fan ID");
634
635
SYSCTL_ADD_PROC(sysctlctx,
636
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
637
OID_AUTO, "speed",
638
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
639
dev, j, model->smc_fan_speed, "I",
640
"Fan speed in RPM");
641
642
SYSCTL_ADD_PROC(sysctlctx,
643
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
644
OID_AUTO, "safespeed",
645
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
646
dev, j, model->smc_fan_safespeed, "I",
647
"Fan safe speed in RPM");
648
649
SYSCTL_ADD_PROC(sysctlctx,
650
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
651
OID_AUTO, "minspeed",
652
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
653
dev, j, model->smc_fan_minspeed, "I",
654
"Fan minimum speed in RPM");
655
656
SYSCTL_ADD_PROC(sysctlctx,
657
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
658
OID_AUTO, "maxspeed",
659
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
660
dev, j, model->smc_fan_maxspeed, "I",
661
"Fan maximum speed in RPM");
662
663
SYSCTL_ADD_PROC(sysctlctx,
664
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
665
OID_AUTO, "targetspeed",
666
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
667
dev, j, model->smc_fan_targetspeed, "I",
668
"Fan target speed in RPM");
669
670
SYSCTL_ADD_PROC(sysctlctx,
671
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
672
OID_AUTO, "manual",
673
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
674
dev, j, asmc_mb_sysctl_fanmanual, "I",
675
"Fan manual mode (0=auto, 1=manual)");
676
}
677
678
/*
679
* dev.asmc.n.temp tree.
680
*/
681
sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
682
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
683
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
684
685
for (i = 0; model->smc_temps[i]; i++) {
686
SYSCTL_ADD_PROC(sysctlctx,
687
SYSCTL_CHILDREN(sc->sc_temp_tree),
688
OID_AUTO, model->smc_tempnames[i],
689
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
690
dev, i, asmc_temp_sysctl, "I",
691
model->smc_tempdescs[i]);
692
}
693
694
/*
695
* dev.asmc.n.light
696
*/
697
if (model->smc_light_left) {
698
sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
699
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
700
CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
701
"Keyboard backlight sensors");
702
703
SYSCTL_ADD_PROC(sysctlctx,
704
SYSCTL_CHILDREN(sc->sc_light_tree),
705
OID_AUTO, "left",
706
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
707
dev, 0, model->smc_light_left, "I",
708
"Keyboard backlight left sensor");
709
710
SYSCTL_ADD_PROC(sysctlctx,
711
SYSCTL_CHILDREN(sc->sc_light_tree),
712
OID_AUTO, "right",
713
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
714
dev, 0, model->smc_light_right, "I",
715
"Keyboard backlight right sensor");
716
717
SYSCTL_ADD_PROC(sysctlctx,
718
SYSCTL_CHILDREN(sc->sc_light_tree),
719
OID_AUTO, "control",
720
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY |
721
CTLFLAG_NEEDGIANT, dev, 0,
722
model->smc_light_control, "I",
723
"Keyboard backlight brightness control");
724
}
725
726
if (model->smc_sms_x == NULL)
727
goto nosms;
728
729
/*
730
* dev.asmc.n.sms tree.
731
*/
732
sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
733
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
734
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
735
736
SYSCTL_ADD_PROC(sysctlctx,
737
SYSCTL_CHILDREN(sc->sc_sms_tree),
738
OID_AUTO, "x",
739
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
740
dev, 0, model->smc_sms_x, "I",
741
"Sudden Motion Sensor X value");
742
743
SYSCTL_ADD_PROC(sysctlctx,
744
SYSCTL_CHILDREN(sc->sc_sms_tree),
745
OID_AUTO, "y",
746
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
747
dev, 0, model->smc_sms_y, "I",
748
"Sudden Motion Sensor Y value");
749
750
SYSCTL_ADD_PROC(sysctlctx,
751
SYSCTL_CHILDREN(sc->sc_sms_tree),
752
OID_AUTO, "z",
753
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
754
dev, 0, model->smc_sms_z, "I",
755
"Sudden Motion Sensor Z value");
756
757
/*
758
* Need a taskqueue to send devctl_notify() events
759
* when the SMS interrupt us.
760
*
761
* PI_REALTIME is used due to the sensitivity of the
762
* interrupt. An interrupt from the SMS means that the
763
* disk heads should be turned off as quickly as possible.
764
*
765
* We only need to do this for the non INTR_FILTER case.
766
*/
767
sc->sc_sms_tq = NULL;
768
TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
769
sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
770
taskqueue_thread_enqueue, &sc->sc_sms_tq);
771
taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
772
device_get_nameunit(dev));
773
/*
774
* Allocate an IRQ for the SMS.
775
*/
776
sc->sc_rid_irq = 0;
777
sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq,
778
RF_ACTIVE);
779
if (sc->sc_irq == NULL) {
780
device_printf(dev, "unable to allocate IRQ resource\n");
781
ret = ENXIO;
782
goto err2;
783
}
784
785
ret = bus_setup_intr(dev, sc->sc_irq,
786
INTR_TYPE_MISC | INTR_MPSAFE,
787
asmc_sms_intrfast, NULL,
788
dev, &sc->sc_cookie);
789
790
if (ret) {
791
device_printf(dev, "unable to setup SMS IRQ\n");
792
goto err1;
793
}
794
nosms:
795
return (0);
796
err1:
797
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq);
798
err2:
799
bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
800
sc->sc_ioport);
801
mtx_destroy(&sc->sc_mtx);
802
if (sc->sc_sms_tq)
803
taskqueue_free(sc->sc_sms_tq);
804
805
return (ret);
806
}
807
808
static int
809
asmc_detach(device_t dev)
810
{
811
struct asmc_softc *sc = device_get_softc(dev);
812
813
if (sc->sc_sms_tq) {
814
taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
815
taskqueue_free(sc->sc_sms_tq);
816
}
817
if (sc->sc_cookie)
818
bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
819
if (sc->sc_irq)
820
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
821
sc->sc_irq);
822
if (sc->sc_ioport)
823
bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
824
sc->sc_ioport);
825
mtx_destroy(&sc->sc_mtx);
826
827
return (0);
828
}
829
830
static int
831
asmc_resume(device_t dev)
832
{
833
uint8_t buf[2];
834
835
buf[0] = light_control;
836
buf[1] = 0x00;
837
asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
838
839
return (0);
840
}
841
842
#ifdef ASMC_DEBUG
843
void
844
asmc_dumpall(device_t dev)
845
{
846
struct asmc_softc *sc = device_get_softc(dev);
847
int i;
848
849
if (sc->sc_nkeys == 0) {
850
device_printf(dev, "asmc_dumpall: key count not available\n");
851
return;
852
}
853
854
device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys);
855
for (i = 0; i < sc->sc_nkeys; i++)
856
asmc_key_dump(dev, i);
857
}
858
#endif
859
860
static int
861
asmc_init(device_t dev)
862
{
863
struct asmc_softc *sc = device_get_softc(dev);
864
int i, error = 1;
865
uint8_t buf[4];
866
867
if (sc->sc_model->smc_sms_x == NULL)
868
goto nosms;
869
870
/*
871
* We are ready to receive interrupts from the SMS.
872
*/
873
buf[0] = 0x01;
874
ASMC_DPRINTF(("intok key\n"));
875
asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
876
DELAY(50);
877
878
/*
879
* Initiate the polling intervals.
880
*/
881
buf[0] = 20; /* msecs */
882
ASMC_DPRINTF(("low int key\n"));
883
asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
884
DELAY(200);
885
886
buf[0] = 20; /* msecs */
887
ASMC_DPRINTF(("high int key\n"));
888
asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
889
DELAY(200);
890
891
buf[0] = 0x00;
892
buf[1] = 0x60;
893
ASMC_DPRINTF(("sms low key\n"));
894
asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
895
DELAY(200);
896
897
buf[0] = 0x01;
898
buf[1] = 0xc0;
899
ASMC_DPRINTF(("sms high key\n"));
900
asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
901
DELAY(200);
902
903
/*
904
* I'm not sure what this key does, but it seems to be
905
* required.
906
*/
907
buf[0] = 0x01;
908
ASMC_DPRINTF(("sms flag key\n"));
909
asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
910
DELAY(100);
911
912
sc->sc_sms_intr_works = 0;
913
914
/*
915
* Retry SMS initialization 1000 times
916
* (takes approx. 2 seconds in worst case)
917
*/
918
for (i = 0; i < 1000; i++) {
919
if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
920
(buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
921
error = 0;
922
sc->sc_sms_intr_works = 1;
923
goto out;
924
}
925
buf[0] = ASMC_SMS_INIT1;
926
buf[1] = ASMC_SMS_INIT2;
927
ASMC_DPRINTF(("sms key\n"));
928
asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
929
DELAY(50);
930
}
931
device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
932
933
out:
934
asmc_sms_calibrate(dev);
935
nosms:
936
sc->sc_nfan = asmc_fan_count(dev);
937
if (sc->sc_nfan > ASMC_MAXFANS) {
938
device_printf(dev, "more than %d fans were detected. Please "
939
"report this.\n", ASMC_MAXFANS);
940
sc->sc_nfan = ASMC_MAXFANS;
941
}
942
943
/*
944
* Read and cache the number of SMC keys (32 bit buffer)
945
*/
946
if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) {
947
sc->sc_nkeys = be32dec(buf);
948
if (bootverbose)
949
device_printf(dev, "number of keys: %d\n",
950
sc->sc_nkeys);
951
} else {
952
sc->sc_nkeys = 0;
953
}
954
955
#ifdef ASMC_DEBUG
956
asmc_dumpall(dev);
957
#endif
958
959
return (error);
960
}
961
962
/*
963
* We need to make sure that the SMC acks the byte sent.
964
* Just wait up to (amount * 10) ms.
965
*/
966
static int
967
asmc_wait_ack(device_t dev, uint8_t val, int amount)
968
{
969
struct asmc_softc *sc = device_get_softc(dev);
970
u_int i;
971
972
val = val & ASMC_STATUS_MASK;
973
974
for (i = 0; i < amount; i++) {
975
if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
976
return (0);
977
DELAY(10);
978
}
979
980
return (1);
981
}
982
983
/*
984
* We need to make sure that the SMC acks the byte sent.
985
* Just wait up to 100 ms.
986
*/
987
static int
988
asmc_wait(device_t dev, uint8_t val)
989
{
990
#ifdef ASMC_DEBUG
991
struct asmc_softc *sc;
992
#endif
993
994
if (asmc_wait_ack(dev, val, 1000) == 0)
995
return (0);
996
997
#ifdef ASMC_DEBUG
998
sc = device_get_softc(dev);
999
#endif
1000
val = val & ASMC_STATUS_MASK;
1001
1002
#ifdef ASMC_DEBUG
1003
device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
1004
ASMC_CMDPORT_READ(sc));
1005
#endif
1006
return (1);
1007
}
1008
1009
/*
1010
* Send the given command, retrying up to 10 times if
1011
* the acknowledgement fails.
1012
*/
1013
static int
1014
asmc_command(device_t dev, uint8_t command)
1015
{
1016
int i;
1017
struct asmc_softc *sc = device_get_softc(dev);
1018
1019
for (i = 0; i < 10; i++) {
1020
ASMC_CMDPORT_WRITE(sc, command);
1021
if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
1022
return (0);
1023
}
1024
}
1025
1026
#ifdef ASMC_DEBUG
1027
device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
1028
ASMC_CMDPORT_READ(sc));
1029
#endif
1030
return (1);
1031
}
1032
1033
static int
1034
asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1035
{
1036
int i, error = 1, try = 0;
1037
struct asmc_softc *sc = device_get_softc(dev);
1038
1039
mtx_lock_spin(&sc->sc_mtx);
1040
1041
begin:
1042
if (asmc_command(dev, ASMC_CMDREAD))
1043
goto out;
1044
1045
for (i = 0; i < 4; i++) {
1046
ASMC_DATAPORT_WRITE(sc, key[i]);
1047
if (asmc_wait(dev, 0x04))
1048
goto out;
1049
}
1050
1051
ASMC_DATAPORT_WRITE(sc, len);
1052
1053
for (i = 0; i < len; i++) {
1054
if (asmc_wait(dev, 0x05))
1055
goto out;
1056
buf[i] = ASMC_DATAPORT_READ(sc);
1057
}
1058
1059
error = 0;
1060
out:
1061
if (error) {
1062
if (++try < 10)
1063
goto begin;
1064
device_printf(dev, "%s for key %s failed %d times, giving up\n",
1065
__func__, key, try);
1066
}
1067
1068
mtx_unlock_spin(&sc->sc_mtx);
1069
1070
return (error);
1071
}
1072
1073
#ifdef ASMC_DEBUG
1074
static int
1075
asmc_key_dump(device_t dev, int number)
1076
{
1077
struct asmc_softc *sc = device_get_softc(dev);
1078
char key[5] = { 0 };
1079
char type[7] = { 0 };
1080
uint8_t index[4];
1081
uint8_t v[32];
1082
uint8_t maxlen;
1083
int i, error = 1, try = 0;
1084
1085
mtx_lock_spin(&sc->sc_mtx);
1086
1087
index[0] = (number >> 24) & 0xff;
1088
index[1] = (number >> 16) & 0xff;
1089
index[2] = (number >> 8) & 0xff;
1090
index[3] = (number) & 0xff;
1091
1092
begin:
1093
if (asmc_command(dev, 0x12))
1094
goto out;
1095
1096
for (i = 0; i < 4; i++) {
1097
ASMC_DATAPORT_WRITE(sc, index[i]);
1098
if (asmc_wait(dev, 0x04))
1099
goto out;
1100
}
1101
1102
ASMC_DATAPORT_WRITE(sc, 4);
1103
1104
for (i = 0; i < 4; i++) {
1105
if (asmc_wait(dev, 0x05))
1106
goto out;
1107
key[i] = ASMC_DATAPORT_READ(sc);
1108
}
1109
1110
/* get type */
1111
if (asmc_command(dev, 0x13))
1112
goto out;
1113
1114
for (i = 0; i < 4; i++) {
1115
ASMC_DATAPORT_WRITE(sc, key[i]);
1116
if (asmc_wait(dev, 0x04))
1117
goto out;
1118
}
1119
1120
ASMC_DATAPORT_WRITE(sc, 6);
1121
1122
for (i = 0; i < 6; i++) {
1123
if (asmc_wait(dev, 0x05))
1124
goto out;
1125
type[i] = ASMC_DATAPORT_READ(sc);
1126
}
1127
1128
error = 0;
1129
out:
1130
if (error) {
1131
if (++try < 10)
1132
goto begin;
1133
device_printf(dev, "%s for key %s failed %d times, giving up\n",
1134
__func__, key, try);
1135
mtx_unlock_spin(&sc->sc_mtx);
1136
} else {
1137
char buf[1024];
1138
char buf2[8];
1139
mtx_unlock_spin(&sc->sc_mtx);
1140
maxlen = type[0];
1141
type[0] = ' ';
1142
type[5] = 0;
1143
if (maxlen > sizeof(v)) {
1144
device_printf(dev,
1145
"WARNING: cropping maxlen from %d to %zu\n",
1146
maxlen, sizeof(v));
1147
maxlen = sizeof(v);
1148
}
1149
for (i = 0; i < sizeof(v); i++) {
1150
v[i] = 0;
1151
}
1152
asmc_key_read(dev, key, v, maxlen);
1153
snprintf(buf, sizeof(buf), "key %d is: %s, type %s "
1154
"(len %d), data", number, key, type, maxlen);
1155
for (i = 0; i < maxlen; i++) {
1156
snprintf(buf2, sizeof(buf2), " %02x", v[i]);
1157
strlcat(buf, buf2, sizeof(buf));
1158
}
1159
strlcat(buf, " \n", sizeof(buf));
1160
device_printf(dev, "%s", buf);
1161
}
1162
1163
return (error);
1164
}
1165
#endif
1166
1167
static int
1168
asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1169
{
1170
int i, error = -1, try = 0;
1171
struct asmc_softc *sc = device_get_softc(dev);
1172
1173
mtx_lock_spin(&sc->sc_mtx);
1174
1175
begin:
1176
ASMC_DPRINTF(("cmd port: cmd write\n"));
1177
if (asmc_command(dev, ASMC_CMDWRITE))
1178
goto out;
1179
1180
ASMC_DPRINTF(("data port: key\n"));
1181
for (i = 0; i < 4; i++) {
1182
ASMC_DATAPORT_WRITE(sc, key[i]);
1183
if (asmc_wait(dev, 0x04))
1184
goto out;
1185
}
1186
ASMC_DPRINTF(("data port: length\n"));
1187
ASMC_DATAPORT_WRITE(sc, len);
1188
1189
ASMC_DPRINTF(("data port: buffer\n"));
1190
for (i = 0; i < len; i++) {
1191
if (asmc_wait(dev, 0x04))
1192
goto out;
1193
ASMC_DATAPORT_WRITE(sc, buf[i]);
1194
}
1195
1196
error = 0;
1197
out:
1198
if (error) {
1199
if (++try < 10)
1200
goto begin;
1201
device_printf(dev, "%s for key %s failed %d times, giving up\n",
1202
__func__, key, try);
1203
}
1204
1205
mtx_unlock_spin(&sc->sc_mtx);
1206
1207
return (error);
1208
}
1209
1210
/*
1211
* Fan control functions.
1212
*/
1213
static int
1214
asmc_fan_count(device_t dev)
1215
{
1216
uint8_t buf[1];
1217
1218
if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) != 0)
1219
return (-1);
1220
1221
return (buf[0]);
1222
}
1223
1224
static int
1225
asmc_fan_getvalue(device_t dev, const char *key, int fan)
1226
{
1227
int speed;
1228
uint8_t buf[2];
1229
char fankey[5];
1230
1231
snprintf(fankey, sizeof(fankey), key, fan);
1232
if (asmc_key_read(dev, fankey, buf, sizeof buf) != 0)
1233
return (-1);
1234
speed = (buf[0] << 6) | (buf[1] >> 2);
1235
1236
return (speed);
1237
}
1238
1239
static char *
1240
asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf,
1241
uint8_t buflen)
1242
{
1243
char fankey[5];
1244
char *desc;
1245
1246
snprintf(fankey, sizeof(fankey), key, fan);
1247
if (asmc_key_read(dev, fankey, buf, buflen) != 0)
1248
return (NULL);
1249
desc = buf + 4;
1250
1251
return (desc);
1252
}
1253
1254
static int
1255
asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
1256
{
1257
uint8_t buf[2];
1258
char fankey[5];
1259
1260
speed *= 4;
1261
1262
buf[0] = speed >> 8;
1263
buf[1] = speed;
1264
1265
snprintf(fankey, sizeof(fankey), key, fan);
1266
if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0)
1267
return (-1);
1268
1269
return (0);
1270
}
1271
1272
static int
1273
asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
1274
{
1275
device_t dev = (device_t)arg1;
1276
int fan = arg2;
1277
int error;
1278
int32_t v;
1279
1280
v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
1281
error = sysctl_handle_int(oidp, &v, 0, req);
1282
1283
return (error);
1284
}
1285
1286
static int
1287
asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
1288
{
1289
uint8_t buf[16];
1290
device_t dev = (device_t)arg1;
1291
int fan = arg2;
1292
int error = true;
1293
char *desc;
1294
1295
desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
1296
1297
if (desc != NULL)
1298
error = sysctl_handle_string(oidp, desc, 0, req);
1299
1300
return (error);
1301
}
1302
1303
static int
1304
asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
1305
{
1306
device_t dev = (device_t)arg1;
1307
int fan = arg2;
1308
int error;
1309
int32_t v;
1310
1311
v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
1312
error = sysctl_handle_int(oidp, &v, 0, req);
1313
1314
return (error);
1315
}
1316
1317
static int
1318
asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
1319
{
1320
device_t dev = (device_t)arg1;
1321
int fan = arg2;
1322
int error;
1323
int32_t v;
1324
1325
v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
1326
error = sysctl_handle_int(oidp, &v, 0, req);
1327
1328
if (error == 0 && req->newptr != NULL) {
1329
unsigned int newspeed = v;
1330
asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
1331
}
1332
1333
return (error);
1334
}
1335
1336
static int
1337
asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
1338
{
1339
device_t dev = (device_t)arg1;
1340
int fan = arg2;
1341
int error;
1342
int32_t v;
1343
1344
v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
1345
error = sysctl_handle_int(oidp, &v, 0, req);
1346
1347
if (error == 0 && req->newptr != NULL) {
1348
unsigned int newspeed = v;
1349
asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
1350
}
1351
1352
return (error);
1353
}
1354
1355
static int
1356
asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
1357
{
1358
device_t dev = (device_t)arg1;
1359
int fan = arg2;
1360
int error;
1361
int32_t v;
1362
1363
v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
1364
error = sysctl_handle_int(oidp, &v, 0, req);
1365
1366
if (error == 0 && req->newptr != NULL) {
1367
unsigned int newspeed = v;
1368
asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
1369
}
1370
1371
return (error);
1372
}
1373
1374
static int
1375
asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)
1376
{
1377
device_t dev = (device_t)arg1;
1378
int fan = arg2;
1379
int error;
1380
int32_t v;
1381
uint8_t buf[2];
1382
uint16_t val;
1383
1384
/* Read current FS! bitmask (asmc_key_read locks internally) */
1385
error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf));
1386
if (error != 0)
1387
return (error);
1388
1389
/* Extract manual bit for this fan (big-endian) */
1390
val = (buf[0] << 8) | buf[1];
1391
v = (val >> fan) & 0x01;
1392
1393
/* Let sysctl handle the value */
1394
error = sysctl_handle_int(oidp, &v, 0, req);
1395
1396
if (error == 0 && req->newptr != NULL) {
1397
/* Validate input (0 = auto, 1 = manual) */
1398
if (v != 0 && v != 1)
1399
return (EINVAL);
1400
/* Read-modify-write of FS! bitmask */
1401
error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf,
1402
sizeof(buf));
1403
if (error == 0) {
1404
val = (buf[0] << 8) | buf[1];
1405
1406
/* Modify single bit */
1407
if (v)
1408
val |= (1 << fan); /* Set to manual */
1409
else
1410
val &= ~(1 << fan); /* Set to auto */
1411
1412
/* Write back */
1413
buf[0] = val >> 8;
1414
buf[1] = val & 0xff;
1415
error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf,
1416
sizeof(buf));
1417
}
1418
}
1419
1420
return (error);
1421
}
1422
1423
/*
1424
* Temperature functions.
1425
*/
1426
static int
1427
asmc_temp_getvalue(device_t dev, const char *key)
1428
{
1429
uint8_t buf[2];
1430
1431
/*
1432
* Check for invalid temperatures.
1433
*/
1434
if (asmc_key_read(dev, key, buf, sizeof buf) != 0)
1435
return (-1);
1436
1437
return (buf[0]);
1438
}
1439
1440
static int
1441
asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
1442
{
1443
device_t dev = (device_t)arg1;
1444
struct asmc_softc *sc = device_get_softc(dev);
1445
int error, val;
1446
1447
val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
1448
error = sysctl_handle_int(oidp, &val, 0, req);
1449
1450
return (error);
1451
}
1452
1453
/*
1454
* Sudden Motion Sensor functions.
1455
*/
1456
static int
1457
asmc_sms_read(device_t dev, const char *key, int16_t *val)
1458
{
1459
uint8_t buf[2];
1460
int error;
1461
1462
/* no need to do locking here as asmc_key_read() already does it */
1463
switch (key[3]) {
1464
case 'X':
1465
case 'Y':
1466
case 'Z':
1467
error = asmc_key_read(dev, key, buf, sizeof buf);
1468
break;
1469
default:
1470
device_printf(dev, "%s called with invalid argument %s\n",
1471
__func__, key);
1472
error = 1;
1473
goto out;
1474
}
1475
*val = ((int16_t)buf[0] << 8) | buf[1];
1476
out:
1477
return (error);
1478
}
1479
1480
static void
1481
asmc_sms_calibrate(device_t dev)
1482
{
1483
struct asmc_softc *sc = device_get_softc(dev);
1484
1485
asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
1486
asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
1487
asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
1488
}
1489
1490
static int
1491
asmc_sms_intrfast(void *arg)
1492
{
1493
uint8_t type;
1494
device_t dev = (device_t)arg;
1495
struct asmc_softc *sc = device_get_softc(dev);
1496
if (!sc->sc_sms_intr_works)
1497
return (FILTER_HANDLED);
1498
1499
mtx_lock_spin(&sc->sc_mtx);
1500
type = ASMC_INTPORT_READ(sc);
1501
mtx_unlock_spin(&sc->sc_mtx);
1502
1503
sc->sc_sms_intrtype = type;
1504
asmc_sms_printintr(dev, type);
1505
1506
taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
1507
return (FILTER_HANDLED);
1508
}
1509
1510
static void
1511
asmc_sms_printintr(device_t dev, uint8_t type)
1512
{
1513
struct asmc_softc *sc = device_get_softc(dev);
1514
1515
switch (type) {
1516
case ASMC_SMS_INTFF:
1517
device_printf(dev, "WARNING: possible free fall!\n");
1518
break;
1519
case ASMC_SMS_INTHA:
1520
device_printf(dev, "WARNING: high acceleration detected!\n");
1521
break;
1522
case ASMC_SMS_INTSH:
1523
device_printf(dev, "WARNING: possible shock!\n");
1524
break;
1525
case ASMC_ALSL_INT2A:
1526
/*
1527
* This suppresses console and log messages for the ambient
1528
* light sensor for models known to generate this interrupt.
1529
*/
1530
if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 ||
1531
strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0)
1532
break;
1533
/* FALLTHROUGH */
1534
default:
1535
device_printf(dev, "unknown interrupt: 0x%x\n", type);
1536
}
1537
}
1538
1539
static void
1540
asmc_sms_task(void *arg, int pending)
1541
{
1542
struct asmc_softc *sc = (struct asmc_softc *)arg;
1543
char notify[16];
1544
int type;
1545
1546
switch (sc->sc_sms_intrtype) {
1547
case ASMC_SMS_INTFF:
1548
type = 2;
1549
break;
1550
case ASMC_SMS_INTHA:
1551
type = 1;
1552
break;
1553
case ASMC_SMS_INTSH:
1554
type = 0;
1555
break;
1556
default:
1557
type = 255;
1558
}
1559
1560
snprintf(notify, sizeof(notify), " notify=0x%x", type);
1561
devctl_notify("ACPI", "asmc", "SMS", notify);
1562
}
1563
1564
static int
1565
asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
1566
{
1567
device_t dev = (device_t)arg1;
1568
int error;
1569
int16_t val;
1570
int32_t v;
1571
1572
asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
1573
v = (int32_t)val;
1574
error = sysctl_handle_int(oidp, &v, 0, req);
1575
1576
return (error);
1577
}
1578
1579
static int
1580
asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
1581
{
1582
device_t dev = (device_t)arg1;
1583
int error;
1584
int16_t val;
1585
int32_t v;
1586
1587
asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
1588
v = (int32_t)val;
1589
error = sysctl_handle_int(oidp, &v, 0, req);
1590
1591
return (error);
1592
}
1593
1594
static int
1595
asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
1596
{
1597
device_t dev = (device_t)arg1;
1598
int error;
1599
int16_t val;
1600
int32_t v;
1601
1602
asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
1603
v = (int32_t)val;
1604
error = sysctl_handle_int(oidp, &v, 0, req);
1605
1606
return (error);
1607
}
1608
1609
static int
1610
asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
1611
{
1612
device_t dev = (device_t)arg1;
1613
uint8_t buf[6];
1614
int error;
1615
int32_t v;
1616
1617
asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
1618
v = buf[2];
1619
error = sysctl_handle_int(oidp, &v, 0, req);
1620
1621
return (error);
1622
}
1623
1624
static int
1625
asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
1626
{
1627
device_t dev = (device_t)arg1;
1628
uint8_t buf[6];
1629
int error;
1630
int32_t v;
1631
1632
asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf);
1633
v = buf[2];
1634
error = sysctl_handle_int(oidp, &v, 0, req);
1635
1636
return (error);
1637
}
1638
1639
static int
1640
asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
1641
{
1642
device_t dev = (device_t)arg1;
1643
uint8_t buf[2];
1644
int error;
1645
int v;
1646
1647
v = light_control;
1648
error = sysctl_handle_int(oidp, &v, 0, req);
1649
1650
if (error == 0 && req->newptr != NULL) {
1651
if (v < 0 || v > 255)
1652
return (EINVAL);
1653
light_control = v;
1654
buf[0] = light_control;
1655
buf[1] = 0x00;
1656
asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
1657
}
1658
return (error);
1659
}
1660
1661
static int
1662
asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
1663
{
1664
device_t dev = (device_t)arg1;
1665
uint8_t buf[10];
1666
int error;
1667
uint32_t v;
1668
1669
asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
1670
1671
/*
1672
* This seems to be a 32 bit big endian value from buf[6] -> buf[9].
1673
*
1674
* Extract it out manually here, then shift/clamp it.
1675
*/
1676
v = be32dec(&buf[6]);
1677
1678
/*
1679
* Shift out, clamp at 255; that way it looks like the
1680
* earlier SMC firmware version responses.
1681
*/
1682
v = v >> 8;
1683
if (v > 255)
1684
v = 255;
1685
1686
error = sysctl_handle_int(oidp, &v, 0, req);
1687
1688
return (error);
1689
}
1690
1691