FreeBSD kernel IICBUS device code
acpi_iicbus.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/bus.h>
33#include <sys/endian.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37#include <sys/rman.h>
38#include <sys/sbuf.h>
39
40#include <machine/resource.h>
41
42#include <contrib/dev/acpica/include/acpi.h>
43#include <contrib/dev/acpica/include/accommon.h>
44#include <contrib/dev/acpica/include/amlcode.h>
45#include <dev/acpica/acpivar.h>
46
47#include <dev/iicbus/iiconf.h>
48#include <dev/iicbus/iicbus.h>
49
50#define ACPI_IICBUS_LOCAL_BUFSIZE 32 /* Fits max SMBUS block size */
51
52/*
53 * Make a copy of ACPI_RESOURCE_I2C_SERIALBUS type and replace "pointer to ACPI
54 * object name string" field with pointer to ACPI object itself.
55 * This saves us extra strdup()/free() pair on acpi_iicbus_get_i2cres call.
56 */
57typedef ACPI_RESOURCE_I2C_SERIALBUS ACPI_IICBUS_RESOURCE_I2C_SERIALBUS;
58#define ResourceSource_Handle ResourceSource.StringPtr
59
60/* Hooks for the ACPI CA debugging infrastructure. */
61#define _COMPONENT ACPI_BUS
62ACPI_MODULE_NAME("IIC")
63
64struct gsb_buffer {
65 UINT8 status;
66 UINT8 len;
67 UINT8 data[];
69
72 ACPI_CONNECTION_INFO space_handler_info;
74};
75
78 ACPI_HANDLE handle;
79};
80
81static int install_space_handler = 0;
82TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler);
83
84static inline bool
86{
87
88 return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
89 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_I2C);
90}
91
92/*
93 * IICBUS Address space handler
94 */
95static int
96acpi_iicbus_sendb(device_t dev, u_char slave, char byte)
97{
98 struct iic_msg msgs[] = {
99 { slave, IIC_M_WR, 1, &byte },
100 };
101
102 return (iicbus_transfer(dev, msgs, nitems(msgs)));
103}
104
105static int
106acpi_iicbus_recvb(device_t dev, u_char slave, char *byte)
107{
108 char buf;
109 struct iic_msg msgs[] = {
110 { slave, IIC_M_RD, 1, &buf },
111 };
112 int error;
113
114 error = iicbus_transfer(dev, msgs, nitems(msgs));
115 if (error == 0)
116 *byte = buf;
117
118 return (error);
119}
120
121static int
122acpi_iicbus_write(device_t dev, u_char slave, char cmd, void *buf,
123 uint16_t buflen)
124{
125 struct iic_msg msgs[] = {
126 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
127 { slave, IIC_M_WR | IIC_M_NOSTART, buflen, buf },
128 };
129
130 return (iicbus_transfer(dev, msgs, nitems(msgs)));
131}
132
133static int
134acpi_iicbus_read(device_t dev, u_char slave, char cmd, void *buf,
135 uint16_t buflen)
136{
137 uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE];
138 struct iic_msg msgs[] = {
139 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
140 { slave, IIC_M_RD, buflen, NULL },
141 };
142 int error;
143
144 if (buflen <= sizeof(local_buffer))
145 msgs[1].buf = local_buffer;
146 else
147 msgs[1].buf = malloc(buflen, M_DEVBUF, M_WAITOK);
148 error = iicbus_transfer(dev, msgs, nitems(msgs));
149 if (error == 0)
150 memcpy(buf, msgs[1].buf, buflen);
151 if (msgs[1].buf != local_buffer)
152 free(msgs[1].buf, M_DEVBUF);
153
154 return (error);
155}
156
157static int
158acpi_iicbus_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
159{
160 uint8_t bytes[2] = { cmd, count };
161 struct iic_msg msgs[] = {
162 { slave, IIC_M_WR | IIC_M_NOSTOP, nitems(bytes), bytes },
163 { slave, IIC_M_WR | IIC_M_NOSTART, count, buf },
164 };
165
166 if (count == 0)
167 return (errno2iic(EINVAL));
168
169 return (iicbus_transfer(dev, msgs, nitems(msgs)));
170}
171
172static int
173acpi_iicbus_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
174{
175 uint8_t local_buffer[ACPI_IICBUS_LOCAL_BUFSIZE];
176 u_char len;
177 struct iic_msg msgs[] = {
178 { slave, IIC_M_WR | IIC_M_NOSTOP, 1, &cmd },
179 { slave, IIC_M_RD | IIC_M_NOSTOP, 1, &len },
180 };
181 struct iic_msg block_msg[] = {
182 { slave, IIC_M_RD | IIC_M_NOSTART, 0, NULL },
183 };
184 device_t parent = device_get_parent(dev);
185 int error;
186
187 /* Have to do this because the command is split in two transfers. */
188 error = iicbus_request_bus(parent, dev, IIC_WAIT);
189 if (error == 0)
190 error = iicbus_transfer(dev, msgs, nitems(msgs));
191 if (error == 0) {
192 /*
193 * If the slave offers an empty reply,
194 * read one byte to generate the stop or abort.
195 */
196 if (len == 0)
197 block_msg[0].len = 1;
198 else
199 block_msg[0].len = len;
200 if (len <= sizeof(local_buffer))
201 block_msg[0].buf = local_buffer;
202 else
203 block_msg[0].buf = malloc(len, M_DEVBUF, M_WAITOK);
204 error = iicbus_transfer(dev, block_msg, nitems(block_msg));
205 if (len == 0)
206 error = errno2iic(EBADMSG);
207 if (error == 0) {
208 *count = len;
209 memcpy(buf, block_msg[0].buf, len);
210 }
211 if (block_msg[0].buf != local_buffer)
212 free(block_msg[0].buf, M_DEVBUF);
213 }
214 (void)iicbus_release_bus(parent, dev);
215 return (error);
216}
217
218static ACPI_STATUS
219acpi_iicbus_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address,
220 UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext)
221{
222 struct gsb_buffer *gsb;
223 struct acpi_iicbus_softc *sc;
224 device_t dev;
225 ACPI_CONNECTION_INFO *info;
226 ACPI_RESOURCE_I2C_SERIALBUS *sb;
227 ACPI_RESOURCE *res;
228 ACPI_STATUS s;
229 int val;
230
231 gsb = (struct gsb_buffer *)Value;
232 if (gsb == NULL)
233 return (AE_BAD_PARAMETER);
234
235 info = HandlerContext;
236 s = AcpiBufferToResource(info->Connection, info->Length, &res);
237 if (ACPI_FAILURE(s))
238 return (s);
239
241 s = AE_BAD_PARAMETER;
242 goto err;
243 }
244
245 sb = &res->Data.I2cSerialBus;
246
247 /* XXX Ignore 10bit addressing for now */
248 if (sb->AccessMode == ACPI_I2C_10BIT_MODE) {
249 s = AE_BAD_PARAMETER;
250 goto err;
251 }
252
253#define AML_FIELD_ATTRIB_MASK 0x0F
254#define AML_FIELD_ATTRIO(attr, io) (((attr) << 16) | (io))
255
256 Function &= AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_MASK, ACPI_IO_MASK);
257 sc = __containerof(info, struct acpi_iicbus_softc, space_handler_info);
258 dev = sc->super_sc.dev;
259
260 switch (Function) {
261 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_READ):
262 val = acpi_iicbus_recvb(dev, sb->SlaveAddress, gsb->data);
263 break;
264
265 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_SEND_RECEIVE, ACPI_WRITE):
266 val = acpi_iicbus_sendb(dev, sb->SlaveAddress, gsb->data[0]);
267 break;
268
269 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_READ):
270 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
271 gsb->data, 1);
272 break;
273
274 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTE, ACPI_WRITE):
275 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
276 gsb->data, 1);
277 break;
278
279 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_READ):
280 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
281 gsb->data, 2);
282 break;
283
284 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_WORD, ACPI_WRITE):
285 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
286 gsb->data, 2);
287 break;
288
289 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_READ):
290 val = acpi_iicbus_bread(dev, sb->SlaveAddress, Address,
291 &gsb->len, gsb->data);
292 break;
293
294 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BLOCK, ACPI_WRITE):
295 val = acpi_iicbus_bwrite(dev, sb->SlaveAddress, Address,
296 gsb->len, gsb->data);
297 break;
298
299 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_READ):
300 val = acpi_iicbus_read(dev, sb->SlaveAddress, Address,
301 gsb->data, info->AccessLength);
302 break;
303
304 case AML_FIELD_ATTRIO(AML_FIELD_ATTRIB_BYTES, ACPI_WRITE):
305 val = acpi_iicbus_write(dev, sb->SlaveAddress, Address,
306 gsb->data, info->AccessLength);
307 break;
308
309 default:
310 device_printf(dev, "protocol(0x%04x) is not supported.\n",
311 Function);
312 s = AE_BAD_PARAMETER;
313 goto err;
314 }
315
316 gsb->status = val;
317
318err:
319 ACPI_FREE(res);
320
321 return (s);
322}
323
324static int
326{
327 ACPI_HANDLE handle;
328 ACPI_STATUS s;
329
330 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
331 s = AcpiInstallAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
333 if (ACPI_FAILURE(s)) {
334 device_printf(sc->super_sc.dev,
335 "Failed to install GSBUS Address Space Handler in ACPI\n");
336 return (ENXIO);
337 }
338
339 return (0);
340}
341
342static int
344{
345 ACPI_HANDLE handle;
346 ACPI_STATUS s;
347
348 handle = acpi_get_handle(device_get_parent(sc->super_sc.dev));
349 s = AcpiRemoveAddressSpaceHandler(handle, ACPI_ADR_SPACE_GSBUS,
351 if (ACPI_FAILURE(s)) {
352 device_printf(sc->super_sc.dev,
353 "Failed to remove GSBUS Address Space Handler from ACPI\n");
354 return (ENXIO);
355 }
356
357 return (0);
358}
359
360static ACPI_STATUS
361acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context)
362{
364 ACPI_STATUS status;
365 ACPI_HANDLE handle;
366
368 status = AcpiGetHandle(ACPI_ROOT_OBJECT,
369 res->Data.I2cSerialBus.ResourceSource.StringPtr, &handle);
370 if (ACPI_FAILURE(status))
371 return (status);
372 memcpy(sb, &res->Data.I2cSerialBus,
374 /*
375 * replace "pointer to ACPI object name string" field
376 * with pointer to ACPI object itself.
377 */
378 sb->ResourceSource_Handle = handle;
379 return (AE_CTRL_TERMINATE);
380 } else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
381 return (AE_NOT_FOUND);
382
383 return (AE_OK);
384}
385
386static ACPI_STATUS
387acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb)
388{
389
390 return (AcpiWalkResources(handle, "_CRS",
392}
393
394static ACPI_STATUS
395acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context)
396{
397 device_t dev = context;
398 struct iicbus_ivar *super_devi = device_get_ivars(dev);
399 struct resource_list *rl = &super_devi->rl;
400 int irq, gpio_pin;
401
402 switch(res->Type) {
403 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
404 if (res->Data.ExtendedIrq.InterruptCount > 0) {
405 irq = res->Data.ExtendedIrq.Interrupts[0];
406 if (bootverbose)
407 printf(" IRQ: %d\n", irq);
408 resource_list_add_next(rl, SYS_RES_IRQ, irq, irq, 1);
409 return (AE_CTRL_TERMINATE);
410 }
411 break;
412 case ACPI_RESOURCE_TYPE_GPIO:
413 if (res->Data.Gpio.ConnectionType ==
414 ACPI_RESOURCE_GPIO_TYPE_INT) {
415 /* Not supported by FreeBSD yet */
416 gpio_pin = res->Data.Gpio.PinTable[0];
417 if (bootverbose)
418 printf(" GPIO IRQ pin: %d\n", gpio_pin);
419 return (AE_CTRL_TERMINATE);
420 }
421 break;
422 default:
423 break;
424 }
425
426 return (AE_OK);
427}
428
429static ACPI_STATUS
430acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev)
431{
432
433 return (AcpiWalkResources(handle, "_CRS",
435}
436
437static void
439{
440 device_printf(dev, "found ACPI child\n");
441 printf(" SlaveAddress: 0x%04hx\n", sb->SlaveAddress);
442 printf(" ConnectionSpeed: %uHz\n", sb->ConnectionSpeed);
443 printf(" SlaveMode: %s\n",
444 sb->SlaveMode == ACPI_CONTROLLER_INITIATED ?
445 "ControllerInitiated" : "DeviceInitiated");
446 printf(" AddressingMode: %uBit\n", sb->AccessMode == 0 ? 7 : 10);
447 printf(" ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ?
448 "Exclusive" : "Shared");
449}
450
451static device_t
452acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit)
453{
454
456 dev, order, name, unit, sizeof(struct acpi_iicbus_ivars)));
457}
458
459static ACPI_STATUS
460acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level,
461 void *context, void **result)
462{
463 device_t iicbus, child, acpi_child, acpi0;
464 struct iicbus_softc *super_sc;
466 ACPI_STATUS status;
467 UINT32 sta;
468
469 iicbus = context;
470 super_sc = device_get_softc(iicbus);
471
472 /*
473 * If no _STA method or if it failed, then assume that
474 * the device is present.
475 */
476 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
477 !ACPI_DEVICE_PRESENT(sta))
478 return (AE_OK);
479
480 if (!acpi_has_hid(handle))
481 return (AE_OK);
482
483 /*
484 * Read "I2C Serial Bus Connection Resource Descriptor"
485 * described in p.19.6.57 of ACPI specification.
486 */
487 bzero(&sb, sizeof(ACPI_IICBUS_RESOURCE_I2C_SERIALBUS));
488 if (ACPI_FAILURE(acpi_iicbus_get_i2cres(handle, &sb)) ||
489 sb.SlaveAddress == 0)
490 return (AE_OK);
491 if (sb.ResourceSource_Handle !=
492 acpi_get_handle(device_get_parent(iicbus)))
493 return (AE_OK);
494 if (bootverbose)
496
497 /* Find out speed of the slowest slave */
498 if (super_sc->bus_freq == 0 || super_sc->bus_freq > sb.ConnectionSpeed)
499 super_sc->bus_freq = sb.ConnectionSpeed;
500
501 /* Delete existing child of acpi bus */
502 acpi_child = acpi_get_device(handle);
503 if (acpi_child != NULL) {
504 acpi0 = devclass_get_device(devclass_find("acpi"), 0);
505 if (device_get_parent(acpi_child) != acpi0)
506 return (AE_OK);
507
508 if (device_is_attached(acpi_child))
509 return (AE_OK);
510
511 if (device_delete_child(acpi0, acpi_child) != 0)
512 return (AE_OK);
513 }
514
515 child = BUS_ADD_CHILD(iicbus, 0, NULL, -1);
516 if (child == NULL) {
517 device_printf(iicbus, "add child failed\n");
518 return (AE_OK);
519 }
520
521 iicbus_set_addr(child, sb.SlaveAddress);
522 acpi_set_handle(child, handle);
523 (void)acpi_iicbus_parse_resources(handle, child);
524
525 /*
526 * Update ACPI-CA to use the IIC enumerated device_t for this handle.
527 */
528 status = AcpiAttachData(handle, acpi_fake_objhandler, child);
529 if (ACPI_FAILURE(status))
530 printf("WARNING: Unable to attach object data to %s - %s\n",
531 acpi_name(handle), AcpiFormatException(status));
532
533 return (AE_OK);
534}
535
536static ACPI_STATUS
538{
539
540 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
541 ACPI_UINT32_MAX, acpi_iicbus_enumerate_child, NULL, dev, NULL));
542}
543
544static void
545acpi_iicbus_set_power_children(device_t dev, int state, bool all_children)
546{
547 device_t *devlist;
548 int i, numdevs;
549
550 if (device_get_children(dev, &devlist, &numdevs) != 0)
551 return;
552
553 for (i = 0; i < numdevs; i++)
554 if (all_children || device_is_attached(devlist[i]) != 0)
555 acpi_set_powerstate(devlist[i], state);
556
557 free(devlist, M_TEMP);
558}
559
560static int
562{
563 ACPI_HANDLE handle;
564 device_t controller;
565
566 if (acpi_disabled("iicbus"))
567 return (ENXIO);
568
569 controller = device_get_parent(dev);
570 if (controller == NULL)
571 return (ENXIO);
572
573 handle = acpi_get_handle(controller);
574 if (handle == NULL)
575 return (ENXIO);
576
577 device_set_desc(dev, "Philips I2C bus (ACPI-hinted)");
578 return (BUS_PROBE_DEFAULT);
579}
580
581static int
583{
584 struct acpi_iicbus_softc *sc = device_get_softc(dev);
585 int error;
586
587 if (ACPI_FAILURE(acpi_iicbus_enumerate_children(dev)))
588 device_printf(dev, "children enumeration failed\n");
589
590 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, true);
592 if (error == 0 && install_space_handler != 0 &&
594 sc->space_handler_installed = true;
595
596 return (error);
597}
598
599static int
601{
602 struct acpi_iicbus_softc *sc = device_get_softc(dev);
603
606 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
607
608 return (iicbus_detach(dev));
609}
610
611static int
613{
614 int error;
615
616 error = bus_generic_suspend(dev);
617 if (error == 0)
618 acpi_iicbus_set_power_children(dev, ACPI_STATE_D3, false);
619
620 return (error);
621}
622
623static int
625{
626
627 acpi_iicbus_set_power_children(dev, ACPI_STATE_D0, false);
628
629 return (bus_generic_resume(dev));
630}
631
632/*
633 * If this device is an ACPI child but no one claimed it, attempt
634 * to power it off. We'll power it back up when a driver is added.
635 */
636static void
637acpi_iicbus_probe_nomatch(device_t bus, device_t child)
638{
639
640 iicbus_probe_nomatch(bus, child);
641 acpi_set_powerstate(child, ACPI_STATE_D3);
642}
643
644/*
645 * If a new driver has a chance to probe a child, first power it up.
646 */
647static void
648acpi_iicbus_driver_added(device_t dev, driver_t *driver)
649{
650 device_t child, *devlist;
651 int i, numdevs;
652
653 DEVICE_IDENTIFY(driver, dev);
654 if (device_get_children(dev, &devlist, &numdevs) != 0)
655 return;
656
657 for (i = 0; i < numdevs; i++) {
658 child = devlist[i];
659 if (device_get_state(child) == DS_NOTPRESENT) {
660 acpi_set_powerstate(child, ACPI_STATE_D0);
661 if (device_probe_and_attach(child) != 0)
662 acpi_set_powerstate(child, ACPI_STATE_D3);
663 }
664 }
665 free(devlist, M_TEMP);
666}
667
668static void
669acpi_iicbus_child_deleted(device_t bus, device_t child)
670{
671 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
672
673 if (acpi_get_device(devi->handle) == child)
674 AcpiDetachData(devi->handle, acpi_fake_objhandler);
675}
676
677static int
678acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
679{
680 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
681
682 switch (which) {
683 case ACPI_IVAR_HANDLE:
684 *res = (uintptr_t)devi->handle;
685 break;
686 default:
687 return (iicbus_read_ivar(bus, child, which, res));
688 }
689
690 return (0);
691}
692
693static int
694acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
695{
696 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
697
698 switch (which) {
699 case ACPI_IVAR_HANDLE:
700 if (devi->handle != NULL)
701 return (EINVAL);
702 devi->handle = (ACPI_HANDLE)val;
703 break;
704 default:
705 return (iicbus_write_ivar(bus, child, which, val));
706 }
707
708 return (0);
709}
710
711/* Location hint for devctl(8). Concatenate IIC and ACPI hints. */
712static int
713acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb)
714{
715 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
716 int error;
717
718 /* read IIC location hint string into the buffer. */
719 error = iicbus_child_location(bus, child, sb);
720 if (error != 0)
721 return (error);
722
723 /* Place ACPI string right after IIC one's terminating NUL. */
724 if (devi->handle != NULL)
725 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle));
726
727 return (0);
728}
729
730/* PnP information for devctl(8). Concatenate IIC and ACPI info strings. */
731static int
732acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
733{
734 struct acpi_iicbus_ivars *devi = device_get_ivars(child);
735 int error;
736
737 /* read IIC PnP string into the buffer. */
738 error = iicbus_child_pnpinfo(bus, child, sb);
739 if (error != 0)
740 return (error);
741
742 if (devi->handle == NULL)
743 return (0);
744
745 error = acpi_pnpinfo(devi->handle, sb);
746
747 return (error);
748}
749
750static device_method_t acpi_iicbus_methods[] = {
751 /* Device interface */
752 DEVMETHOD(device_probe, acpi_iicbus_probe),
753 DEVMETHOD(device_attach, acpi_iicbus_attach),
754 DEVMETHOD(device_detach, acpi_iicbus_detach),
755 DEVMETHOD(device_suspend, acpi_iicbus_suspend),
756 DEVMETHOD(device_resume, acpi_iicbus_resume),
757
758 /* Bus interface */
759 DEVMETHOD(bus_add_child, acpi_iicbus_add_child),
760 DEVMETHOD(bus_probe_nomatch, acpi_iicbus_probe_nomatch),
761 DEVMETHOD(bus_driver_added, acpi_iicbus_driver_added),
762 DEVMETHOD(bus_child_deleted, acpi_iicbus_child_deleted),
763 DEVMETHOD(bus_read_ivar, acpi_iicbus_read_ivar),
764 DEVMETHOD(bus_write_ivar, acpi_iicbus_write_ivar),
765 DEVMETHOD(bus_child_location, acpi_iicbus_child_location),
766 DEVMETHOD(bus_child_pnpinfo, acpi_iicbus_child_pnpinfo),
767 DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path),
768
769 DEVMETHOD_END,
770};
771
773 sizeof(struct acpi_iicbus_softc), iicbus_driver);
774MODULE_VERSION(acpi_iicbus, 1);
775MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1);
static int acpi_iicbus_detach(device_t dev)
Definition: acpi_iicbus.c:600
static void acpi_iicbus_probe_nomatch(device_t bus, device_t child)
Definition: acpi_iicbus.c:637
#define AML_FIELD_ATTRIB_MASK
static ACPI_STATUS acpi_iicbus_parse_resources_cb(ACPI_RESOURCE *res, void *context)
Definition: acpi_iicbus.c:395
static ACPI_STATUS acpi_iicbus_space_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 BitWidth, UINT64 *Value, void *HandlerContext, void *RegionContext)
Definition: acpi_iicbus.c:219
MODULE_DEPEND(acpi_iicbus, acpi, 1, 1, 1)
static int acpi_iicbus_attach(device_t dev)
Definition: acpi_iicbus.c:582
static ACPI_STATUS acpi_iicbus_get_i2cres(ACPI_HANDLE handle, ACPI_RESOURCE_I2C_SERIALBUS *sb)
Definition: acpi_iicbus.c:387
TUNABLE_INT("hw.iicbus.enable_acpi_space_handler", &install_space_handler)
MODULE_VERSION(acpi_iicbus, 1)
ACPI_RESOURCE_I2C_SERIALBUS ACPI_IICBUS_RESOURCE_I2C_SERIALBUS
Definition: acpi_iicbus.c:57
static int acpi_iicbus_suspend(device_t dev)
Definition: acpi_iicbus.c:612
static int acpi_iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
Definition: acpi_iicbus.c:694
static bool acpi_resource_is_i2c_serialbus(ACPI_RESOURCE *res)
Definition: acpi_iicbus.c:85
static void acpi_iicbus_dump_res(device_t dev, ACPI_IICBUS_RESOURCE_I2C_SERIALBUS *sb)
Definition: acpi_iicbus.c:438
static int acpi_iicbus_recvb(device_t dev, u_char slave, char *byte)
Definition: acpi_iicbus.c:106
static int acpi_iicbus_install_address_space_handler(struct acpi_iicbus_softc *sc)
Definition: acpi_iicbus.c:325
static device_t acpi_iicbus_add_child(device_t dev, u_int order, const char *name, int unit)
Definition: acpi_iicbus.c:452
static int install_space_handler
Definition: acpi_iicbus.c:81
static device_method_t acpi_iicbus_methods[]
Definition: acpi_iicbus.c:750
static int acpi_iicbus_probe(device_t dev)
Definition: acpi_iicbus.c:561
static int acpi_iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
Definition: acpi_iicbus.c:732
static ACPI_STATUS acpi_iicbus_enumerate_children(device_t dev)
Definition: acpi_iicbus.c:537
__FBSDID("$FreeBSD$")
static void acpi_iicbus_driver_added(device_t dev, driver_t *driver)
Definition: acpi_iicbus.c:648
#define AML_FIELD_ATTRIO(attr, io)
static ACPI_STATUS acpi_iicbus_parse_resources(ACPI_HANDLE handle, device_t dev)
Definition: acpi_iicbus.c:430
static ACPI_STATUS acpi_iicbus_enumerate_child(ACPI_HANDLE handle, UINT32 level, void *context, void **result)
Definition: acpi_iicbus.c:460
#define ACPI_IICBUS_LOCAL_BUFSIZE
Definition: acpi_iicbus.c:50
static int acpi_iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
Definition: acpi_iicbus.c:678
static int acpi_iicbus_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
Definition: acpi_iicbus.c:173
static ACPI_STATUS acpi_iicbus_get_i2cres_cb(ACPI_RESOURCE *res, void *context)
Definition: acpi_iicbus.c:361
static int acpi_iicbus_remove_address_space_handler(struct acpi_iicbus_softc *sc)
Definition: acpi_iicbus.c:343
static int acpi_iicbus_child_location(device_t bus, device_t child, struct sbuf *sb)
Definition: acpi_iicbus.c:713
static int acpi_iicbus_resume(device_t dev)
Definition: acpi_iicbus.c:624
static int acpi_iicbus_sendb(device_t dev, u_char slave, char byte)
Definition: acpi_iicbus.c:96
struct gsb_buffer __packed
static void acpi_iicbus_set_power_children(device_t dev, int state, bool all_children)
Definition: acpi_iicbus.c:545
static int acpi_iicbus_write(device_t dev, u_char slave, char cmd, void *buf, uint16_t buflen)
Definition: acpi_iicbus.c:122
DEFINE_CLASS_1(iicbus, acpi_iicbus_driver, acpi_iicbus_methods, sizeof(struct acpi_iicbus_softc), iicbus_driver)
static int acpi_iicbus_read(device_t dev, u_char slave, char cmd, void *buf, uint16_t buflen)
Definition: acpi_iicbus.c:134
static int acpi_iicbus_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
Definition: acpi_iicbus.c:158
static void acpi_iicbus_child_deleted(device_t bus, device_t child)
Definition: acpi_iicbus.c:669
#define IIC_M_WR
Definition: ad7418.c:45
#define IIC_M_RD
Definition: iic.h:42
#define IIC_M_NOSTOP
Definition: iic.h:43
#define IIC_M_NOSTART
Definition: iic.h:44
caddr_t data
Definition: iicbb_if.m:61
int val
Definition: iicbb_if.m:83
int iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
Definition: iicbus.c:210
int iicbus_attach_common(device_t dev, u_int bus_freq)
Definition: iicbus.c:96
int iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
Definition: iicbus.c:195
void iicbus_probe_nomatch(device_t bus, device_t child)
Definition: iicbus.c:172
int iicbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
Definition: iicbus.c:189
int iicbus_child_location(device_t bus, device_t child, struct sbuf *sb)
Definition: iicbus.c:180
driver_t iicbus_driver
Definition: iicbus.c:380
device_t iicbus_add_child_common(device_t dev, u_int order, const char *name, int unit, size_t ivars_size)
Definition: iicbus.c:226
int iicbus_detach(device_t dev)
Definition: iicbus.c:144
driver_t acpi_iicbus_driver
char * buf
Definition: iicbus_if.m:55
int * bytes
Definition: iicbus_if.m:103
u_char slave
Definition: iicbus_if.m:76
struct iic_msg * msgs
Definition: iicbus_if.m:134
INTERFACE iicbus
Definition: iicbus_if.m:32
int len
Definition: iicbus_if.m:102
int errno2iic(int errno)
Definition: iiconf.c:51
int iicbus_request_bus(device_t bus, device_t dev, int how)
Definition: iiconf.c:138
int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
Definition: iiconf.c:442
int iicbus_release_bus(device_t bus, device_t dev)
Definition: iiconf.c:206
#define IIC_WAIT
Definition: iiconf.h:46
device_t dev
Definition: ofw_iicbus_if.m:38
struct iicbus_ivar super_ivar
Definition: acpi_iicbus.c:77
ACPI_HANDLE handle
Definition: acpi_iicbus.c:78
bool space_handler_installed
Definition: acpi_iicbus.c:73
struct iicbus_softc super_sc
Definition: acpi_iicbus.c:71
ACPI_CONNECTION_INFO space_handler_info
Definition: acpi_iicbus.c:72
UINT8 len
Definition: acpi_iicbus.c:66
UINT8 status
Definition: acpi_iicbus.c:65
UINT8 data[]
Definition: acpi_iicbus.c:67
Definition: iic.h:38
uint16_t len
Definition: iic.h:45
uint8_t * buf
Definition: iic.h:46
struct resource_list rl
Definition: iicbus.h:57
u_int bus_freq
Definition: iicbus.h:51
device_t dev
Definition: iicbus.h:42