| @@ -1,528 +1,530 @@ | | | @@ -1,528 +1,530 @@ |
1 | /* $NetBSD: ichsmb.c,v 1.81 2022/09/22 14:45:33 riastradh Exp $ */ | | 1 | /* $NetBSD: ichsmb.c,v 1.81.4.1 2023/07/29 10:50:05 martin Exp $ */ |
2 | /* $OpenBSD: ichiic.c,v 1.44 2020/10/07 11:23:05 jsg Exp $ */ | | 2 | /* $OpenBSD: ichiic.c,v 1.44 2020/10/07 11:23:05 jsg Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org> | | 5 | * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | /* | | 20 | /* |
21 | * Intel ICH SMBus controller driver. | | 21 | * Intel ICH SMBus controller driver. |
22 | */ | | 22 | */ |
23 | | | 23 | |
24 | #include <sys/cdefs.h> | | 24 | #include <sys/cdefs.h> |
25 | __KERNEL_RCSID(0, "$NetBSD: ichsmb.c,v 1.81 2022/09/22 14:45:33 riastradh Exp $"); | | 25 | __KERNEL_RCSID(0, "$NetBSD: ichsmb.c,v 1.81.4.1 2023/07/29 10:50:05 martin Exp $"); |
26 | | | 26 | |
27 | #include <sys/param.h> | | 27 | #include <sys/param.h> |
28 | #include <sys/device.h> | | 28 | #include <sys/device.h> |
29 | #include <sys/errno.h> | | 29 | #include <sys/errno.h> |
30 | #include <sys/kernel.h> | | 30 | #include <sys/kernel.h> |
31 | #include <sys/mutex.h> | | 31 | #include <sys/mutex.h> |
32 | #include <sys/condvar.h> | | 32 | #include <sys/condvar.h> |
33 | #include <sys/module.h> | | 33 | #include <sys/module.h> |
34 | | | 34 | |
35 | #include <sys/bus.h> | | 35 | #include <sys/bus.h> |
36 | | | 36 | |
37 | #include <dev/pci/pcidevs.h> | | 37 | #include <dev/pci/pcidevs.h> |
38 | #include <dev/pci/pcireg.h> | | 38 | #include <dev/pci/pcireg.h> |
39 | #include <dev/pci/pcivar.h> | | 39 | #include <dev/pci/pcivar.h> |
40 | | | 40 | |
41 | #include <dev/ic/i82801lpcreg.h> | | 41 | #include <dev/ic/i82801lpcreg.h> |
42 | | | 42 | |
43 | #include <dev/i2c/i2cvar.h> | | 43 | #include <dev/i2c/i2cvar.h> |
44 | | | 44 | |
45 | #ifdef ICHIIC_DEBUG | | 45 | #ifdef ICHIIC_DEBUG |
46 | #define DPRINTF(x) printf x | | 46 | #define DPRINTF(x) printf x |
47 | #else | | 47 | #else |
48 | #define DPRINTF(x) | | 48 | #define DPRINTF(x) |
49 | #endif | | 49 | #endif |
50 | | | 50 | |
51 | #define ICHIIC_DELAY 100 | | 51 | #define ICHIIC_DELAY 100 |
52 | #define ICHIIC_TIMEOUT 1 | | 52 | #define ICHIIC_TIMEOUT 1 |
53 | | | 53 | |
54 | struct ichsmb_softc { | | 54 | struct ichsmb_softc { |
55 | device_t sc_dev; | | 55 | device_t sc_dev; |
56 | | | 56 | |
57 | bus_space_tag_t sc_iot; | | 57 | bus_space_tag_t sc_iot; |
58 | bus_space_handle_t sc_ioh; | | 58 | bus_space_handle_t sc_ioh; |
59 | bus_size_t sc_size; | | 59 | bus_size_t sc_size; |
60 | pci_chipset_tag_t sc_pc; | | 60 | pci_chipset_tag_t sc_pc; |
61 | void * sc_ih; | | 61 | void * sc_ih; |
62 | int sc_poll; | | 62 | int sc_poll; |
63 | pci_intr_handle_t *sc_pihp; | | 63 | pci_intr_handle_t *sc_pihp; |
64 | | | 64 | |
65 | kmutex_t sc_exec_lock; | | 65 | kmutex_t sc_exec_lock; |
66 | kcondvar_t sc_exec_wait; | | 66 | kcondvar_t sc_exec_wait; |
67 | | | 67 | |
68 | struct i2c_controller sc_i2c_tag; | | 68 | struct i2c_controller sc_i2c_tag; |
69 | struct { | | 69 | struct { |
70 | i2c_op_t op; | | 70 | i2c_op_t op; |
71 | void * buf; | | 71 | void * buf; |
72 | size_t len; | | 72 | size_t len; |
73 | int flags; | | 73 | int flags; |
74 | int error; | | 74 | int error; |
75 | bool done; | | 75 | bool done; |
76 | } sc_i2c_xfer; | | 76 | } sc_i2c_xfer; |
77 | device_t sc_i2c_device; | | 77 | device_t sc_i2c_device; |
78 | }; | | 78 | }; |
79 | | | 79 | |
80 | static int ichsmb_match(device_t, cfdata_t, void *); | | 80 | static int ichsmb_match(device_t, cfdata_t, void *); |
81 | static void ichsmb_attach(device_t, device_t, void *); | | 81 | static void ichsmb_attach(device_t, device_t, void *); |
82 | static int ichsmb_detach(device_t, int); | | 82 | static int ichsmb_detach(device_t, int); |
83 | static int ichsmb_rescan(device_t, const char *, const int *); | | 83 | static int ichsmb_rescan(device_t, const char *, const int *); |
84 | static void ichsmb_chdet(device_t, device_t); | | 84 | static void ichsmb_chdet(device_t, device_t); |
85 | | | 85 | |
86 | static int ichsmb_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, | | 86 | static int ichsmb_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, |
87 | size_t, void *, size_t, int); | | 87 | size_t, void *, size_t, int); |
88 | | | 88 | |
89 | static int ichsmb_intr(void *); | | 89 | static int ichsmb_intr(void *); |
90 | | | 90 | |
91 | #include "ioconf.h" | | 91 | #include "ioconf.h" |
92 | | | 92 | |
93 | CFATTACH_DECL3_NEW(ichsmb, sizeof(struct ichsmb_softc), | | 93 | CFATTACH_DECL3_NEW(ichsmb, sizeof(struct ichsmb_softc), |
94 | ichsmb_match, ichsmb_attach, ichsmb_detach, NULL, ichsmb_rescan, | | 94 | ichsmb_match, ichsmb_attach, ichsmb_detach, NULL, ichsmb_rescan, |
95 | ichsmb_chdet, DVF_DETACH_SHUTDOWN); | | 95 | ichsmb_chdet, DVF_DETACH_SHUTDOWN); |
96 | | | 96 | |
97 | | | 97 | |
98 | static int | | 98 | static int |
99 | ichsmb_match(device_t parent, cfdata_t match, void *aux) | | 99 | ichsmb_match(device_t parent, cfdata_t match, void *aux) |
100 | { | | 100 | { |
101 | struct pci_attach_args *pa = aux; | | 101 | struct pci_attach_args *pa = aux; |
102 | | | 102 | |
103 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) { | | 103 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) { |
104 | switch (PCI_PRODUCT(pa->pa_id)) { | | 104 | switch (PCI_PRODUCT(pa->pa_id)) { |
105 | case PCI_PRODUCT_INTEL_6300ESB_SMB: | | 105 | case PCI_PRODUCT_INTEL_6300ESB_SMB: |
106 | case PCI_PRODUCT_INTEL_63XXESB_SMB: | | 106 | case PCI_PRODUCT_INTEL_63XXESB_SMB: |
107 | case PCI_PRODUCT_INTEL_82801AA_SMB: | | 107 | case PCI_PRODUCT_INTEL_82801AA_SMB: |
108 | case PCI_PRODUCT_INTEL_82801AB_SMB: | | 108 | case PCI_PRODUCT_INTEL_82801AB_SMB: |
109 | case PCI_PRODUCT_INTEL_82801BA_SMB: | | 109 | case PCI_PRODUCT_INTEL_82801BA_SMB: |
110 | case PCI_PRODUCT_INTEL_82801CA_SMB: | | 110 | case PCI_PRODUCT_INTEL_82801CA_SMB: |
111 | case PCI_PRODUCT_INTEL_82801DB_SMB: | | 111 | case PCI_PRODUCT_INTEL_82801DB_SMB: |
112 | case PCI_PRODUCT_INTEL_82801E_SMB: | | 112 | case PCI_PRODUCT_INTEL_82801E_SMB: |
113 | case PCI_PRODUCT_INTEL_82801EB_SMB: | | 113 | case PCI_PRODUCT_INTEL_82801EB_SMB: |
114 | case PCI_PRODUCT_INTEL_82801FB_SMB: | | 114 | case PCI_PRODUCT_INTEL_82801FB_SMB: |
115 | case PCI_PRODUCT_INTEL_82801G_SMB: | | 115 | case PCI_PRODUCT_INTEL_82801G_SMB: |
116 | case PCI_PRODUCT_INTEL_82801H_SMB: | | 116 | case PCI_PRODUCT_INTEL_82801H_SMB: |
117 | case PCI_PRODUCT_INTEL_82801I_SMB: | | 117 | case PCI_PRODUCT_INTEL_82801I_SMB: |
118 | case PCI_PRODUCT_INTEL_82801JD_SMB: | | 118 | case PCI_PRODUCT_INTEL_82801JD_SMB: |
119 | case PCI_PRODUCT_INTEL_82801JI_SMB: | | 119 | case PCI_PRODUCT_INTEL_82801JI_SMB: |
120 | case PCI_PRODUCT_INTEL_3400_SMB: | | 120 | case PCI_PRODUCT_INTEL_3400_SMB: |
121 | case PCI_PRODUCT_INTEL_6SERIES_SMB: | | 121 | case PCI_PRODUCT_INTEL_6SERIES_SMB: |
122 | case PCI_PRODUCT_INTEL_7SERIES_SMB: | | 122 | case PCI_PRODUCT_INTEL_7SERIES_SMB: |
123 | case PCI_PRODUCT_INTEL_8SERIES_SMB: | | 123 | case PCI_PRODUCT_INTEL_8SERIES_SMB: |
124 | case PCI_PRODUCT_INTEL_9SERIES_SMB: | | 124 | case PCI_PRODUCT_INTEL_9SERIES_SMB: |
125 | case PCI_PRODUCT_INTEL_100SERIES_SMB: | | 125 | case PCI_PRODUCT_INTEL_100SERIES_SMB: |
126 | case PCI_PRODUCT_INTEL_100SERIES_LP_SMB: | | 126 | case PCI_PRODUCT_INTEL_100SERIES_LP_SMB: |
127 | case PCI_PRODUCT_INTEL_2HS_SMB: | | 127 | case PCI_PRODUCT_INTEL_2HS_SMB: |
128 | case PCI_PRODUCT_INTEL_3HS_SMB: | | 128 | case PCI_PRODUCT_INTEL_3HS_SMB: |
129 | case PCI_PRODUCT_INTEL_3HS_U_SMB: | | 129 | case PCI_PRODUCT_INTEL_3HS_U_SMB: |
130 | case PCI_PRODUCT_INTEL_4HS_H_SMB: | | 130 | case PCI_PRODUCT_INTEL_4HS_H_SMB: |
131 | case PCI_PRODUCT_INTEL_4HS_V_SMB: | | 131 | case PCI_PRODUCT_INTEL_4HS_V_SMB: |
132 | case PCI_PRODUCT_INTEL_CORE4G_M_SMB: | | 132 | case PCI_PRODUCT_INTEL_CORE4G_M_SMB: |
133 | case PCI_PRODUCT_INTEL_CORE5G_M_SMB: | | 133 | case PCI_PRODUCT_INTEL_CORE5G_M_SMB: |
134 | case PCI_PRODUCT_INTEL_CMTLK_SMB: | | 134 | case PCI_PRODUCT_INTEL_CMTLK_SMB: |
135 | case PCI_PRODUCT_INTEL_BAYTRAIL_PCU_SMB: | | 135 | case PCI_PRODUCT_INTEL_BAYTRAIL_PCU_SMB: |
136 | case PCI_PRODUCT_INTEL_BSW_PCU_SMB: | | 136 | case PCI_PRODUCT_INTEL_BSW_PCU_SMB: |
137 | case PCI_PRODUCT_INTEL_APL_SMB: | | 137 | case PCI_PRODUCT_INTEL_APL_SMB: |
138 | case PCI_PRODUCT_INTEL_GLK_SMB: | | 138 | case PCI_PRODUCT_INTEL_GLK_SMB: |
139 | case PCI_PRODUCT_INTEL_EHL_SMB: | | 139 | case PCI_PRODUCT_INTEL_EHL_SMB: |
140 | case PCI_PRODUCT_INTEL_JSL_SMB: | | 140 | case PCI_PRODUCT_INTEL_JSL_SMB: |
| | | 141 | case PCI_PRODUCT_INTEL_ADL_N_SMB: |
141 | case PCI_PRODUCT_INTEL_C600_SMBUS: | | 142 | case PCI_PRODUCT_INTEL_C600_SMBUS: |
142 | case PCI_PRODUCT_INTEL_C600_SMB_0: | | 143 | case PCI_PRODUCT_INTEL_C600_SMB_0: |
143 | case PCI_PRODUCT_INTEL_C600_SMB_1: | | 144 | case PCI_PRODUCT_INTEL_C600_SMB_1: |
144 | case PCI_PRODUCT_INTEL_C600_SMB_2: | | 145 | case PCI_PRODUCT_INTEL_C600_SMB_2: |
145 | case PCI_PRODUCT_INTEL_C610_SMB: | | 146 | case PCI_PRODUCT_INTEL_C610_SMB: |
146 | case PCI_PRODUCT_INTEL_C620_SMB: | | 147 | case PCI_PRODUCT_INTEL_C620_SMB: |
147 | case PCI_PRODUCT_INTEL_C620_SMB_S: | | 148 | case PCI_PRODUCT_INTEL_C620_SMB_S: |
148 | case PCI_PRODUCT_INTEL_EP80579_SMB: | | 149 | case PCI_PRODUCT_INTEL_EP80579_SMB: |
149 | case PCI_PRODUCT_INTEL_DH89XXCC_SMB: | | 150 | case PCI_PRODUCT_INTEL_DH89XXCC_SMB: |
150 | case PCI_PRODUCT_INTEL_DH89XXCL_SMB: | | 151 | case PCI_PRODUCT_INTEL_DH89XXCL_SMB: |
151 | case PCI_PRODUCT_INTEL_C2000_PCU_SMBUS: | | 152 | case PCI_PRODUCT_INTEL_C2000_PCU_SMBUS: |
152 | case PCI_PRODUCT_INTEL_C3K_SMBUS_LEGACY: | | 153 | case PCI_PRODUCT_INTEL_C3K_SMBUS_LEGACY: |
153 | case PCI_PRODUCT_INTEL_495_YU_SMB: | | 154 | case PCI_PRODUCT_INTEL_495_YU_SMB: |
154 | case PCI_PRODUCT_INTEL_5HS_H_SMB: | | 155 | case PCI_PRODUCT_INTEL_5HS_H_SMB: |
155 | case PCI_PRODUCT_INTEL_5HS_LP_SMB: | | 156 | case PCI_PRODUCT_INTEL_5HS_LP_SMB: |
156 | case PCI_PRODUCT_INTEL_6HS_H_SMB: | | 157 | case PCI_PRODUCT_INTEL_6HS_H_SMB: |
157 | case PCI_PRODUCT_INTEL_6HS_LP_SMB: | | 158 | case PCI_PRODUCT_INTEL_6HS_LP_SMB: |
| | | 159 | case PCI_PRODUCT_INTEL_7HS_SMB: |
158 | return 1; | | 160 | return 1; |
159 | } | | 161 | } |
160 | } | | 162 | } |
161 | return 0; | | 163 | return 0; |
162 | } | | 164 | } |
163 | | | 165 | |
164 | static void | | 166 | static void |
165 | ichsmb_attach(device_t parent, device_t self, void *aux) | | 167 | ichsmb_attach(device_t parent, device_t self, void *aux) |
166 | { | | 168 | { |
167 | struct ichsmb_softc *sc = device_private(self); | | 169 | struct ichsmb_softc *sc = device_private(self); |
168 | struct pci_attach_args *pa = aux; | | 170 | struct pci_attach_args *pa = aux; |
169 | pcireg_t conf; | | 171 | pcireg_t conf; |
170 | const char *intrstr = NULL; | | 172 | const char *intrstr = NULL; |
171 | char intrbuf[PCI_INTRSTR_LEN]; | | 173 | char intrbuf[PCI_INTRSTR_LEN]; |
172 | | | 174 | |
173 | sc->sc_dev = self; | | 175 | sc->sc_dev = self; |
174 | sc->sc_pc = pa->pa_pc; | | 176 | sc->sc_pc = pa->pa_pc; |
175 | | | 177 | |
176 | pci_aprint_devinfo(pa, NULL); | | 178 | pci_aprint_devinfo(pa, NULL); |
177 | | | 179 | |
178 | mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO); | | 180 | mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO); |
179 | cv_init(&sc->sc_exec_wait, device_xname(self)); | | 181 | cv_init(&sc->sc_exec_wait, device_xname(self)); |
180 | | | 182 | |
181 | /* Read configuration */ | | 183 | /* Read configuration */ |
182 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOSTC); | | 184 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOSTC); |
183 | DPRINTF(("%s: conf 0x%08x\n", device_xname(sc->sc_dev), conf)); | | 185 | DPRINTF(("%s: conf 0x%08x\n", device_xname(sc->sc_dev), conf)); |
184 | | | 186 | |
185 | if ((conf & SMB_HOSTC_HSTEN) == 0) { | | 187 | if ((conf & SMB_HOSTC_HSTEN) == 0) { |
186 | aprint_error_dev(self, "SMBus disabled\n"); | | 188 | aprint_error_dev(self, "SMBus disabled\n"); |
187 | goto out; | | 189 | goto out; |
188 | } | | 190 | } |
189 | | | 191 | |
190 | /* Map I/O space */ | | 192 | /* Map I/O space */ |
191 | if (pci_mapreg_map(pa, SMB_BASE, PCI_MAPREG_TYPE_IO, 0, | | 193 | if (pci_mapreg_map(pa, SMB_BASE, PCI_MAPREG_TYPE_IO, 0, |
192 | &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size)) { | | 194 | &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size)) { |
193 | aprint_error_dev(self, "can't map I/O space\n"); | | 195 | aprint_error_dev(self, "can't map I/O space\n"); |
194 | goto out; | | 196 | goto out; |
195 | } | | 197 | } |
196 | | | 198 | |
197 | sc->sc_poll = 1; | | 199 | sc->sc_poll = 1; |
198 | sc->sc_ih = NULL; | | 200 | sc->sc_ih = NULL; |
199 | if (conf & SMB_HOSTC_SMIEN) { | | 201 | if (conf & SMB_HOSTC_SMIEN) { |
200 | /* No PCI IRQ */ | | 202 | /* No PCI IRQ */ |
201 | aprint_normal_dev(self, "interrupting at SMI\n"); | | 203 | aprint_normal_dev(self, "interrupting at SMI\n"); |
202 | } else { | | 204 | } else { |
203 | /* Install interrupt handler */ | | 205 | /* Install interrupt handler */ |
204 | if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0) { | | 206 | if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0) { |
205 | intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], | | 207 | intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], |
206 | intrbuf, sizeof(intrbuf)); | | 208 | intrbuf, sizeof(intrbuf)); |
207 | pci_intr_setattr(pa->pa_pc, &sc->sc_pihp[0], | | 209 | pci_intr_setattr(pa->pa_pc, &sc->sc_pihp[0], |
208 | PCI_INTR_MPSAFE, true); | | 210 | PCI_INTR_MPSAFE, true); |
209 | sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, | | 211 | sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, |
210 | sc->sc_pihp[0], IPL_BIO, ichsmb_intr, sc, | | 212 | sc->sc_pihp[0], IPL_BIO, ichsmb_intr, sc, |
211 | device_xname(sc->sc_dev)); | | 213 | device_xname(sc->sc_dev)); |
212 | if (sc->sc_ih != NULL) { | | 214 | if (sc->sc_ih != NULL) { |
213 | aprint_normal_dev(self, "interrupting at %s\n", | | 215 | aprint_normal_dev(self, "interrupting at %s\n", |
214 | intrstr); | | 216 | intrstr); |
215 | sc->sc_poll = 0; | | 217 | sc->sc_poll = 0; |
216 | } else { | | 218 | } else { |
217 | pci_intr_release(pa->pa_pc, sc->sc_pihp, 1); | | 219 | pci_intr_release(pa->pa_pc, sc->sc_pihp, 1); |
218 | sc->sc_pihp = NULL; | | 220 | sc->sc_pihp = NULL; |
219 | } | | 221 | } |
220 | } | | 222 | } |
221 | if (sc->sc_poll) | | 223 | if (sc->sc_poll) |
222 | aprint_normal_dev(self, "polling\n"); | | 224 | aprint_normal_dev(self, "polling\n"); |
223 | } | | 225 | } |
224 | | | 226 | |
225 | /* Attach I2C bus */ | | 227 | /* Attach I2C bus */ |
226 | iic_tag_init(&sc->sc_i2c_tag); | | 228 | iic_tag_init(&sc->sc_i2c_tag); |
227 | sc->sc_i2c_tag.ic_cookie = sc; | | 229 | sc->sc_i2c_tag.ic_cookie = sc; |
228 | sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec; | | 230 | sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec; |
229 | | | 231 | |
230 | sc->sc_i2c_device = NULL; | | 232 | sc->sc_i2c_device = NULL; |
231 | ichsmb_rescan(self, NULL, NULL); | | 233 | ichsmb_rescan(self, NULL, NULL); |
232 | | | 234 | |
233 | out: if (!pmf_device_register(self, NULL, NULL)) | | 235 | out: if (!pmf_device_register(self, NULL, NULL)) |
234 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 236 | aprint_error_dev(self, "couldn't establish power handler\n"); |
235 | } | | 237 | } |
236 | | | 238 | |
237 | static int | | 239 | static int |
238 | ichsmb_rescan(device_t self, const char *ifattr, const int *locators) | | 240 | ichsmb_rescan(device_t self, const char *ifattr, const int *locators) |
239 | { | | 241 | { |
240 | struct ichsmb_softc *sc = device_private(self); | | 242 | struct ichsmb_softc *sc = device_private(self); |
241 | | | 243 | |
242 | if (ifattr_match(ifattr, "i2cbus") && sc->sc_i2c_device == NULL) { | | 244 | if (ifattr_match(ifattr, "i2cbus") && sc->sc_i2c_device == NULL) { |
243 | struct i2cbus_attach_args iba; | | 245 | struct i2cbus_attach_args iba; |
244 | | | 246 | |
245 | memset(&iba, 0, sizeof(iba)); | | 247 | memset(&iba, 0, sizeof(iba)); |
246 | iba.iba_tag = &sc->sc_i2c_tag; | | 248 | iba.iba_tag = &sc->sc_i2c_tag; |
247 | sc->sc_i2c_device = config_found(self, &iba, iicbus_print, | | 249 | sc->sc_i2c_device = config_found(self, &iba, iicbus_print, |
248 | CFARGS_NONE); | | 250 | CFARGS_NONE); |
249 | } | | 251 | } |
250 | | | 252 | |
251 | return 0; | | 253 | return 0; |
252 | } | | 254 | } |
253 | | | 255 | |
254 | static int | | 256 | static int |
255 | ichsmb_detach(device_t self, int flags) | | 257 | ichsmb_detach(device_t self, int flags) |
256 | { | | 258 | { |
257 | struct ichsmb_softc *sc = device_private(self); | | 259 | struct ichsmb_softc *sc = device_private(self); |
258 | int error; | | 260 | int error; |
259 | | | 261 | |
260 | error = config_detach_children(self, flags); | | 262 | error = config_detach_children(self, flags); |
261 | if (error) | | 263 | if (error) |
262 | return error; | | 264 | return error; |
263 | | | 265 | |
264 | iic_tag_fini(&sc->sc_i2c_tag); | | 266 | iic_tag_fini(&sc->sc_i2c_tag); |
265 | | | 267 | |
266 | if (sc->sc_ih) { | | 268 | if (sc->sc_ih) { |
267 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); | | 269 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
268 | sc->sc_ih = NULL; | | 270 | sc->sc_ih = NULL; |
269 | } | | 271 | } |
270 | | | 272 | |
271 | if (sc->sc_pihp) { | | 273 | if (sc->sc_pihp) { |
272 | pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); | | 274 | pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); |
273 | sc->sc_pihp = NULL; | | 275 | sc->sc_pihp = NULL; |
274 | } | | 276 | } |
275 | | | 277 | |
276 | if (sc->sc_size != 0) | | 278 | if (sc->sc_size != 0) |
277 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); | | 279 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); |
278 | | | 280 | |
279 | mutex_destroy(&sc->sc_exec_lock); | | 281 | mutex_destroy(&sc->sc_exec_lock); |
280 | cv_destroy(&sc->sc_exec_wait); | | 282 | cv_destroy(&sc->sc_exec_wait); |
281 | | | 283 | |
282 | return 0; | | 284 | return 0; |
283 | } | | 285 | } |
284 | | | 286 | |
285 | static void | | 287 | static void |
286 | ichsmb_chdet(device_t self, device_t child) | | 288 | ichsmb_chdet(device_t self, device_t child) |
287 | { | | 289 | { |
288 | struct ichsmb_softc *sc = device_private(self); | | 290 | struct ichsmb_softc *sc = device_private(self); |
289 | | | 291 | |
290 | if (sc->sc_i2c_device == child) | | 292 | if (sc->sc_i2c_device == child) |
291 | sc->sc_i2c_device = NULL; | | 293 | sc->sc_i2c_device = NULL; |
292 | } | | 294 | } |
293 | | | 295 | |
294 | static int | | 296 | static int |
295 | ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, | | 297 | ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, |
296 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) | | 298 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
297 | { | | 299 | { |
298 | struct ichsmb_softc *sc = cookie; | | 300 | struct ichsmb_softc *sc = cookie; |
299 | const uint8_t *b; | | 301 | const uint8_t *b; |
300 | uint8_t ctl = 0, st; | | 302 | uint8_t ctl = 0, st; |
301 | int retries; | | 303 | int retries; |
302 | char fbuf[64]; | | 304 | char fbuf[64]; |
303 | | | 305 | |
304 | DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " | | 306 | DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " |
305 | "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen, | | 307 | "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen, |
306 | len, flags)); | | 308 | len, flags)); |
307 | | | 309 | |
308 | mutex_enter(&sc->sc_exec_lock); | | 310 | mutex_enter(&sc->sc_exec_lock); |
309 | | | 311 | |
310 | /* Clear status bits */ | | 312 | /* Clear status bits */ |
311 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, | | 313 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, |
312 | SMB_HS_INTR | SMB_HS_DEVERR | SMB_HS_BUSERR | SMB_HS_FAILED); | | 314 | SMB_HS_INTR | SMB_HS_DEVERR | SMB_HS_BUSERR | SMB_HS_FAILED); |
313 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, SMB_HS, 1, | | 315 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, SMB_HS, 1, |
314 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); | | 316 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
315 | | | 317 | |
316 | /* Wait for bus to be idle */ | | 318 | /* Wait for bus to be idle */ |
317 | for (retries = 100; retries > 0; retries--) { | | 319 | for (retries = 100; retries > 0; retries--) { |
318 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); | | 320 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); |
319 | if (!(st & SMB_HS_BUSY)) | | 321 | if (!(st & SMB_HS_BUSY)) |
320 | break; | | 322 | break; |
321 | DELAY(ICHIIC_DELAY); | | 323 | DELAY(ICHIIC_DELAY); |
322 | } | | 324 | } |
323 | #ifdef ICHIIC_DEBUG | | 325 | #ifdef ICHIIC_DEBUG |
324 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); | | 326 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); |
325 | printf("%s: exec: st %s\n", device_xname(sc->sc_dev), fbuf); | | 327 | printf("%s: exec: st %s\n", device_xname(sc->sc_dev), fbuf); |
326 | #endif | | 328 | #endif |
327 | if (st & SMB_HS_BUSY) { | | 329 | if (st & SMB_HS_BUSY) { |
328 | mutex_exit(&sc->sc_exec_lock); | | 330 | mutex_exit(&sc->sc_exec_lock); |
329 | return (EBUSY); | | 331 | return (EBUSY); |
330 | } | | 332 | } |
331 | | | 333 | |
332 | if (sc->sc_poll) | | 334 | if (sc->sc_poll) |
333 | flags |= I2C_F_POLL; | | 335 | flags |= I2C_F_POLL; |
334 | | | 336 | |
335 | if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || | | 337 | if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || |
336 | (cmdlen == 0 && len > 1)) { | | 338 | (cmdlen == 0 && len > 1)) { |
337 | mutex_exit(&sc->sc_exec_lock); | | 339 | mutex_exit(&sc->sc_exec_lock); |
338 | return (EINVAL); | | 340 | return (EINVAL); |
339 | } | | 341 | } |
340 | | | 342 | |
341 | /* Setup transfer */ | | 343 | /* Setup transfer */ |
342 | sc->sc_i2c_xfer.op = op; | | 344 | sc->sc_i2c_xfer.op = op; |
343 | sc->sc_i2c_xfer.buf = buf; | | 345 | sc->sc_i2c_xfer.buf = buf; |
344 | sc->sc_i2c_xfer.len = len; | | 346 | sc->sc_i2c_xfer.len = len; |
345 | sc->sc_i2c_xfer.flags = flags; | | 347 | sc->sc_i2c_xfer.flags = flags; |
346 | sc->sc_i2c_xfer.error = 0; | | 348 | sc->sc_i2c_xfer.error = 0; |
347 | sc->sc_i2c_xfer.done = false; | | 349 | sc->sc_i2c_xfer.done = false; |
348 | | | 350 | |
349 | /* Set slave address and transfer direction */ | | 351 | /* Set slave address and transfer direction */ |
350 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_TXSLVA, | | 352 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_TXSLVA, |
351 | SMB_TXSLVA_ADDR(addr) | | | 353 | SMB_TXSLVA_ADDR(addr) | |
352 | (I2C_OP_READ_P(op) ? SMB_TXSLVA_READ : 0)); | | 354 | (I2C_OP_READ_P(op) ? SMB_TXSLVA_READ : 0)); |
353 | | | 355 | |
354 | b = (const uint8_t *)cmdbuf; | | 356 | b = (const uint8_t *)cmdbuf; |
355 | if (cmdlen > 0) | | 357 | if (cmdlen > 0) |
356 | /* Set command byte */ | | 358 | /* Set command byte */ |
357 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HCMD, b[0]); | | 359 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HCMD, b[0]); |
358 | | | 360 | |
359 | if (I2C_OP_WRITE_P(op)) { | | 361 | if (I2C_OP_WRITE_P(op)) { |
360 | /* Write data */ | | 362 | /* Write data */ |
361 | b = buf; | | 363 | b = buf; |
362 | if (cmdlen == 0 && len == 1) | | 364 | if (cmdlen == 0 && len == 1) |
363 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 365 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
364 | SMB_HCMD, b[0]); | | 366 | SMB_HCMD, b[0]); |
365 | else if (len > 0) | | 367 | else if (len > 0) |
366 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 368 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
367 | SMB_HD0, b[0]); | | 369 | SMB_HD0, b[0]); |
368 | if (len > 1) | | 370 | if (len > 1) |
369 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 371 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
370 | SMB_HD1, b[1]); | | 372 | SMB_HD1, b[1]); |
371 | } | | 373 | } |
372 | | | 374 | |
373 | /* Set SMBus command */ | | 375 | /* Set SMBus command */ |
374 | if (cmdlen == 0) { | | 376 | if (cmdlen == 0) { |
375 | if (len == 0) | | 377 | if (len == 0) |
376 | ctl = SMB_HC_CMD_QUICK; | | 378 | ctl = SMB_HC_CMD_QUICK; |
377 | else | | 379 | else |
378 | ctl = SMB_HC_CMD_BYTE; | | 380 | ctl = SMB_HC_CMD_BYTE; |
379 | } else if (len == 1) | | 381 | } else if (len == 1) |
380 | ctl = SMB_HC_CMD_BDATA; | | 382 | ctl = SMB_HC_CMD_BDATA; |
381 | else if (len == 2) | | 383 | else if (len == 2) |
382 | ctl = SMB_HC_CMD_WDATA; | | 384 | ctl = SMB_HC_CMD_WDATA; |
383 | | | 385 | |
384 | if ((flags & I2C_F_POLL) == 0) | | 386 | if ((flags & I2C_F_POLL) == 0) |
385 | ctl |= SMB_HC_INTREN; | | 387 | ctl |= SMB_HC_INTREN; |
386 | | | 388 | |
387 | /* Start transaction */ | | 389 | /* Start transaction */ |
388 | ctl |= SMB_HC_START; | | 390 | ctl |= SMB_HC_START; |
389 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HC, ctl); | | 391 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HC, ctl); |
390 | | | 392 | |
391 | if (flags & I2C_F_POLL) { | | 393 | if (flags & I2C_F_POLL) { |
392 | /* Poll for completion */ | | 394 | /* Poll for completion */ |
393 | DELAY(ICHIIC_DELAY); | | 395 | DELAY(ICHIIC_DELAY); |
394 | for (retries = 1000; retries > 0; retries--) { | | 396 | for (retries = 1000; retries > 0; retries--) { |
395 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); | | 397 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); |
396 | if ((st & SMB_HS_BUSY) == 0) | | 398 | if ((st & SMB_HS_BUSY) == 0) |
397 | break; | | 399 | break; |
398 | DELAY(ICHIIC_DELAY); | | 400 | DELAY(ICHIIC_DELAY); |
399 | } | | 401 | } |
400 | if (st & SMB_HS_BUSY) | | 402 | if (st & SMB_HS_BUSY) |
401 | goto timeout; | | 403 | goto timeout; |
402 | ichsmb_intr(sc); | | 404 | ichsmb_intr(sc); |
403 | } else { | | 405 | } else { |
404 | /* Wait for interrupt */ | | 406 | /* Wait for interrupt */ |
405 | while (! sc->sc_i2c_xfer.done) { | | 407 | while (! sc->sc_i2c_xfer.done) { |
406 | if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock, | | 408 | if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock, |
407 | ICHIIC_TIMEOUT * hz)) | | 409 | ICHIIC_TIMEOUT * hz)) |
408 | goto timeout; | | 410 | goto timeout; |
409 | } | | 411 | } |
410 | } | | 412 | } |
411 | | | 413 | |
412 | int error = sc->sc_i2c_xfer.error; | | 414 | int error = sc->sc_i2c_xfer.error; |
413 | mutex_exit(&sc->sc_exec_lock); | | 415 | mutex_exit(&sc->sc_exec_lock); |
414 | | | 416 | |
415 | return (error); | | 417 | return (error); |
416 | | | 418 | |
417 | timeout: | | 419 | timeout: |
418 | /* | | 420 | /* |
419 | * Transfer timeout. Kill the transaction and clear status bits. | | 421 | * Transfer timeout. Kill the transaction and clear status bits. |
420 | */ | | 422 | */ |
421 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HC, SMB_HC_KILL); | | 423 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HC, SMB_HC_KILL); |
422 | DELAY(ICHIIC_DELAY); | | 424 | DELAY(ICHIIC_DELAY); |
423 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); | | 425 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); |
424 | if ((st & SMB_HS_FAILED) == 0) { | | 426 | if ((st & SMB_HS_FAILED) == 0) { |
425 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); | | 427 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); |
426 | aprint_error_dev(sc->sc_dev, "abort failed, status %s\n", | | 428 | device_printf(sc->sc_dev, "abort failed, status %s\n", |
427 | fbuf); | | 429 | fbuf); |
428 | } | | 430 | } |
429 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, st); | | 431 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, st); |
430 | mutex_exit(&sc->sc_exec_lock); | | 432 | mutex_exit(&sc->sc_exec_lock); |
431 | return (ETIMEDOUT); | | 433 | return (ETIMEDOUT); |
432 | } | | 434 | } |
433 | | | 435 | |
434 | static int | | 436 | static int |
435 | ichsmb_intr(void *arg) | | 437 | ichsmb_intr(void *arg) |
436 | { | | 438 | { |
437 | struct ichsmb_softc *sc = arg; | | 439 | struct ichsmb_softc *sc = arg; |
438 | uint8_t st; | | 440 | uint8_t st; |
439 | uint8_t *b; | | 441 | uint8_t *b; |
440 | size_t len; | | 442 | size_t len; |
441 | #ifdef ICHIIC_DEBUG | | 443 | #ifdef ICHIIC_DEBUG |
442 | char fbuf[64]; | | 444 | char fbuf[64]; |
443 | #endif | | 445 | #endif |
444 | | | 446 | |
445 | /* Read status */ | | 447 | /* Read status */ |
446 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); | | 448 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SMB_HS); |
447 | | | 449 | |
448 | /* Clear status bits */ | | 450 | /* Clear status bits */ |
449 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, st); | | 451 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, SMB_HS, st); |
450 | | | 452 | |
451 | /* XXX Ignore SMBALERT# for now */ | | 453 | /* XXX Ignore SMBALERT# for now */ |
452 | if ((st & SMB_HS_BUSY) != 0 || | | 454 | if ((st & SMB_HS_BUSY) != 0 || |
453 | (st & (SMB_HS_INTR | SMB_HS_DEVERR | SMB_HS_BUSERR | | | 455 | (st & (SMB_HS_INTR | SMB_HS_DEVERR | SMB_HS_BUSERR | |
454 | SMB_HS_FAILED | SMB_HS_BDONE)) == 0) | | 456 | SMB_HS_FAILED | SMB_HS_BDONE)) == 0) |
455 | /* Interrupt was not for us */ | | 457 | /* Interrupt was not for us */ |
456 | return (0); | | 458 | return (0); |
457 | | | 459 | |
458 | #ifdef ICHIIC_DEBUG | | 460 | #ifdef ICHIIC_DEBUG |
459 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); | | 461 | snprintb(fbuf, sizeof(fbuf), SMB_HS_BITS, st); |
460 | printf("%s: intr st %s\n", device_xname(sc->sc_dev), fbuf); | | 462 | printf("%s: intr st %s\n", device_xname(sc->sc_dev), fbuf); |
461 | #endif | | 463 | #endif |
462 | | | 464 | |
463 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) | | 465 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) |
464 | mutex_enter(&sc->sc_exec_lock); | | 466 | mutex_enter(&sc->sc_exec_lock); |
465 | | | 467 | |
466 | /* Check for errors */ | | 468 | /* Check for errors */ |
467 | if (st & (SMB_HS_DEVERR | SMB_HS_BUSERR | SMB_HS_FAILED)) { | | 469 | if (st & (SMB_HS_DEVERR | SMB_HS_BUSERR | SMB_HS_FAILED)) { |
468 | sc->sc_i2c_xfer.error = EIO; | | 470 | sc->sc_i2c_xfer.error = EIO; |
469 | goto done; | | 471 | goto done; |
470 | } | | 472 | } |
471 | | | 473 | |
472 | if (st & SMB_HS_INTR) { | | 474 | if (st & SMB_HS_INTR) { |
473 | if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) | | 475 | if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) |
474 | goto done; | | 476 | goto done; |
475 | | | 477 | |
476 | /* Read data */ | | 478 | /* Read data */ |
477 | b = sc->sc_i2c_xfer.buf; | | 479 | b = sc->sc_i2c_xfer.buf; |
478 | len = sc->sc_i2c_xfer.len; | | 480 | len = sc->sc_i2c_xfer.len; |
479 | if (len > 0) | | 481 | if (len > 0) |
480 | b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 482 | b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
481 | SMB_HD0); | | 483 | SMB_HD0); |
482 | if (len > 1) | | 484 | if (len > 1) |
483 | b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 485 | b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
484 | SMB_HD1); | | 486 | SMB_HD1); |
485 | } | | 487 | } |
486 | | | 488 | |
487 | done: | | 489 | done: |
488 | sc->sc_i2c_xfer.done = true; | | 490 | sc->sc_i2c_xfer.done = true; |
489 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) { | | 491 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) { |
490 | cv_signal(&sc->sc_exec_wait); | | 492 | cv_signal(&sc->sc_exec_wait); |
491 | mutex_exit(&sc->sc_exec_lock); | | 493 | mutex_exit(&sc->sc_exec_lock); |
492 | } | | 494 | } |
493 | return (1); | | 495 | return (1); |
494 | } | | 496 | } |
495 | | | 497 | |
496 | MODULE(MODULE_CLASS_DRIVER, ichsmb, "pci,iic"); | | 498 | MODULE(MODULE_CLASS_DRIVER, ichsmb, "pci,iic"); |
497 | | | 499 | |
498 | #ifdef _MODULE | | 500 | #ifdef _MODULE |
499 | #include "ioconf.c" | | 501 | #include "ioconf.c" |
500 | #endif | | 502 | #endif |
501 | | | 503 | |
502 | static int | | 504 | static int |
503 | ichsmb_modcmd(modcmd_t cmd, void *opaque) | | 505 | ichsmb_modcmd(modcmd_t cmd, void *opaque) |
504 | { | | 506 | { |
505 | int error = 0; | | 507 | int error = 0; |
506 | | | 508 | |
507 | switch (cmd) { | | 509 | switch (cmd) { |
508 | case MODULE_CMD_INIT: | | 510 | case MODULE_CMD_INIT: |
509 | #ifdef _MODULE | | 511 | #ifdef _MODULE |
510 | error = config_init_component(cfdriver_ioconf_ichsmb, | | 512 | error = config_init_component(cfdriver_ioconf_ichsmb, |
511 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); | | 513 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); |
512 | #endif | | 514 | #endif |
513 | break; | | 515 | break; |
514 | case MODULE_CMD_FINI: | | 516 | case MODULE_CMD_FINI: |
515 | #ifdef _MODULE | | 517 | #ifdef _MODULE |
516 | error = config_fini_component(cfdriver_ioconf_ichsmb, | | 518 | error = config_fini_component(cfdriver_ioconf_ichsmb, |
517 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); | | 519 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); |
518 | #endif | | 520 | #endif |
519 | break; | | 521 | break; |
520 | default: | | 522 | default: |
521 | #ifdef _MODULE | | 523 | #ifdef _MODULE |
522 | error = ENOTTY; | | 524 | error = ENOTTY; |
523 | #endif | | 525 | #endif |
524 | break; | | 526 | break; |
525 | } | | 527 | } |
526 | | | 528 | |
527 | return error; | | 529 | return error; |
528 | } | | 530 | } |