150f14c4fSAndriy Gapon /*-
250f14c4fSAndriy Gapon * SPDX-License-Identifier: BSD-2-Clause
350f14c4fSAndriy Gapon *
450f14c4fSAndriy Gapon * Copyright (c) 2019 Andriy Gapon
5e3722b78SAndriy Gapon *
6e3722b78SAndriy Gapon * Redistribution and use in source and binary forms, with or without
7e3722b78SAndriy Gapon * modification, are permitted provided that the following conditions
8e3722b78SAndriy Gapon * are met:
9e3722b78SAndriy Gapon * 1. Redistributions of source code must retain the above copyright
10e3722b78SAndriy Gapon * notice, this list of conditions and the following disclaimer.
11e3722b78SAndriy Gapon * 2. Redistributions in binary form must reproduce the above copyright
12e3722b78SAndriy Gapon * notice, this list of conditions and the following disclaimer in the
13e3722b78SAndriy Gapon * documentation and/or other materials provided with the distribution.
14e3722b78SAndriy Gapon *
1550f14c4fSAndriy Gapon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e3722b78SAndriy Gapon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e3722b78SAndriy Gapon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e3722b78SAndriy Gapon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e3722b78SAndriy Gapon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e3722b78SAndriy Gapon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e3722b78SAndriy Gapon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e3722b78SAndriy Gapon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e3722b78SAndriy Gapon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e3722b78SAndriy Gapon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e3722b78SAndriy Gapon * SUCH DAMAGE.
26e3722b78SAndriy Gapon */
27e3722b78SAndriy Gapon
28e3722b78SAndriy Gapon #include <sys/param.h>
29e3722b78SAndriy Gapon #include <sys/systm.h>
30e3722b78SAndriy Gapon #include <sys/bus.h>
31e3722b78SAndriy Gapon #include <sys/conf.h>
32e3722b78SAndriy Gapon #include <sys/kernel.h>
33e3722b78SAndriy Gapon #include <sys/lock.h>
34e3722b78SAndriy Gapon #include <sys/mutex.h>
35e3722b78SAndriy Gapon #include <sys/malloc.h>
36e3722b78SAndriy Gapon #include <sys/module.h>
37e3722b78SAndriy Gapon #include <sys/proc.h>
38e3722b78SAndriy Gapon #include <sys/rman.h>
39ddfc9c4cSWarner Losh #include <sys/sbuf.h>
40e3722b78SAndriy Gapon #include <sys/time.h>
41e3722b78SAndriy Gapon
42e3722b78SAndriy Gapon #include <machine/bus.h>
43e3722b78SAndriy Gapon #include <machine/resource.h>
44e3722b78SAndriy Gapon #include <machine/stdarg.h>
45e3722b78SAndriy Gapon
46e3722b78SAndriy Gapon #include <isa/isavar.h>
47e3722b78SAndriy Gapon
48e3722b78SAndriy Gapon #include <dev/superio/superio.h>
490aee3bdcSAndriy Gapon #include <dev/superio/superio_io.h>
50e3722b78SAndriy Gapon
51e3722b78SAndriy Gapon #include "isa_if.h"
52e3722b78SAndriy Gapon
53e3722b78SAndriy Gapon typedef void (*sio_conf_enter_f)(struct resource*, uint16_t);
54e3722b78SAndriy Gapon typedef void (*sio_conf_exit_f)(struct resource*, uint16_t);
55e3722b78SAndriy Gapon
56e3722b78SAndriy Gapon struct sio_conf_methods {
57e3722b78SAndriy Gapon sio_conf_enter_f enter;
58e3722b78SAndriy Gapon sio_conf_exit_f exit;
59e3722b78SAndriy Gapon superio_vendor_t vendor;
60e3722b78SAndriy Gapon };
61e3722b78SAndriy Gapon
62e3722b78SAndriy Gapon struct sio_device {
63e3722b78SAndriy Gapon uint8_t ldn;
64e3722b78SAndriy Gapon superio_dev_type_t type;
65e3722b78SAndriy Gapon };
66e3722b78SAndriy Gapon
67e3722b78SAndriy Gapon struct superio_devinfo {
68e3722b78SAndriy Gapon STAILQ_ENTRY(superio_devinfo) link;
69e3722b78SAndriy Gapon struct resource_list resources;
70e3722b78SAndriy Gapon device_t dev;
71e3722b78SAndriy Gapon uint8_t ldn;
72e3722b78SAndriy Gapon superio_dev_type_t type;
73e3722b78SAndriy Gapon uint16_t iobase;
74e3722b78SAndriy Gapon uint16_t iobase2;
75e3722b78SAndriy Gapon uint8_t irq;
76e3722b78SAndriy Gapon uint8_t dma;
77e3722b78SAndriy Gapon };
78e3722b78SAndriy Gapon
79e3722b78SAndriy Gapon struct siosc {
80e3722b78SAndriy Gapon struct mtx conf_lock;
81e3722b78SAndriy Gapon STAILQ_HEAD(, superio_devinfo) devlist;
82e3722b78SAndriy Gapon struct resource* io_res;
830aee3bdcSAndriy Gapon struct cdev *chardev;
84e3722b78SAndriy Gapon int io_rid;
85e3722b78SAndriy Gapon uint16_t io_port;
86e3722b78SAndriy Gapon const struct sio_conf_methods *methods;
87e3722b78SAndriy Gapon const struct sio_device *known_devices;
88e3722b78SAndriy Gapon superio_vendor_t vendor;
89e3722b78SAndriy Gapon uint16_t devid;
90e3722b78SAndriy Gapon uint8_t revid;
91a0bcfa78SStéphane Rochoy int extid;
92e3722b78SAndriy Gapon uint8_t current_ldn;
93e3722b78SAndriy Gapon uint8_t ldn_reg;
94e3722b78SAndriy Gapon uint8_t enable_reg;
95e3722b78SAndriy Gapon };
96e3722b78SAndriy Gapon
970aee3bdcSAndriy Gapon static d_ioctl_t superio_ioctl;
980aee3bdcSAndriy Gapon
990aee3bdcSAndriy Gapon static struct cdevsw superio_cdevsw = {
1000aee3bdcSAndriy Gapon .d_version = D_VERSION,
1010aee3bdcSAndriy Gapon .d_ioctl = superio_ioctl,
1020aee3bdcSAndriy Gapon .d_name = "superio",
1030aee3bdcSAndriy Gapon };
1040aee3bdcSAndriy Gapon
105e3722b78SAndriy Gapon #define NUMPORTS 2
106e3722b78SAndriy Gapon
107e3722b78SAndriy Gapon static uint8_t
sio_read(struct resource * res,uint8_t reg)108e3722b78SAndriy Gapon sio_read(struct resource* res, uint8_t reg)
109e3722b78SAndriy Gapon {
110e3722b78SAndriy Gapon bus_write_1(res, 0, reg);
111e3722b78SAndriy Gapon return (bus_read_1(res, 1));
112e3722b78SAndriy Gapon }
113e3722b78SAndriy Gapon
114e3722b78SAndriy Gapon /* Read a word from two one-byte registers, big endian. */
115e3722b78SAndriy Gapon static uint16_t
sio_readw(struct resource * res,uint8_t reg)116e3722b78SAndriy Gapon sio_readw(struct resource* res, uint8_t reg)
117e3722b78SAndriy Gapon {
118e3722b78SAndriy Gapon uint16_t v;
119e3722b78SAndriy Gapon
120e3722b78SAndriy Gapon v = sio_read(res, reg);
121e3722b78SAndriy Gapon v <<= 8;
122e3722b78SAndriy Gapon v |= sio_read(res, reg + 1);
123e3722b78SAndriy Gapon return (v);
124e3722b78SAndriy Gapon }
125e3722b78SAndriy Gapon
126e3722b78SAndriy Gapon static void
sio_write(struct resource * res,uint8_t reg,uint8_t val)127e3722b78SAndriy Gapon sio_write(struct resource* res, uint8_t reg, uint8_t val)
128e3722b78SAndriy Gapon {
129e3722b78SAndriy Gapon bus_write_1(res, 0, reg);
130e3722b78SAndriy Gapon bus_write_1(res, 1, val);
131e3722b78SAndriy Gapon }
132e3722b78SAndriy Gapon
133e3722b78SAndriy Gapon static void
sio_ldn_select(struct siosc * sc,uint8_t ldn)134e3722b78SAndriy Gapon sio_ldn_select(struct siosc *sc, uint8_t ldn)
135e3722b78SAndriy Gapon {
136e3722b78SAndriy Gapon mtx_assert(&sc->conf_lock, MA_OWNED);
137e3722b78SAndriy Gapon if (ldn == sc->current_ldn)
138e3722b78SAndriy Gapon return;
139e3722b78SAndriy Gapon sio_write(sc->io_res, sc->ldn_reg, ldn);
140e3722b78SAndriy Gapon sc->current_ldn = ldn;
141e3722b78SAndriy Gapon }
142e3722b78SAndriy Gapon
143e3722b78SAndriy Gapon static uint8_t
sio_ldn_read(struct siosc * sc,uint8_t ldn,uint8_t reg)144e3722b78SAndriy Gapon sio_ldn_read(struct siosc *sc, uint8_t ldn, uint8_t reg)
145e3722b78SAndriy Gapon {
146e3722b78SAndriy Gapon mtx_assert(&sc->conf_lock, MA_OWNED);
147e3722b78SAndriy Gapon if (reg >= sc->enable_reg) {
148e3722b78SAndriy Gapon sio_ldn_select(sc, ldn);
149e3722b78SAndriy Gapon KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed"));
150e3722b78SAndriy Gapon }
151e3722b78SAndriy Gapon return (sio_read(sc->io_res, reg));
152e3722b78SAndriy Gapon }
153e3722b78SAndriy Gapon
154e3722b78SAndriy Gapon static uint16_t
sio_ldn_readw(struct siosc * sc,uint8_t ldn,uint8_t reg)155e3722b78SAndriy Gapon sio_ldn_readw(struct siosc *sc, uint8_t ldn, uint8_t reg)
156e3722b78SAndriy Gapon {
157e3722b78SAndriy Gapon mtx_assert(&sc->conf_lock, MA_OWNED);
158e3722b78SAndriy Gapon if (reg >= sc->enable_reg) {
159e3722b78SAndriy Gapon sio_ldn_select(sc, ldn);
160e3722b78SAndriy Gapon KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed"));
161e3722b78SAndriy Gapon }
162e3722b78SAndriy Gapon return (sio_readw(sc->io_res, reg));
163e3722b78SAndriy Gapon }
164e3722b78SAndriy Gapon
165e3722b78SAndriy Gapon static void
sio_ldn_write(struct siosc * sc,uint8_t ldn,uint8_t reg,uint8_t val)166e3722b78SAndriy Gapon sio_ldn_write(struct siosc *sc, uint8_t ldn, uint8_t reg, uint8_t val)
167e3722b78SAndriy Gapon {
168e3722b78SAndriy Gapon mtx_assert(&sc->conf_lock, MA_OWNED);
169e3722b78SAndriy Gapon if (reg <= sc->ldn_reg) {
170e3722b78SAndriy Gapon printf("ignored attempt to write special register 0x%x\n", reg);
171e3722b78SAndriy Gapon return;
172e3722b78SAndriy Gapon }
173e3722b78SAndriy Gapon sio_ldn_select(sc, ldn);
174e3722b78SAndriy Gapon KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed"));
175e3722b78SAndriy Gapon sio_write(sc->io_res, reg, val);
176e3722b78SAndriy Gapon }
177e3722b78SAndriy Gapon
178e3722b78SAndriy Gapon static void
sio_conf_enter(struct siosc * sc)179e3722b78SAndriy Gapon sio_conf_enter(struct siosc *sc)
180e3722b78SAndriy Gapon {
181e3722b78SAndriy Gapon mtx_lock(&sc->conf_lock);
182e3722b78SAndriy Gapon sc->methods->enter(sc->io_res, sc->io_port);
183e3722b78SAndriy Gapon }
184e3722b78SAndriy Gapon
185e3722b78SAndriy Gapon static void
sio_conf_exit(struct siosc * sc)186e3722b78SAndriy Gapon sio_conf_exit(struct siosc *sc)
187e3722b78SAndriy Gapon {
188e3722b78SAndriy Gapon sc->methods->exit(sc->io_res, sc->io_port);
189e84d4316SAndriy Gapon sc->current_ldn = 0xff;
190e3722b78SAndriy Gapon mtx_unlock(&sc->conf_lock);
191e3722b78SAndriy Gapon }
192e3722b78SAndriy Gapon
193e3722b78SAndriy Gapon static void
ite_conf_enter(struct resource * res,uint16_t port)194e3722b78SAndriy Gapon ite_conf_enter(struct resource* res, uint16_t port)
195e3722b78SAndriy Gapon {
196e3722b78SAndriy Gapon bus_write_1(res, 0, 0x87);
197e3722b78SAndriy Gapon bus_write_1(res, 0, 0x01);
198e3722b78SAndriy Gapon bus_write_1(res, 0, 0x55);
199e3722b78SAndriy Gapon bus_write_1(res, 0, port == 0x2e ? 0x55 : 0xaa);
200e3722b78SAndriy Gapon }
201e3722b78SAndriy Gapon
202e3722b78SAndriy Gapon static void
ite_conf_exit(struct resource * res,uint16_t port)203e3722b78SAndriy Gapon ite_conf_exit(struct resource* res, uint16_t port)
204e3722b78SAndriy Gapon {
205e3722b78SAndriy Gapon sio_write(res, 0x02, 0x02);
206e3722b78SAndriy Gapon }
207e3722b78SAndriy Gapon
208e3722b78SAndriy Gapon static const struct sio_conf_methods ite_conf_methods = {
209e3722b78SAndriy Gapon .enter = ite_conf_enter,
210e3722b78SAndriy Gapon .exit = ite_conf_exit,
211e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE
212e3722b78SAndriy Gapon };
213e3722b78SAndriy Gapon
214e3722b78SAndriy Gapon static void
nvt_conf_enter(struct resource * res,uint16_t port)215e3722b78SAndriy Gapon nvt_conf_enter(struct resource* res, uint16_t port)
216e3722b78SAndriy Gapon {
217e3722b78SAndriy Gapon bus_write_1(res, 0, 0x87);
218e3722b78SAndriy Gapon bus_write_1(res, 0, 0x87);
219e3722b78SAndriy Gapon }
220e3722b78SAndriy Gapon
221e3722b78SAndriy Gapon static void
nvt_conf_exit(struct resource * res,uint16_t port)222e3722b78SAndriy Gapon nvt_conf_exit(struct resource* res, uint16_t port)
223e3722b78SAndriy Gapon {
224e3722b78SAndriy Gapon bus_write_1(res, 0, 0xaa);
225e3722b78SAndriy Gapon }
226e3722b78SAndriy Gapon
227e3722b78SAndriy Gapon static const struct sio_conf_methods nvt_conf_methods = {
228e3722b78SAndriy Gapon .enter = nvt_conf_enter,
229e3722b78SAndriy Gapon .exit = nvt_conf_exit,
230e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON
231e3722b78SAndriy Gapon };
232e3722b78SAndriy Gapon
233c0c23454SPoul-Henning Kamp static void
fintek_conf_enter(struct resource * res,uint16_t port)234c0c23454SPoul-Henning Kamp fintek_conf_enter(struct resource* res, uint16_t port)
235c0c23454SPoul-Henning Kamp {
236c0c23454SPoul-Henning Kamp bus_write_1(res, 0, 0x87);
237c0c23454SPoul-Henning Kamp bus_write_1(res, 0, 0x87);
238c0c23454SPoul-Henning Kamp }
239c0c23454SPoul-Henning Kamp
240c0c23454SPoul-Henning Kamp static void
fintek_conf_exit(struct resource * res,uint16_t port)241c0c23454SPoul-Henning Kamp fintek_conf_exit(struct resource* res, uint16_t port)
242c0c23454SPoul-Henning Kamp {
243c0c23454SPoul-Henning Kamp bus_write_1(res, 0, 0xaa);
244c0c23454SPoul-Henning Kamp }
245c0c23454SPoul-Henning Kamp
246c0c23454SPoul-Henning Kamp static const struct sio_conf_methods fintek_conf_methods = {
247c0c23454SPoul-Henning Kamp .enter = fintek_conf_enter,
248c0c23454SPoul-Henning Kamp .exit = fintek_conf_exit,
249c0c23454SPoul-Henning Kamp .vendor = SUPERIO_VENDOR_FINTEK
250c0c23454SPoul-Henning Kamp };
251c0c23454SPoul-Henning Kamp
252e3722b78SAndriy Gapon static const struct sio_conf_methods * const methods_table[] = {
253e3722b78SAndriy Gapon &ite_conf_methods,
254e3722b78SAndriy Gapon &nvt_conf_methods,
255c0c23454SPoul-Henning Kamp &fintek_conf_methods,
256e3722b78SAndriy Gapon NULL
257e3722b78SAndriy Gapon };
258e3722b78SAndriy Gapon
259e3722b78SAndriy Gapon static const uint16_t ports_table[] = {
260e3722b78SAndriy Gapon 0x2e, 0x4e, 0
261e3722b78SAndriy Gapon };
262e3722b78SAndriy Gapon
263e3722b78SAndriy Gapon const struct sio_device ite_devices[] = {
264e3722b78SAndriy Gapon { .ldn = 4, .type = SUPERIO_DEV_HWM },
265e3722b78SAndriy Gapon { .ldn = 7, .type = SUPERIO_DEV_WDT },
266e3722b78SAndriy Gapon { .type = SUPERIO_DEV_NONE },
267e3722b78SAndriy Gapon };
268e3722b78SAndriy Gapon
2698e6ea10cSStéphane Rochoy const struct sio_device w83627_devices[] = {
2708e6ea10cSStéphane Rochoy { .ldn = 8, .type = SUPERIO_DEV_WDT },
2718e6ea10cSStéphane Rochoy { .ldn = 9, .type = SUPERIO_DEV_GPIO },
2728e6ea10cSStéphane Rochoy { .type = SUPERIO_DEV_NONE },
2738e6ea10cSStéphane Rochoy };
2748e6ea10cSStéphane Rochoy
275e3722b78SAndriy Gapon const struct sio_device nvt_devices[] = {
276e3722b78SAndriy Gapon { .ldn = 8, .type = SUPERIO_DEV_WDT },
277e3722b78SAndriy Gapon { .type = SUPERIO_DEV_NONE },
278e3722b78SAndriy Gapon };
279e3722b78SAndriy Gapon
280e3722b78SAndriy Gapon const struct sio_device nct5104_devices[] = {
281e3722b78SAndriy Gapon { .ldn = 7, .type = SUPERIO_DEV_GPIO },
282e3722b78SAndriy Gapon { .ldn = 8, .type = SUPERIO_DEV_WDT },
283e3722b78SAndriy Gapon { .ldn = 15, .type = SUPERIO_DEV_GPIO },
284e3722b78SAndriy Gapon { .type = SUPERIO_DEV_NONE },
285e3722b78SAndriy Gapon };
286e3722b78SAndriy Gapon
2878e6ea10cSStéphane Rochoy const struct sio_device nct5585_devices[] = {
2888e6ea10cSStéphane Rochoy { .ldn = 9, .type = SUPERIO_DEV_GPIO },
2898e6ea10cSStéphane Rochoy { .type = SUPERIO_DEV_NONE },
2908e6ea10cSStéphane Rochoy };
2918e6ea10cSStéphane Rochoy
2928e6ea10cSStéphane Rochoy const struct sio_device nct611x_devices[] = {
2938e6ea10cSStéphane Rochoy { .ldn = 0x7, .type = SUPERIO_DEV_GPIO },
2948e6ea10cSStéphane Rochoy { .ldn = 0x8, .type = SUPERIO_DEV_WDT },
2958e6ea10cSStéphane Rochoy { .type = SUPERIO_DEV_NONE },
2968e6ea10cSStéphane Rochoy };
2978e6ea10cSStéphane Rochoy
2988e6ea10cSStéphane Rochoy const struct sio_device nct67xx_devices[] = {
2998e6ea10cSStéphane Rochoy { .ldn = 0x8, .type = SUPERIO_DEV_WDT },
3008e6ea10cSStéphane Rochoy { .ldn = 0x9, .type = SUPERIO_DEV_GPIO },
301350b7c35SStéphane Rochoy { .ldn = 0xb, .type = SUPERIO_DEV_HWM },
3028e6ea10cSStéphane Rochoy { .type = SUPERIO_DEV_NONE },
3038e6ea10cSStéphane Rochoy };
3048e6ea10cSStéphane Rochoy
305c0c23454SPoul-Henning Kamp const struct sio_device fintek_devices[] = {
3061b10e191SStéphane Rochoy { .ldn = 6, .type = SUPERIO_DEV_GPIO },
307c0c23454SPoul-Henning Kamp { .ldn = 7, .type = SUPERIO_DEV_WDT },
308c0c23454SPoul-Henning Kamp { .type = SUPERIO_DEV_NONE },
309c0c23454SPoul-Henning Kamp };
310c0c23454SPoul-Henning Kamp
311e3722b78SAndriy Gapon static const struct {
312e3722b78SAndriy Gapon superio_vendor_t vendor;
313e3722b78SAndriy Gapon uint16_t devid;
314e3722b78SAndriy Gapon uint16_t mask;
315a0bcfa78SStéphane Rochoy int extid; /* Extra ID: used to handle conflicting devid. */
316e3722b78SAndriy Gapon const char *descr;
317e3722b78SAndriy Gapon const struct sio_device *devices;
318e3722b78SAndriy Gapon } superio_table[] = {
319e3722b78SAndriy Gapon {
3205804b7abSJohannes Totz .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8613,
3215804b7abSJohannes Totz .devices = ite_devices,
3225804b7abSJohannes Totz },
3235804b7abSJohannes Totz {
324e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712,
325e3722b78SAndriy Gapon .devices = ite_devices,
326e3722b78SAndriy Gapon },
327e3722b78SAndriy Gapon {
328e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716,
329e3722b78SAndriy Gapon .devices = ite_devices,
330e3722b78SAndriy Gapon },
331e3722b78SAndriy Gapon {
332e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718,
333e3722b78SAndriy Gapon .devices = ite_devices,
334e3722b78SAndriy Gapon },
335e3722b78SAndriy Gapon {
336e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720,
337e3722b78SAndriy Gapon .devices = ite_devices,
338e3722b78SAndriy Gapon },
339e3722b78SAndriy Gapon {
340e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721,
341e3722b78SAndriy Gapon .devices = ite_devices,
342e3722b78SAndriy Gapon },
343e3722b78SAndriy Gapon {
344e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726,
345e3722b78SAndriy Gapon .devices = ite_devices,
346e3722b78SAndriy Gapon },
347e3722b78SAndriy Gapon {
348e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728,
349e3722b78SAndriy Gapon .devices = ite_devices,
350e3722b78SAndriy Gapon },
351e3722b78SAndriy Gapon {
352e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771,
353e3722b78SAndriy Gapon .devices = ite_devices,
354e3722b78SAndriy Gapon },
355e3722b78SAndriy Gapon {
356e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00,
357e3722b78SAndriy Gapon .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)",
358e3722b78SAndriy Gapon .devices = nct5104_devices,
359e3722b78SAndriy Gapon },
360e3722b78SAndriy Gapon {
361e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff,
362e3722b78SAndriy Gapon .descr = "Winbond 83627HF/F/HG/G",
363e3722b78SAndriy Gapon .devices = nvt_devices,
364e3722b78SAndriy Gapon },
365e3722b78SAndriy Gapon {
366e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff,
367e3722b78SAndriy Gapon .descr = "Winbond 83627S",
368e3722b78SAndriy Gapon .devices = nvt_devices,
369e3722b78SAndriy Gapon },
370e3722b78SAndriy Gapon {
371e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff,
372e3722b78SAndriy Gapon .descr = "Winbond 83697HF",
373e3722b78SAndriy Gapon .devices = nvt_devices,
374e3722b78SAndriy Gapon },
375e3722b78SAndriy Gapon {
376e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff,
377e3722b78SAndriy Gapon .descr = "Winbond 83697UG",
378e3722b78SAndriy Gapon .devices = nvt_devices,
379e3722b78SAndriy Gapon },
380e3722b78SAndriy Gapon {
381e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff,
382e3722b78SAndriy Gapon .descr = "Winbond 83637HF",
383e3722b78SAndriy Gapon .devices = nvt_devices,
384e3722b78SAndriy Gapon },
385e3722b78SAndriy Gapon {
386e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff,
387e3722b78SAndriy Gapon .descr = "Winbond 83627THF",
388e3722b78SAndriy Gapon .devices = nvt_devices,
389e3722b78SAndriy Gapon },
390e3722b78SAndriy Gapon {
391e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff,
392e3722b78SAndriy Gapon .descr = "Winbond 83687THF",
393e3722b78SAndriy Gapon .devices = nvt_devices,
394e3722b78SAndriy Gapon },
395e3722b78SAndriy Gapon {
396e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff,
397e3722b78SAndriy Gapon .descr = "Winbond 83627EHF",
398e3722b78SAndriy Gapon .devices = nvt_devices,
399e3722b78SAndriy Gapon },
400e3722b78SAndriy Gapon {
401e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff,
402e3722b78SAndriy Gapon .descr = "Winbond 83627DHG",
4038e6ea10cSStéphane Rochoy .devices = w83627_devices,
404e3722b78SAndriy Gapon },
405e3722b78SAndriy Gapon {
406e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff,
407e3722b78SAndriy Gapon .descr = "Winbond 83627UHG",
408e3722b78SAndriy Gapon .devices = nvt_devices,
409e3722b78SAndriy Gapon },
410e3722b78SAndriy Gapon {
411e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff,
412e3722b78SAndriy Gapon .descr = "Winbond 83667HG",
413e3722b78SAndriy Gapon .devices = nvt_devices,
414e3722b78SAndriy Gapon },
415e3722b78SAndriy Gapon {
416e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff,
417e3722b78SAndriy Gapon .descr = "Winbond 83627DHG-P",
418e3722b78SAndriy Gapon .devices = nvt_devices,
419e3722b78SAndriy Gapon },
420e3722b78SAndriy Gapon {
421e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff,
422e3722b78SAndriy Gapon .descr = "Winbond 83667HG-B",
423e3722b78SAndriy Gapon .devices = nvt_devices,
424e3722b78SAndriy Gapon },
425e3722b78SAndriy Gapon {
426e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff,
427e3722b78SAndriy Gapon .descr = "Nuvoton NCT6775",
428e3722b78SAndriy Gapon .devices = nvt_devices,
429e3722b78SAndriy Gapon },
430e3722b78SAndriy Gapon {
431e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff,
432e3722b78SAndriy Gapon .descr = "Nuvoton NCT6776",
433e3722b78SAndriy Gapon .devices = nvt_devices,
434e3722b78SAndriy Gapon },
435e3722b78SAndriy Gapon {
436e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff,
437e3722b78SAndriy Gapon .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)",
438e3722b78SAndriy Gapon .devices = nct5104_devices,
439e3722b78SAndriy Gapon },
440e3722b78SAndriy Gapon {
441e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff,
4428e6ea10cSStéphane Rochoy .descr = "Nuvoton NCT6779D",
4438e6ea10cSStéphane Rochoy .devices = nct67xx_devices,
4448e6ea10cSStéphane Rochoy },
4458e6ea10cSStéphane Rochoy {
4468e6ea10cSStéphane Rochoy .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 1,
4478e6ea10cSStéphane Rochoy .descr = "Nuvoton NCT6796D-E",
4488e6ea10cSStéphane Rochoy .devices = nct67xx_devices,
4498e6ea10cSStéphane Rochoy },
4508e6ea10cSStéphane Rochoy {
4518e6ea10cSStéphane Rochoy .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 2,
4528e6ea10cSStéphane Rochoy .descr = "Nuvoton NCT5585D",
4538e6ea10cSStéphane Rochoy .devices = nct5585_devices,
454e3722b78SAndriy Gapon },
455e3722b78SAndriy Gapon {
456e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff,
457e3722b78SAndriy Gapon .descr = "Nuvoton NCT6791",
458e3722b78SAndriy Gapon .devices = nvt_devices,
459e3722b78SAndriy Gapon },
460e3722b78SAndriy Gapon {
461e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff,
462e3722b78SAndriy Gapon .descr = "Nuvoton NCT6792",
463e3722b78SAndriy Gapon .devices = nvt_devices,
464e3722b78SAndriy Gapon },
465e3722b78SAndriy Gapon {
466e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff,
467e3722b78SAndriy Gapon .descr = "Nuvoton NCT6793",
468e3722b78SAndriy Gapon .devices = nvt_devices,
469e3722b78SAndriy Gapon },
470e3722b78SAndriy Gapon {
4718e6ea10cSStéphane Rochoy .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd200, .mask = 0xff,
4728e6ea10cSStéphane Rochoy .descr = "Nuvoton NCT6112D/NCT6114D/NCT6116D",
4738e6ea10cSStéphane Rochoy .devices = nct611x_devices,
4748e6ea10cSStéphane Rochoy },
4758e6ea10cSStéphane Rochoy {
476e3722b78SAndriy Gapon .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff,
477e3722b78SAndriy Gapon .descr = "Nuvoton NCT6795",
478e3722b78SAndriy Gapon .devices = nvt_devices,
479e3722b78SAndriy Gapon },
480c0c23454SPoul-Henning Kamp {
481c0c23454SPoul-Henning Kamp .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x1210, .mask = 0xff,
482c0c23454SPoul-Henning Kamp .descr = "Fintek F81803",
483c0c23454SPoul-Henning Kamp .devices = fintek_devices,
484c0c23454SPoul-Henning Kamp },
4851b10e191SStéphane Rochoy {
4861b10e191SStéphane Rochoy .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x0704,
4871b10e191SStéphane Rochoy .descr = "Fintek F81865",
4881b10e191SStéphane Rochoy .devices = fintek_devices,
4891b10e191SStéphane Rochoy },
490e3722b78SAndriy Gapon { 0, 0 }
491e3722b78SAndriy Gapon };
492e3722b78SAndriy Gapon
493e3722b78SAndriy Gapon static const char *
devtype_to_str(superio_dev_type_t type)494e3722b78SAndriy Gapon devtype_to_str(superio_dev_type_t type)
495e3722b78SAndriy Gapon {
496e3722b78SAndriy Gapon switch (type) {
497e3722b78SAndriy Gapon case SUPERIO_DEV_NONE:
4986529459aSLi-Wen Hsu return ("none");
499e3722b78SAndriy Gapon case SUPERIO_DEV_HWM:
500e3722b78SAndriy Gapon return ("HWM");
501e3722b78SAndriy Gapon case SUPERIO_DEV_WDT:
502e3722b78SAndriy Gapon return ("WDT");
503e3722b78SAndriy Gapon case SUPERIO_DEV_GPIO:
504e3722b78SAndriy Gapon return ("GPIO");
505e3722b78SAndriy Gapon case SUPERIO_DEV_MAX:
506e3722b78SAndriy Gapon return ("invalid");
507e3722b78SAndriy Gapon }
5086529459aSLi-Wen Hsu return ("invalid");
509e3722b78SAndriy Gapon }
510e3722b78SAndriy Gapon
511e3722b78SAndriy Gapon static int
superio_detect(device_t dev,bool claim,struct siosc * sc)512e3722b78SAndriy Gapon superio_detect(device_t dev, bool claim, struct siosc *sc)
513e3722b78SAndriy Gapon {
514e3722b78SAndriy Gapon struct resource *res;
515e3722b78SAndriy Gapon rman_res_t port;
516e3722b78SAndriy Gapon rman_res_t count;
517e3722b78SAndriy Gapon uint16_t devid;
518e3722b78SAndriy Gapon uint8_t revid;
519e3722b78SAndriy Gapon int error;
520e3722b78SAndriy Gapon int rid;
521e3722b78SAndriy Gapon int i, m;
522a0bcfa78SStéphane Rochoy int prefer;
523e3722b78SAndriy Gapon
524e3722b78SAndriy Gapon error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count);
525e3722b78SAndriy Gapon if (error != 0)
526e3722b78SAndriy Gapon return (error);
527e3722b78SAndriy Gapon if (port > UINT16_MAX || count < NUMPORTS) {
528e3722b78SAndriy Gapon device_printf(dev, "unexpected I/O range size\n");
529e3722b78SAndriy Gapon return (ENXIO);
530e3722b78SAndriy Gapon }
531e3722b78SAndriy Gapon
532e3722b78SAndriy Gapon /*
533e3722b78SAndriy Gapon * Make a temporary resource reservation for hardware probing.
534e3722b78SAndriy Gapon * If we can't get the resources we need then
535e3722b78SAndriy Gapon * we need to abort. Possibly this indicates
536e3722b78SAndriy Gapon * the resources were used by another device
537e3722b78SAndriy Gapon * in which case the probe would have failed anyhow.
538e3722b78SAndriy Gapon */
539e3722b78SAndriy Gapon rid = 0;
540e3722b78SAndriy Gapon res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
541e3722b78SAndriy Gapon if (res == NULL) {
542e3722b78SAndriy Gapon if (claim)
543e3722b78SAndriy Gapon device_printf(dev, "failed to allocate I/O resource\n");
544e3722b78SAndriy Gapon return (ENXIO);
545e3722b78SAndriy Gapon }
546e3722b78SAndriy Gapon
547a0bcfa78SStéphane Rochoy prefer = 0;
548a0bcfa78SStéphane Rochoy resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer", &prefer);
549a0bcfa78SStéphane Rochoy if (bootverbose && prefer > 0)
550a0bcfa78SStéphane Rochoy device_printf(dev, "prefer extid %d\n", prefer);
551a0bcfa78SStéphane Rochoy
552e3722b78SAndriy Gapon for (m = 0; methods_table[m] != NULL; m++) {
553e3722b78SAndriy Gapon methods_table[m]->enter(res, port);
554e3722b78SAndriy Gapon if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) {
555e3722b78SAndriy Gapon devid = sio_readw(res, 0x20);
556e3722b78SAndriy Gapon revid = sio_read(res, 0x22);
557e3722b78SAndriy Gapon } else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) {
558e3722b78SAndriy Gapon devid = sio_read(res, 0x20);
559e3722b78SAndriy Gapon revid = sio_read(res, 0x21);
560e3722b78SAndriy Gapon devid = (devid << 8) | revid;
561c0c23454SPoul-Henning Kamp } else if (methods_table[m]->vendor == SUPERIO_VENDOR_FINTEK) {
562c0c23454SPoul-Henning Kamp devid = sio_read(res, 0x20);
563c0c23454SPoul-Henning Kamp revid = sio_read(res, 0x21);
564c0c23454SPoul-Henning Kamp devid = (devid << 8) | revid;
565e3722b78SAndriy Gapon } else {
566e3722b78SAndriy Gapon continue;
567e3722b78SAndriy Gapon }
568e3722b78SAndriy Gapon methods_table[m]->exit(res, port);
569e3722b78SAndriy Gapon for (i = 0; superio_table[i].vendor != 0; i++) {
570e3722b78SAndriy Gapon uint16_t mask;
571e3722b78SAndriy Gapon
572e3722b78SAndriy Gapon mask = superio_table[i].mask;
573e3722b78SAndriy Gapon if (superio_table[i].vendor !=
574e3722b78SAndriy Gapon methods_table[m]->vendor)
575e3722b78SAndriy Gapon continue;
576e3722b78SAndriy Gapon if ((superio_table[i].devid & ~mask) != (devid & ~mask))
577e3722b78SAndriy Gapon continue;
578a0bcfa78SStéphane Rochoy if (prefer > 0 && prefer != superio_table[i].extid)
579a0bcfa78SStéphane Rochoy continue;
580e3722b78SAndriy Gapon break;
581e3722b78SAndriy Gapon }
582e3722b78SAndriy Gapon
583e3722b78SAndriy Gapon /* Found a matching SuperIO entry. */
584e3722b78SAndriy Gapon if (superio_table[i].vendor != 0)
585e3722b78SAndriy Gapon break;
586e3722b78SAndriy Gapon }
587e3722b78SAndriy Gapon
588e3722b78SAndriy Gapon if (methods_table[m] == NULL)
589e3722b78SAndriy Gapon error = ENXIO;
590e3722b78SAndriy Gapon else
591e3722b78SAndriy Gapon error = 0;
592e3722b78SAndriy Gapon if (!claim || error != 0) {
593e3722b78SAndriy Gapon bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
594e3722b78SAndriy Gapon return (error);
595e3722b78SAndriy Gapon }
596e3722b78SAndriy Gapon
597e3722b78SAndriy Gapon sc->methods = methods_table[m];
598e3722b78SAndriy Gapon sc->vendor = sc->methods->vendor;
599e3722b78SAndriy Gapon sc->known_devices = superio_table[i].devices;
600e3722b78SAndriy Gapon sc->io_res = res;
601e3722b78SAndriy Gapon sc->io_rid = rid;
602e3722b78SAndriy Gapon sc->io_port = port;
603e3722b78SAndriy Gapon sc->devid = devid;
604e3722b78SAndriy Gapon sc->revid = revid;
605a0bcfa78SStéphane Rochoy sc->extid = superio_table[i].extid;
606e3722b78SAndriy Gapon
607e3722b78SAndriy Gapon KASSERT(sc->vendor == SUPERIO_VENDOR_ITE ||
6081b10e191SStéphane Rochoy sc->vendor == SUPERIO_VENDOR_NUVOTON ||
6091b10e191SStéphane Rochoy sc->vendor == SUPERIO_VENDOR_FINTEK,
6101b10e191SStéphane Rochoy ("Only ITE, Nuvoton and Fintek SuperIO-s are supported"));
611e3722b78SAndriy Gapon sc->ldn_reg = 0x07;
61226a0a403SStéphane Rochoy sc->enable_reg = 0x30; /* FIXME enable_reg not used by nctgpio(4). */
613e3722b78SAndriy Gapon sc->current_ldn = 0xff; /* no device should have this */
614e3722b78SAndriy Gapon
615e3722b78SAndriy Gapon if (superio_table[i].descr != NULL) {
616e3722b78SAndriy Gapon device_set_desc(dev, superio_table[i].descr);
617e3722b78SAndriy Gapon } else if (sc->vendor == SUPERIO_VENDOR_ITE) {
61876a79178SMark Johnston device_set_descf(dev,
619e3722b78SAndriy Gapon "ITE IT%4x SuperIO (revision 0x%02x)",
620e3722b78SAndriy Gapon sc->devid, sc->revid);
621e3722b78SAndriy Gapon }
622e3722b78SAndriy Gapon return (0);
623e3722b78SAndriy Gapon }
624e3722b78SAndriy Gapon
625e3722b78SAndriy Gapon static void
superio_identify(driver_t * driver,device_t parent)626e3722b78SAndriy Gapon superio_identify(driver_t *driver, device_t parent)
627e3722b78SAndriy Gapon {
628e3722b78SAndriy Gapon device_t child;
629e3722b78SAndriy Gapon int i;
630e3722b78SAndriy Gapon
631e3722b78SAndriy Gapon /*
632e3722b78SAndriy Gapon * Don't create child devices if any already exist.
633e3722b78SAndriy Gapon * Those could be created via isa hints or if this
634e3722b78SAndriy Gapon * driver is loaded, unloaded and then loaded again.
635e3722b78SAndriy Gapon */
636e3722b78SAndriy Gapon if (device_find_child(parent, "superio", -1)) {
637e3722b78SAndriy Gapon if (bootverbose)
638e3722b78SAndriy Gapon printf("superio: device(s) already created\n");
639e3722b78SAndriy Gapon return;
640e3722b78SAndriy Gapon }
641e3722b78SAndriy Gapon
642e3722b78SAndriy Gapon /*
643e3722b78SAndriy Gapon * Create a child for each candidate port.
644e3722b78SAndriy Gapon * It would be nice if we could somehow clean up those
645e3722b78SAndriy Gapon * that this driver fails to probe.
646e3722b78SAndriy Gapon */
647e3722b78SAndriy Gapon for (i = 0; ports_table[i] != 0; i++) {
648e3722b78SAndriy Gapon child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE,
649e3722b78SAndriy Gapon "superio", -1);
650e3722b78SAndriy Gapon if (child == NULL) {
651e3722b78SAndriy Gapon device_printf(parent, "failed to add superio child\n");
652e3722b78SAndriy Gapon continue;
653e3722b78SAndriy Gapon }
654e3722b78SAndriy Gapon bus_set_resource(child, SYS_RES_IOPORT, 0, ports_table[i], 2);
655e3722b78SAndriy Gapon if (superio_detect(child, false, NULL) != 0)
656e3722b78SAndriy Gapon device_delete_child(parent, child);
657e3722b78SAndriy Gapon }
658e3722b78SAndriy Gapon }
659e3722b78SAndriy Gapon
660e3722b78SAndriy Gapon static int
superio_probe(device_t dev)661e3722b78SAndriy Gapon superio_probe(device_t dev)
662e3722b78SAndriy Gapon {
663e3722b78SAndriy Gapon struct siosc *sc;
664e3722b78SAndriy Gapon int error;
665e3722b78SAndriy Gapon
666e3722b78SAndriy Gapon /* Make sure we do not claim some ISA PNP device. */
667e3722b78SAndriy Gapon if (isa_get_logicalid(dev) != 0)
668e3722b78SAndriy Gapon return (ENXIO);
669e3722b78SAndriy Gapon
670e3722b78SAndriy Gapon /*
671e3722b78SAndriy Gapon * XXX We can populate the softc now only because we return
672e3722b78SAndriy Gapon * BUS_PROBE_SPECIFIC
673e3722b78SAndriy Gapon */
674e3722b78SAndriy Gapon sc = device_get_softc(dev);
675e3722b78SAndriy Gapon error = superio_detect(dev, true, sc);
676e3722b78SAndriy Gapon if (error != 0)
677e3722b78SAndriy Gapon return (error);
678e3722b78SAndriy Gapon return (BUS_PROBE_SPECIFIC);
679e3722b78SAndriy Gapon }
680e3722b78SAndriy Gapon
681e3722b78SAndriy Gapon static void
superio_add_known_child(device_t dev,superio_dev_type_t type,uint8_t ldn)682e3722b78SAndriy Gapon superio_add_known_child(device_t dev, superio_dev_type_t type, uint8_t ldn)
683e3722b78SAndriy Gapon {
684e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(dev);
685e3722b78SAndriy Gapon struct superio_devinfo *dinfo;
686e3722b78SAndriy Gapon device_t child;
687e3722b78SAndriy Gapon
688a05a6804SWarner Losh child = BUS_ADD_CHILD(dev, 0, NULL, DEVICE_UNIT_ANY);
689e3722b78SAndriy Gapon if (child == NULL) {
690e3722b78SAndriy Gapon device_printf(dev, "failed to add child for ldn %d, type %s\n",
691e3722b78SAndriy Gapon ldn, devtype_to_str(type));
692e3722b78SAndriy Gapon return;
693e3722b78SAndriy Gapon }
694e3722b78SAndriy Gapon dinfo = device_get_ivars(child);
695e3722b78SAndriy Gapon dinfo->ldn = ldn;
696e3722b78SAndriy Gapon dinfo->type = type;
697e3722b78SAndriy Gapon sio_conf_enter(sc);
698e3722b78SAndriy Gapon dinfo->iobase = sio_ldn_readw(sc, ldn, 0x60);
699e3722b78SAndriy Gapon dinfo->iobase2 = sio_ldn_readw(sc, ldn, 0x62);
700e3722b78SAndriy Gapon dinfo->irq = sio_ldn_readw(sc, ldn, 0x70);
701e3722b78SAndriy Gapon dinfo->dma = sio_ldn_readw(sc, ldn, 0x74);
702e3722b78SAndriy Gapon sio_conf_exit(sc);
703e3722b78SAndriy Gapon STAILQ_INSERT_TAIL(&sc->devlist, dinfo, link);
704e3722b78SAndriy Gapon }
705e3722b78SAndriy Gapon
706e3722b78SAndriy Gapon static int
superio_attach(device_t dev)707e3722b78SAndriy Gapon superio_attach(device_t dev)
708e3722b78SAndriy Gapon {
709e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(dev);
710e3722b78SAndriy Gapon int i;
711e3722b78SAndriy Gapon
712e3722b78SAndriy Gapon mtx_init(&sc->conf_lock, device_get_nameunit(dev), "superio", MTX_DEF);
713e3722b78SAndriy Gapon STAILQ_INIT(&sc->devlist);
714e3722b78SAndriy Gapon
715e3722b78SAndriy Gapon for (i = 0; sc->known_devices[i].type != SUPERIO_DEV_NONE; i++) {
716e3722b78SAndriy Gapon superio_add_known_child(dev, sc->known_devices[i].type,
717e3722b78SAndriy Gapon sc->known_devices[i].ldn);
718e3722b78SAndriy Gapon }
719e3722b78SAndriy Gapon
720723da5d9SJohn Baldwin bus_identify_children(dev);
721*18250ec6SJohn Baldwin bus_attach_children(dev);
7220aee3bdcSAndriy Gapon
7230aee3bdcSAndriy Gapon sc->chardev = make_dev(&superio_cdevsw, device_get_unit(dev),
7240aee3bdcSAndriy Gapon UID_ROOT, GID_WHEEL, 0600, "superio%d", device_get_unit(dev));
7250aee3bdcSAndriy Gapon if (sc->chardev == NULL)
7260aee3bdcSAndriy Gapon device_printf(dev, "failed to create character device\n");
727174bd5b0SAndriy Gapon else
7280aee3bdcSAndriy Gapon sc->chardev->si_drv1 = sc;
729e3722b78SAndriy Gapon return (0);
730e3722b78SAndriy Gapon }
731e3722b78SAndriy Gapon
732e3722b78SAndriy Gapon static int
superio_detach(device_t dev)733e3722b78SAndriy Gapon superio_detach(device_t dev)
734e3722b78SAndriy Gapon {
735e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(dev);
736e3722b78SAndriy Gapon int error;
737e3722b78SAndriy Gapon
738e3722b78SAndriy Gapon error = bus_generic_detach(dev);
739e3722b78SAndriy Gapon if (error != 0)
740e3722b78SAndriy Gapon return (error);
7410aee3bdcSAndriy Gapon if (sc->chardev != NULL)
7420aee3bdcSAndriy Gapon destroy_dev(sc->chardev);
743e3722b78SAndriy Gapon bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res);
744e3722b78SAndriy Gapon mtx_destroy(&sc->conf_lock);
745e3722b78SAndriy Gapon return (0);
746e3722b78SAndriy Gapon }
747e3722b78SAndriy Gapon
748e3722b78SAndriy Gapon static device_t
superio_add_child(device_t dev,u_int order,const char * name,int unit)749e3722b78SAndriy Gapon superio_add_child(device_t dev, u_int order, const char *name, int unit)
750e3722b78SAndriy Gapon {
751e3722b78SAndriy Gapon struct superio_devinfo *dinfo;
752e3722b78SAndriy Gapon device_t child;
753e3722b78SAndriy Gapon
754e3722b78SAndriy Gapon child = device_add_child_ordered(dev, order, name, unit);
755e3722b78SAndriy Gapon if (child == NULL)
756e3722b78SAndriy Gapon return (NULL);
757e3722b78SAndriy Gapon dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
758e3722b78SAndriy Gapon if (dinfo == NULL) {
759e3722b78SAndriy Gapon device_delete_child(dev, child);
760e3722b78SAndriy Gapon return (NULL);
761e3722b78SAndriy Gapon }
762e3722b78SAndriy Gapon dinfo->ldn = 0xff;
763e3722b78SAndriy Gapon dinfo->type = SUPERIO_DEV_NONE;
764e3722b78SAndriy Gapon dinfo->dev = child;
765e3722b78SAndriy Gapon resource_list_init(&dinfo->resources);
766e3722b78SAndriy Gapon device_set_ivars(child, dinfo);
767e3722b78SAndriy Gapon return (child);
768e3722b78SAndriy Gapon }
769e3722b78SAndriy Gapon
7702520675dSJohn Baldwin static void
superio_child_deleted(device_t dev,device_t child)7712520675dSJohn Baldwin superio_child_deleted(device_t dev, device_t child)
7722520675dSJohn Baldwin {
7732520675dSJohn Baldwin struct superio_devinfo *dinfo;
7742520675dSJohn Baldwin
7752520675dSJohn Baldwin dinfo = device_get_ivars(child);
7762520675dSJohn Baldwin if (dinfo == NULL)
7772520675dSJohn Baldwin return;
7782520675dSJohn Baldwin resource_list_free(&dinfo->resources);
7792520675dSJohn Baldwin free(dinfo, M_DEVBUF);
7802520675dSJohn Baldwin }
7812520675dSJohn Baldwin
782e3722b78SAndriy Gapon static int
superio_read_ivar(device_t dev,device_t child,int which,uintptr_t * result)783e3722b78SAndriy Gapon superio_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
784e3722b78SAndriy Gapon {
785e3722b78SAndriy Gapon struct superio_devinfo *dinfo;
786e3722b78SAndriy Gapon
787e3722b78SAndriy Gapon dinfo = device_get_ivars(child);
788e3722b78SAndriy Gapon switch (which) {
789e3722b78SAndriy Gapon case SUPERIO_IVAR_LDN:
790e3722b78SAndriy Gapon *result = dinfo->ldn;
791e3722b78SAndriy Gapon break;
792e3722b78SAndriy Gapon case SUPERIO_IVAR_TYPE:
793e3722b78SAndriy Gapon *result = dinfo->type;
794e3722b78SAndriy Gapon break;
795e3722b78SAndriy Gapon case SUPERIO_IVAR_IOBASE:
796e3722b78SAndriy Gapon *result = dinfo->iobase;
797e3722b78SAndriy Gapon break;
798e3722b78SAndriy Gapon case SUPERIO_IVAR_IOBASE2:
799e3722b78SAndriy Gapon *result = dinfo->iobase2;
800e3722b78SAndriy Gapon break;
801e3722b78SAndriy Gapon case SUPERIO_IVAR_IRQ:
802e3722b78SAndriy Gapon *result = dinfo->irq;
803e3722b78SAndriy Gapon break;
804e3722b78SAndriy Gapon case SUPERIO_IVAR_DMA:
805e3722b78SAndriy Gapon *result = dinfo->dma;
806e3722b78SAndriy Gapon break;
807e3722b78SAndriy Gapon default:
808e3722b78SAndriy Gapon return (ENOENT);
809e3722b78SAndriy Gapon }
810e3722b78SAndriy Gapon return (0);
811e3722b78SAndriy Gapon }
812e3722b78SAndriy Gapon
813e3722b78SAndriy Gapon static int
superio_write_ivar(device_t dev,device_t child,int which,uintptr_t value)814e3722b78SAndriy Gapon superio_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
815e3722b78SAndriy Gapon {
816e3722b78SAndriy Gapon
817e3722b78SAndriy Gapon switch (which) {
818e3722b78SAndriy Gapon case SUPERIO_IVAR_LDN:
819e3722b78SAndriy Gapon case SUPERIO_IVAR_TYPE:
820e3722b78SAndriy Gapon case SUPERIO_IVAR_IOBASE:
821e3722b78SAndriy Gapon case SUPERIO_IVAR_IOBASE2:
822e3722b78SAndriy Gapon case SUPERIO_IVAR_IRQ:
823e3722b78SAndriy Gapon case SUPERIO_IVAR_DMA:
824e3722b78SAndriy Gapon return (EINVAL);
825e3722b78SAndriy Gapon default:
826e3722b78SAndriy Gapon return (ENOENT);
827e3722b78SAndriy Gapon }
828e3722b78SAndriy Gapon }
829e3722b78SAndriy Gapon
830e3722b78SAndriy Gapon static struct resource_list *
superio_get_resource_list(device_t dev,device_t child)831e3722b78SAndriy Gapon superio_get_resource_list(device_t dev, device_t child)
832e3722b78SAndriy Gapon {
833e3722b78SAndriy Gapon struct superio_devinfo *dinfo = device_get_ivars(child);
834e3722b78SAndriy Gapon
835e3722b78SAndriy Gapon return (&dinfo->resources);
836e3722b78SAndriy Gapon }
837e3722b78SAndriy Gapon
838e3722b78SAndriy Gapon static int
superio_printf(struct superio_devinfo * dinfo,const char * fmt,...)839e3722b78SAndriy Gapon superio_printf(struct superio_devinfo *dinfo, const char *fmt, ...)
840e3722b78SAndriy Gapon {
841e3722b78SAndriy Gapon va_list ap;
842e3722b78SAndriy Gapon int retval;
843e3722b78SAndriy Gapon
844e3722b78SAndriy Gapon retval = printf("superio:%s@ldn%0x2x: ",
845e3722b78SAndriy Gapon devtype_to_str(dinfo->type), dinfo->ldn);
846e3722b78SAndriy Gapon va_start(ap, fmt);
847e3722b78SAndriy Gapon retval += vprintf(fmt, ap);
848e3722b78SAndriy Gapon va_end(ap);
849e3722b78SAndriy Gapon return (retval);
850e3722b78SAndriy Gapon }
851e3722b78SAndriy Gapon
852e3722b78SAndriy Gapon static void
superio_child_detached(device_t dev,device_t child)853e3722b78SAndriy Gapon superio_child_detached(device_t dev, device_t child)
854e3722b78SAndriy Gapon {
855e3722b78SAndriy Gapon struct superio_devinfo *dinfo;
856e3722b78SAndriy Gapon struct resource_list *rl;
857e3722b78SAndriy Gapon
858e3722b78SAndriy Gapon dinfo = device_get_ivars(child);
859e3722b78SAndriy Gapon rl = &dinfo->resources;
860e3722b78SAndriy Gapon
861e3722b78SAndriy Gapon if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0)
862e3722b78SAndriy Gapon superio_printf(dinfo, "Device leaked IRQ resources\n");
863e3722b78SAndriy Gapon if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0)
864e3722b78SAndriy Gapon superio_printf(dinfo, "Device leaked memory resources\n");
865e3722b78SAndriy Gapon if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0)
866e3722b78SAndriy Gapon superio_printf(dinfo, "Device leaked I/O resources\n");
867e3722b78SAndriy Gapon }
868e3722b78SAndriy Gapon
869e3722b78SAndriy Gapon static int
superio_child_location(device_t parent,device_t child,struct sbuf * sb)870ddfc9c4cSWarner Losh superio_child_location(device_t parent, device_t child, struct sbuf *sb)
871e3722b78SAndriy Gapon {
872e3722b78SAndriy Gapon uint8_t ldn;
873e3722b78SAndriy Gapon
874e3722b78SAndriy Gapon ldn = superio_get_ldn(child);
875ddfc9c4cSWarner Losh sbuf_printf(sb, "ldn=0x%02x", ldn);
876e3722b78SAndriy Gapon return (0);
877e3722b78SAndriy Gapon }
878e3722b78SAndriy Gapon
879e3722b78SAndriy Gapon static int
superio_child_pnp(device_t parent,device_t child,struct sbuf * sb)880ddfc9c4cSWarner Losh superio_child_pnp(device_t parent, device_t child, struct sbuf *sb)
881e3722b78SAndriy Gapon {
882e3722b78SAndriy Gapon superio_dev_type_t type;
883e3722b78SAndriy Gapon
884e3722b78SAndriy Gapon type = superio_get_type(child);
885ddfc9c4cSWarner Losh sbuf_printf(sb, "type=%s", devtype_to_str(type));
886e3722b78SAndriy Gapon return (0);
887e3722b78SAndriy Gapon }
888e3722b78SAndriy Gapon
889e3722b78SAndriy Gapon static int
superio_print_child(device_t parent,device_t child)890e3722b78SAndriy Gapon superio_print_child(device_t parent, device_t child)
891e3722b78SAndriy Gapon {
892e3722b78SAndriy Gapon superio_dev_type_t type;
893e3722b78SAndriy Gapon uint8_t ldn;
894e3722b78SAndriy Gapon int retval;
895e3722b78SAndriy Gapon
896e3722b78SAndriy Gapon ldn = superio_get_ldn(child);
897e3722b78SAndriy Gapon type = superio_get_type(child);
898e3722b78SAndriy Gapon
899e3722b78SAndriy Gapon retval = bus_print_child_header(parent, child);
900e3722b78SAndriy Gapon retval += printf(" at %s ldn 0x%02x", devtype_to_str(type), ldn);
901e3722b78SAndriy Gapon retval += bus_print_child_footer(parent, child);
902e3722b78SAndriy Gapon
903e3722b78SAndriy Gapon return (retval);
904e3722b78SAndriy Gapon }
905e3722b78SAndriy Gapon
906e3722b78SAndriy Gapon superio_vendor_t
superio_vendor(device_t dev)907e3722b78SAndriy Gapon superio_vendor(device_t dev)
908e3722b78SAndriy Gapon {
909e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
910e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
911e3722b78SAndriy Gapon
912e3722b78SAndriy Gapon return (sc->vendor);
913e3722b78SAndriy Gapon }
914e3722b78SAndriy Gapon
915e3722b78SAndriy Gapon uint16_t
superio_devid(device_t dev)916e3722b78SAndriy Gapon superio_devid(device_t dev)
917e3722b78SAndriy Gapon {
918e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
919e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
920e3722b78SAndriy Gapon
921e3722b78SAndriy Gapon return (sc->devid);
922e3722b78SAndriy Gapon }
923e3722b78SAndriy Gapon
924e3722b78SAndriy Gapon uint8_t
superio_revid(device_t dev)925e3722b78SAndriy Gapon superio_revid(device_t dev)
926e3722b78SAndriy Gapon {
927e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
928e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
929e3722b78SAndriy Gapon
930e3722b78SAndriy Gapon return (sc->revid);
931e3722b78SAndriy Gapon }
932e3722b78SAndriy Gapon
933a0bcfa78SStéphane Rochoy int
superio_extid(device_t dev)934a0bcfa78SStéphane Rochoy superio_extid(device_t dev)
935a0bcfa78SStéphane Rochoy {
936a0bcfa78SStéphane Rochoy device_t sio_dev = device_get_parent(dev);
937a0bcfa78SStéphane Rochoy struct siosc *sc = device_get_softc(sio_dev);
938a0bcfa78SStéphane Rochoy
939a0bcfa78SStéphane Rochoy return (sc->extid);
940a0bcfa78SStéphane Rochoy }
941a0bcfa78SStéphane Rochoy
942e3722b78SAndriy Gapon uint8_t
superio_ldn_read(device_t dev,uint8_t ldn,uint8_t reg)94326a0a403SStéphane Rochoy superio_ldn_read(device_t dev, uint8_t ldn, uint8_t reg)
944e3722b78SAndriy Gapon {
945e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
946e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
947e3722b78SAndriy Gapon uint8_t v;
948e3722b78SAndriy Gapon
949e3722b78SAndriy Gapon sio_conf_enter(sc);
95026a0a403SStéphane Rochoy v = sio_ldn_read(sc, ldn, reg);
951e3722b78SAndriy Gapon sio_conf_exit(sc);
952e3722b78SAndriy Gapon return (v);
953e3722b78SAndriy Gapon }
954e3722b78SAndriy Gapon
95526a0a403SStéphane Rochoy uint8_t
superio_read(device_t dev,uint8_t reg)95626a0a403SStéphane Rochoy superio_read(device_t dev, uint8_t reg)
95726a0a403SStéphane Rochoy {
95826a0a403SStéphane Rochoy struct superio_devinfo *dinfo = device_get_ivars(dev);
95926a0a403SStéphane Rochoy
96026a0a403SStéphane Rochoy return (superio_ldn_read(dev, dinfo->ldn, reg));
96126a0a403SStéphane Rochoy }
96226a0a403SStéphane Rochoy
96326a0a403SStéphane Rochoy void
superio_ldn_write(device_t dev,uint8_t ldn,uint8_t reg,uint8_t val)96426a0a403SStéphane Rochoy superio_ldn_write(device_t dev, uint8_t ldn, uint8_t reg, uint8_t val)
96526a0a403SStéphane Rochoy {
96626a0a403SStéphane Rochoy device_t sio_dev = device_get_parent(dev);
96726a0a403SStéphane Rochoy struct siosc *sc = device_get_softc(sio_dev);
96826a0a403SStéphane Rochoy
96926a0a403SStéphane Rochoy sio_conf_enter(sc);
97026a0a403SStéphane Rochoy sio_ldn_write(sc, ldn, reg, val);
97126a0a403SStéphane Rochoy sio_conf_exit(sc);
97226a0a403SStéphane Rochoy }
97326a0a403SStéphane Rochoy
974e3722b78SAndriy Gapon void
superio_write(device_t dev,uint8_t reg,uint8_t val)975e3722b78SAndriy Gapon superio_write(device_t dev, uint8_t reg, uint8_t val)
976e3722b78SAndriy Gapon {
977e3722b78SAndriy Gapon struct superio_devinfo *dinfo = device_get_ivars(dev);
978e3722b78SAndriy Gapon
97926a0a403SStéphane Rochoy return (superio_ldn_write(dev, dinfo->ldn, reg, val));
980e3722b78SAndriy Gapon }
981e3722b78SAndriy Gapon
982e3722b78SAndriy Gapon bool
superio_dev_enabled(device_t dev,uint8_t mask)983e3722b78SAndriy Gapon superio_dev_enabled(device_t dev, uint8_t mask)
984e3722b78SAndriy Gapon {
985e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
986e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
987e3722b78SAndriy Gapon struct superio_devinfo *dinfo = device_get_ivars(dev);
988e3722b78SAndriy Gapon uint8_t v;
989e3722b78SAndriy Gapon
990e3722b78SAndriy Gapon /* GPIO device is always active in ITE chips. */
991e3722b78SAndriy Gapon if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
992e3722b78SAndriy Gapon return (true);
993e3722b78SAndriy Gapon
99426a0a403SStéphane Rochoy v = superio_read(dev, sc->enable_reg); /* FIXME enable_reg not used by nctgpio(4). */
995e3722b78SAndriy Gapon return ((v & mask) != 0);
996e3722b78SAndriy Gapon }
997e3722b78SAndriy Gapon
998e3722b78SAndriy Gapon void
superio_dev_enable(device_t dev,uint8_t mask)999e3722b78SAndriy Gapon superio_dev_enable(device_t dev, uint8_t mask)
1000e3722b78SAndriy Gapon {
1001e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
1002e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
1003e3722b78SAndriy Gapon struct superio_devinfo *dinfo = device_get_ivars(dev);
1004e3722b78SAndriy Gapon uint8_t v;
1005e3722b78SAndriy Gapon
1006e3722b78SAndriy Gapon /* GPIO device is always active in ITE chips. */
1007e3722b78SAndriy Gapon if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
1008e3722b78SAndriy Gapon return;
1009e3722b78SAndriy Gapon
1010e3722b78SAndriy Gapon sio_conf_enter(sc);
1011e3722b78SAndriy Gapon v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg);
1012e3722b78SAndriy Gapon v |= mask;
1013e3722b78SAndriy Gapon sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v);
1014e3722b78SAndriy Gapon sio_conf_exit(sc);
1015e3722b78SAndriy Gapon }
1016e3722b78SAndriy Gapon
1017e3722b78SAndriy Gapon void
superio_dev_disable(device_t dev,uint8_t mask)1018e3722b78SAndriy Gapon superio_dev_disable(device_t dev, uint8_t mask)
1019e3722b78SAndriy Gapon {
1020e3722b78SAndriy Gapon device_t sio_dev = device_get_parent(dev);
1021e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(sio_dev);
1022e3722b78SAndriy Gapon struct superio_devinfo *dinfo = device_get_ivars(dev);
1023e3722b78SAndriy Gapon uint8_t v;
1024e3722b78SAndriy Gapon
1025e3722b78SAndriy Gapon /* GPIO device is always active in ITE chips. */
1026e3722b78SAndriy Gapon if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
1027e3722b78SAndriy Gapon return;
1028e3722b78SAndriy Gapon
1029e3722b78SAndriy Gapon sio_conf_enter(sc);
1030e3722b78SAndriy Gapon v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg);
1031e3722b78SAndriy Gapon v &= ~mask;
1032e3722b78SAndriy Gapon sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v);
1033e3722b78SAndriy Gapon sio_conf_exit(sc);
1034e3722b78SAndriy Gapon }
1035e3722b78SAndriy Gapon
1036e3722b78SAndriy Gapon device_t
superio_find_dev(device_t superio,superio_dev_type_t type,int ldn)1037e3722b78SAndriy Gapon superio_find_dev(device_t superio, superio_dev_type_t type, int ldn)
1038e3722b78SAndriy Gapon {
1039e3722b78SAndriy Gapon struct siosc *sc = device_get_softc(superio);
1040e3722b78SAndriy Gapon struct superio_devinfo *dinfo;
1041e3722b78SAndriy Gapon
1042e3722b78SAndriy Gapon if (ldn < -1 || ldn > UINT8_MAX)
1043e3722b78SAndriy Gapon return (NULL); /* ERANGE */
1044e3722b78SAndriy Gapon if (type == SUPERIO_DEV_NONE && ldn == -1)
1045e3722b78SAndriy Gapon return (NULL); /* EINVAL */
1046e3722b78SAndriy Gapon
1047e3722b78SAndriy Gapon STAILQ_FOREACH(dinfo, &sc->devlist, link) {
1048e3722b78SAndriy Gapon if (ldn != -1 && dinfo->ldn != ldn)
1049e3722b78SAndriy Gapon continue;
1050e3722b78SAndriy Gapon if (type != SUPERIO_DEV_NONE && dinfo->type != type)
1051e3722b78SAndriy Gapon continue;
1052e3722b78SAndriy Gapon return (dinfo->dev);
1053e3722b78SAndriy Gapon }
1054e3722b78SAndriy Gapon return (NULL);
1055e3722b78SAndriy Gapon }
1056e3722b78SAndriy Gapon
10570aee3bdcSAndriy Gapon static int
superio_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)10580aee3bdcSAndriy Gapon superio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
10590aee3bdcSAndriy Gapon struct thread *td)
10600aee3bdcSAndriy Gapon {
10610aee3bdcSAndriy Gapon struct siosc *sc;
10620aee3bdcSAndriy Gapon struct superiocmd *s;
10630aee3bdcSAndriy Gapon
10640aee3bdcSAndriy Gapon sc = dev->si_drv1;
10650aee3bdcSAndriy Gapon s = (struct superiocmd *)data;
10660aee3bdcSAndriy Gapon switch (cmd) {
10670aee3bdcSAndriy Gapon case SUPERIO_CR_READ:
10680aee3bdcSAndriy Gapon sio_conf_enter(sc);
10690aee3bdcSAndriy Gapon s->val = sio_ldn_read(sc, s->ldn, s->cr);
10700aee3bdcSAndriy Gapon sio_conf_exit(sc);
10710aee3bdcSAndriy Gapon return (0);
10720aee3bdcSAndriy Gapon case SUPERIO_CR_WRITE:
10730aee3bdcSAndriy Gapon sio_conf_enter(sc);
10740aee3bdcSAndriy Gapon sio_ldn_write(sc, s->ldn, s->cr, s->val);
10750aee3bdcSAndriy Gapon sio_conf_exit(sc);
10760aee3bdcSAndriy Gapon return (0);
10770aee3bdcSAndriy Gapon default:
10780aee3bdcSAndriy Gapon return (ENOTTY);
10790aee3bdcSAndriy Gapon }
10800aee3bdcSAndriy Gapon }
10810aee3bdcSAndriy Gapon
1082e3722b78SAndriy Gapon static device_method_t superio_methods[] = {
1083e3722b78SAndriy Gapon DEVMETHOD(device_identify, superio_identify),
1084e3722b78SAndriy Gapon DEVMETHOD(device_probe, superio_probe),
1085e3722b78SAndriy Gapon DEVMETHOD(device_attach, superio_attach),
1086e3722b78SAndriy Gapon DEVMETHOD(device_detach, superio_detach),
1087e3722b78SAndriy Gapon DEVMETHOD(device_shutdown, bus_generic_shutdown),
1088e3722b78SAndriy Gapon DEVMETHOD(device_suspend, bus_generic_suspend),
1089e3722b78SAndriy Gapon DEVMETHOD(device_resume, bus_generic_resume),
1090e3722b78SAndriy Gapon
1091e3722b78SAndriy Gapon DEVMETHOD(bus_add_child, superio_add_child),
10922520675dSJohn Baldwin DEVMETHOD(bus_child_deleted, superio_child_deleted),
1093e3722b78SAndriy Gapon DEVMETHOD(bus_child_detached, superio_child_detached),
1094ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, superio_child_location),
1095ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, superio_child_pnp),
1096e3722b78SAndriy Gapon DEVMETHOD(bus_print_child, superio_print_child),
1097e3722b78SAndriy Gapon DEVMETHOD(bus_read_ivar, superio_read_ivar),
1098e3722b78SAndriy Gapon DEVMETHOD(bus_write_ivar, superio_write_ivar),
1099e3722b78SAndriy Gapon DEVMETHOD(bus_get_resource_list, superio_get_resource_list),
1100e3722b78SAndriy Gapon DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
1101e3722b78SAndriy Gapon DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
1102e3722b78SAndriy Gapon DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
1103e3722b78SAndriy Gapon DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
1104e3722b78SAndriy Gapon DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
1105e3722b78SAndriy Gapon DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1106e3722b78SAndriy Gapon DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1107e3722b78SAndriy Gapon DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
1108e3722b78SAndriy Gapon DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
1109e3722b78SAndriy Gapon
1110e3722b78SAndriy Gapon DEVMETHOD_END
1111e3722b78SAndriy Gapon };
1112e3722b78SAndriy Gapon
1113e3722b78SAndriy Gapon static driver_t superio_driver = {
1114e3722b78SAndriy Gapon "superio",
1115e3722b78SAndriy Gapon superio_methods,
1116e3722b78SAndriy Gapon sizeof(struct siosc)
1117e3722b78SAndriy Gapon };
1118e3722b78SAndriy Gapon
1119abd890f9SJohn Baldwin DRIVER_MODULE(superio, isa, superio_driver, 0, 0);
1120e3722b78SAndriy Gapon MODULE_VERSION(superio, 1);
1121