| @@ -1,526 +1,527 @@ | | | @@ -1,526 +1,527 @@ |
1 | /* $NetBSD: ichsmb.c,v 1.70 2021/04/24 23:36:57 thorpej Exp $ */ | | 1 | /* $NetBSD: ichsmb.c,v 1.71 2021/07/12 12:59:54 msaitoh 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.70 2021/04/24 23:36:57 thorpej Exp $"); | | 25 | __KERNEL_RCSID(0, "$NetBSD: ichsmb.c,v 1.71 2021/07/12 12:59:54 msaitoh 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_CORE4G_M_SMB: | | 131 | case PCI_PRODUCT_INTEL_CORE4G_M_SMB: |
132 | case PCI_PRODUCT_INTEL_CORE5G_M_SMB: | | 132 | case PCI_PRODUCT_INTEL_CORE5G_M_SMB: |
133 | case PCI_PRODUCT_INTEL_CMTLK_SMB: | | 133 | case PCI_PRODUCT_INTEL_CMTLK_SMB: |
134 | case PCI_PRODUCT_INTEL_BAYTRAIL_PCU_SMB: | | 134 | case PCI_PRODUCT_INTEL_BAYTRAIL_PCU_SMB: |
135 | case PCI_PRODUCT_INTEL_BSW_PCU_SMB: | | 135 | case PCI_PRODUCT_INTEL_BSW_PCU_SMB: |
136 | case PCI_PRODUCT_INTEL_APL_SMB: | | 136 | case PCI_PRODUCT_INTEL_APL_SMB: |
137 | case PCI_PRODUCT_INTEL_GLK_SMB: | | 137 | case PCI_PRODUCT_INTEL_GLK_SMB: |
| | | 138 | case PCI_PRODUCT_INTEL_JSL_SMB: |
138 | case PCI_PRODUCT_INTEL_C600_SMBUS: | | 139 | case PCI_PRODUCT_INTEL_C600_SMBUS: |
139 | case PCI_PRODUCT_INTEL_C600_SMB_0: | | 140 | case PCI_PRODUCT_INTEL_C600_SMB_0: |
140 | case PCI_PRODUCT_INTEL_C600_SMB_1: | | 141 | case PCI_PRODUCT_INTEL_C600_SMB_1: |
141 | case PCI_PRODUCT_INTEL_C600_SMB_2: | | 142 | case PCI_PRODUCT_INTEL_C600_SMB_2: |
142 | case PCI_PRODUCT_INTEL_C610_SMB: | | 143 | case PCI_PRODUCT_INTEL_C610_SMB: |
143 | case PCI_PRODUCT_INTEL_C620_SMB: | | 144 | case PCI_PRODUCT_INTEL_C620_SMB: |
144 | case PCI_PRODUCT_INTEL_C620_SMB_S: | | 145 | case PCI_PRODUCT_INTEL_C620_SMB_S: |
145 | case PCI_PRODUCT_INTEL_EP80579_SMB: | | 146 | case PCI_PRODUCT_INTEL_EP80579_SMB: |
146 | case PCI_PRODUCT_INTEL_DH89XXCC_SMB: | | 147 | case PCI_PRODUCT_INTEL_DH89XXCC_SMB: |
147 | case PCI_PRODUCT_INTEL_DH89XXCL_SMB: | | 148 | case PCI_PRODUCT_INTEL_DH89XXCL_SMB: |
148 | case PCI_PRODUCT_INTEL_C2000_PCU_SMBUS: | | 149 | case PCI_PRODUCT_INTEL_C2000_PCU_SMBUS: |
149 | case PCI_PRODUCT_INTEL_C3K_SMBUS_LEGACY: | | 150 | case PCI_PRODUCT_INTEL_C3K_SMBUS_LEGACY: |
150 | case PCI_PRODUCT_INTEL_495_YU_SMB: | | 151 | case PCI_PRODUCT_INTEL_495_YU_SMB: |
151 | case PCI_PRODUCT_INTEL_5HS_LP_SMB: | | 152 | case PCI_PRODUCT_INTEL_5HS_LP_SMB: |
152 | return 1; | | 153 | return 1; |
153 | } | | 154 | } |
154 | } | | 155 | } |
155 | return 0; | | 156 | return 0; |
156 | } | | 157 | } |
157 | | | 158 | |
158 | static void | | 159 | static void |
159 | ichsmb_attach(device_t parent, device_t self, void *aux) | | 160 | ichsmb_attach(device_t parent, device_t self, void *aux) |
160 | { | | 161 | { |
161 | struct ichsmb_softc *sc = device_private(self); | | 162 | struct ichsmb_softc *sc = device_private(self); |
162 | struct pci_attach_args *pa = aux; | | 163 | struct pci_attach_args *pa = aux; |
163 | pcireg_t conf; | | 164 | pcireg_t conf; |
164 | const char *intrstr = NULL; | | 165 | const char *intrstr = NULL; |
165 | char intrbuf[PCI_INTRSTR_LEN]; | | 166 | char intrbuf[PCI_INTRSTR_LEN]; |
166 | | | 167 | |
167 | sc->sc_dev = self; | | 168 | sc->sc_dev = self; |
168 | sc->sc_pc = pa->pa_pc; | | 169 | sc->sc_pc = pa->pa_pc; |
169 | | | 170 | |
170 | pci_aprint_devinfo(pa, NULL); | | 171 | pci_aprint_devinfo(pa, NULL); |
171 | | | 172 | |
172 | mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO); | | 173 | mutex_init(&sc->sc_exec_lock, MUTEX_DEFAULT, IPL_BIO); |
173 | cv_init(&sc->sc_exec_wait, device_xname(self)); | | 174 | cv_init(&sc->sc_exec_wait, device_xname(self)); |
174 | | | 175 | |
175 | /* Read configuration */ | | 176 | /* Read configuration */ |
176 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, LPCIB_SMB_HOSTC); | | 177 | conf = pci_conf_read(pa->pa_pc, pa->pa_tag, LPCIB_SMB_HOSTC); |
177 | DPRINTF(("%s: conf 0x%08x\n", device_xname(sc->sc_dev), conf)); | | 178 | DPRINTF(("%s: conf 0x%08x\n", device_xname(sc->sc_dev), conf)); |
178 | | | 179 | |
179 | if ((conf & LPCIB_SMB_HOSTC_HSTEN) == 0) { | | 180 | if ((conf & LPCIB_SMB_HOSTC_HSTEN) == 0) { |
180 | aprint_error_dev(self, "SMBus disabled\n"); | | 181 | aprint_error_dev(self, "SMBus disabled\n"); |
181 | goto out; | | 182 | goto out; |
182 | } | | 183 | } |
183 | | | 184 | |
184 | /* Map I/O space */ | | 185 | /* Map I/O space */ |
185 | if (pci_mapreg_map(pa, LPCIB_SMB_BASE, PCI_MAPREG_TYPE_IO, 0, | | 186 | if (pci_mapreg_map(pa, LPCIB_SMB_BASE, PCI_MAPREG_TYPE_IO, 0, |
186 | &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size)) { | | 187 | &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size)) { |
187 | aprint_error_dev(self, "can't map I/O space\n"); | | 188 | aprint_error_dev(self, "can't map I/O space\n"); |
188 | goto out; | | 189 | goto out; |
189 | } | | 190 | } |
190 | | | 191 | |
191 | sc->sc_poll = 1; | | 192 | sc->sc_poll = 1; |
192 | sc->sc_ih = NULL; | | 193 | sc->sc_ih = NULL; |
193 | if (conf & LPCIB_SMB_HOSTC_SMIEN) { | | 194 | if (conf & LPCIB_SMB_HOSTC_SMIEN) { |
194 | /* No PCI IRQ */ | | 195 | /* No PCI IRQ */ |
195 | aprint_normal_dev(self, "interrupting at SMI\n"); | | 196 | aprint_normal_dev(self, "interrupting at SMI\n"); |
196 | } else { | | 197 | } else { |
197 | /* Install interrupt handler */ | | 198 | /* Install interrupt handler */ |
198 | if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0) { | | 199 | if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) == 0) { |
199 | intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], | | 200 | intrstr = pci_intr_string(pa->pa_pc, sc->sc_pihp[0], |
200 | intrbuf, sizeof(intrbuf)); | | 201 | intrbuf, sizeof(intrbuf)); |
201 | pci_intr_setattr(pa->pa_pc, &sc->sc_pihp[0], | | 202 | pci_intr_setattr(pa->pa_pc, &sc->sc_pihp[0], |
202 | PCI_INTR_MPSAFE, true); | | 203 | PCI_INTR_MPSAFE, true); |
203 | sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, | | 204 | sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, |
204 | sc->sc_pihp[0], IPL_BIO, ichsmb_intr, sc, | | 205 | sc->sc_pihp[0], IPL_BIO, ichsmb_intr, sc, |
205 | device_xname(sc->sc_dev)); | | 206 | device_xname(sc->sc_dev)); |
206 | if (sc->sc_ih != NULL) { | | 207 | if (sc->sc_ih != NULL) { |
207 | aprint_normal_dev(self, "interrupting at %s\n", | | 208 | aprint_normal_dev(self, "interrupting at %s\n", |
208 | intrstr); | | 209 | intrstr); |
209 | sc->sc_poll = 0; | | 210 | sc->sc_poll = 0; |
210 | } else { | | 211 | } else { |
211 | pci_intr_release(pa->pa_pc, sc->sc_pihp, 1); | | 212 | pci_intr_release(pa->pa_pc, sc->sc_pihp, 1); |
212 | sc->sc_pihp = NULL; | | 213 | sc->sc_pihp = NULL; |
213 | } | | 214 | } |
214 | } | | 215 | } |
215 | if (sc->sc_poll) | | 216 | if (sc->sc_poll) |
216 | aprint_normal_dev(self, "polling\n"); | | 217 | aprint_normal_dev(self, "polling\n"); |
217 | } | | 218 | } |
218 | | | 219 | |
219 | sc->sc_i2c_device = NULL; | | 220 | sc->sc_i2c_device = NULL; |
220 | ichsmb_rescan(self, NULL, NULL); | | 221 | ichsmb_rescan(self, NULL, NULL); |
221 | | | 222 | |
222 | out: if (!pmf_device_register(self, NULL, NULL)) | | 223 | out: if (!pmf_device_register(self, NULL, NULL)) |
223 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 224 | aprint_error_dev(self, "couldn't establish power handler\n"); |
224 | } | | 225 | } |
225 | | | 226 | |
226 | static int | | 227 | static int |
227 | ichsmb_rescan(device_t self, const char *ifattr, const int *locators) | | 228 | ichsmb_rescan(device_t self, const char *ifattr, const int *locators) |
228 | { | | 229 | { |
229 | struct ichsmb_softc *sc = device_private(self); | | 230 | struct ichsmb_softc *sc = device_private(self); |
230 | struct i2cbus_attach_args iba; | | 231 | struct i2cbus_attach_args iba; |
231 | | | 232 | |
232 | if (sc->sc_i2c_device != NULL) | | 233 | if (sc->sc_i2c_device != NULL) |
233 | return 0; | | 234 | return 0; |
234 | | | 235 | |
235 | /* Attach I2C bus */ | | 236 | /* Attach I2C bus */ |
236 | iic_tag_init(&sc->sc_i2c_tag); | | 237 | iic_tag_init(&sc->sc_i2c_tag); |
237 | sc->sc_i2c_tag.ic_cookie = sc; | | 238 | sc->sc_i2c_tag.ic_cookie = sc; |
238 | sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec; | | 239 | sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec; |
239 | | | 240 | |
240 | memset(&iba, 0, sizeof(iba)); | | 241 | memset(&iba, 0, sizeof(iba)); |
241 | iba.iba_tag = &sc->sc_i2c_tag; | | 242 | iba.iba_tag = &sc->sc_i2c_tag; |
242 | sc->sc_i2c_device = config_found(self, &iba, iicbus_print, CFARG_EOL); | | 243 | sc->sc_i2c_device = config_found(self, &iba, iicbus_print, CFARG_EOL); |
243 | | | 244 | |
244 | return 0; | | 245 | return 0; |
245 | } | | 246 | } |
246 | | | 247 | |
247 | static int | | 248 | static int |
248 | ichsmb_detach(device_t self, int flags) | | 249 | ichsmb_detach(device_t self, int flags) |
249 | { | | 250 | { |
250 | struct ichsmb_softc *sc = device_private(self); | | 251 | struct ichsmb_softc *sc = device_private(self); |
251 | int error; | | 252 | int error; |
252 | | | 253 | |
253 | if (sc->sc_i2c_device) { | | 254 | if (sc->sc_i2c_device) { |
254 | error = config_detach(sc->sc_i2c_device, flags); | | 255 | error = config_detach(sc->sc_i2c_device, flags); |
255 | if (error) | | 256 | if (error) |
256 | return error; | | 257 | return error; |
257 | } | | 258 | } |
258 | | | 259 | |
259 | iic_tag_fini(&sc->sc_i2c_tag); | | 260 | iic_tag_fini(&sc->sc_i2c_tag); |
260 | | | 261 | |
261 | if (sc->sc_ih) { | | 262 | if (sc->sc_ih) { |
262 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); | | 263 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
263 | sc->sc_ih = NULL; | | 264 | sc->sc_ih = NULL; |
264 | } | | 265 | } |
265 | | | 266 | |
266 | if (sc->sc_pihp) { | | 267 | if (sc->sc_pihp) { |
267 | pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); | | 268 | pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); |
268 | sc->sc_pihp = NULL; | | 269 | sc->sc_pihp = NULL; |
269 | } | | 270 | } |
270 | | | 271 | |
271 | if (sc->sc_size != 0) | | 272 | if (sc->sc_size != 0) |
272 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); | | 273 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); |
273 | | | 274 | |
274 | mutex_destroy(&sc->sc_exec_lock); | | 275 | mutex_destroy(&sc->sc_exec_lock); |
275 | cv_destroy(&sc->sc_exec_wait); | | 276 | cv_destroy(&sc->sc_exec_wait); |
276 | | | 277 | |
277 | return 0; | | 278 | return 0; |
278 | } | | 279 | } |
279 | | | 280 | |
280 | static void | | 281 | static void |
281 | ichsmb_chdet(device_t self, device_t child) | | 282 | ichsmb_chdet(device_t self, device_t child) |
282 | { | | 283 | { |
283 | struct ichsmb_softc *sc = device_private(self); | | 284 | struct ichsmb_softc *sc = device_private(self); |
284 | | | 285 | |
285 | if (sc->sc_i2c_device == child) | | 286 | if (sc->sc_i2c_device == child) |
286 | sc->sc_i2c_device = NULL; | | 287 | sc->sc_i2c_device = NULL; |
287 | } | | 288 | } |
288 | | | 289 | |
289 | static int | | 290 | static int |
290 | ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, | | 291 | ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, |
291 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) | | 292 | const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) |
292 | { | | 293 | { |
293 | struct ichsmb_softc *sc = cookie; | | 294 | struct ichsmb_softc *sc = cookie; |
294 | const uint8_t *b; | | 295 | const uint8_t *b; |
295 | uint8_t ctl = 0, st; | | 296 | uint8_t ctl = 0, st; |
296 | int retries; | | 297 | int retries; |
297 | char fbuf[64]; | | 298 | char fbuf[64]; |
298 | | | 299 | |
299 | DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " | | 300 | DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, " |
300 | "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen, | | 301 | "flags 0x%02x\n", device_xname(sc->sc_dev), op, addr, cmdlen, |
301 | len, flags)); | | 302 | len, flags)); |
302 | | | 303 | |
303 | mutex_enter(&sc->sc_exec_lock); | | 304 | mutex_enter(&sc->sc_exec_lock); |
304 | | | 305 | |
305 | /* Clear status bits */ | | 306 | /* Clear status bits */ |
306 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, | | 307 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, |
307 | LPCIB_SMB_HS_INTR | LPCIB_SMB_HS_DEVERR | | | 308 | LPCIB_SMB_HS_INTR | LPCIB_SMB_HS_DEVERR | |
308 | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED); | | 309 | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED); |
309 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, 1, | | 310 | bus_space_barrier(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, 1, |
310 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); | | 311 | BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); |
311 | | | 312 | |
312 | /* Wait for bus to be idle */ | | 313 | /* Wait for bus to be idle */ |
313 | for (retries = 100; retries > 0; retries--) { | | 314 | for (retries = 100; retries > 0; retries--) { |
314 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); | | 315 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); |
315 | if (!(st & LPCIB_SMB_HS_BUSY)) | | 316 | if (!(st & LPCIB_SMB_HS_BUSY)) |
316 | break; | | 317 | break; |
317 | DELAY(ICHIIC_DELAY); | | 318 | DELAY(ICHIIC_DELAY); |
318 | } | | 319 | } |
319 | #ifdef ICHIIC_DEBUG | | 320 | #ifdef ICHIIC_DEBUG |
320 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); | | 321 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); |
321 | printf("%s: exec: st %s\n", device_xname(sc->sc_dev), fbuf); | | 322 | printf("%s: exec: st %s\n", device_xname(sc->sc_dev), fbuf); |
322 | #endif | | 323 | #endif |
323 | if (st & LPCIB_SMB_HS_BUSY) { | | 324 | if (st & LPCIB_SMB_HS_BUSY) { |
324 | mutex_exit(&sc->sc_exec_lock); | | 325 | mutex_exit(&sc->sc_exec_lock); |
325 | return (EBUSY); | | 326 | return (EBUSY); |
326 | } | | 327 | } |
327 | | | 328 | |
328 | if (sc->sc_poll) | | 329 | if (sc->sc_poll) |
329 | flags |= I2C_F_POLL; | | 330 | flags |= I2C_F_POLL; |
330 | | | 331 | |
331 | if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || | | 332 | if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 || |
332 | (cmdlen == 0 && len > 1)) { | | 333 | (cmdlen == 0 && len > 1)) { |
333 | mutex_exit(&sc->sc_exec_lock); | | 334 | mutex_exit(&sc->sc_exec_lock); |
334 | return (EINVAL); | | 335 | return (EINVAL); |
335 | } | | 336 | } |
336 | | | 337 | |
337 | /* Setup transfer */ | | 338 | /* Setup transfer */ |
338 | sc->sc_i2c_xfer.op = op; | | 339 | sc->sc_i2c_xfer.op = op; |
339 | sc->sc_i2c_xfer.buf = buf; | | 340 | sc->sc_i2c_xfer.buf = buf; |
340 | sc->sc_i2c_xfer.len = len; | | 341 | sc->sc_i2c_xfer.len = len; |
341 | sc->sc_i2c_xfer.flags = flags; | | 342 | sc->sc_i2c_xfer.flags = flags; |
342 | sc->sc_i2c_xfer.error = 0; | | 343 | sc->sc_i2c_xfer.error = 0; |
343 | sc->sc_i2c_xfer.done = false; | | 344 | sc->sc_i2c_xfer.done = false; |
344 | | | 345 | |
345 | /* Set slave address and transfer direction */ | | 346 | /* Set slave address and transfer direction */ |
346 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_TXSLVA, | | 347 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_TXSLVA, |
347 | LPCIB_SMB_TXSLVA_ADDR(addr) | | | 348 | LPCIB_SMB_TXSLVA_ADDR(addr) | |
348 | (I2C_OP_READ_P(op) ? LPCIB_SMB_TXSLVA_READ : 0)); | | 349 | (I2C_OP_READ_P(op) ? LPCIB_SMB_TXSLVA_READ : 0)); |
349 | | | 350 | |
350 | b = (const uint8_t *)cmdbuf; | | 351 | b = (const uint8_t *)cmdbuf; |
351 | if (cmdlen > 0) | | 352 | if (cmdlen > 0) |
352 | /* Set command byte */ | | 353 | /* Set command byte */ |
353 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HCMD, b[0]); | | 354 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HCMD, b[0]); |
354 | | | 355 | |
355 | if (I2C_OP_WRITE_P(op)) { | | 356 | if (I2C_OP_WRITE_P(op)) { |
356 | /* Write data */ | | 357 | /* Write data */ |
357 | b = buf; | | 358 | b = buf; |
358 | if (cmdlen == 0 && len == 1) | | 359 | if (cmdlen == 0 && len == 1) |
359 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 360 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
360 | LPCIB_SMB_HCMD, b[0]); | | 361 | LPCIB_SMB_HCMD, b[0]); |
361 | else if (len > 0) | | 362 | else if (len > 0) |
362 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 363 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
363 | LPCIB_SMB_HD0, b[0]); | | 364 | LPCIB_SMB_HD0, b[0]); |
364 | if (len > 1) | | 365 | if (len > 1) |
365 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, | | 366 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, |
366 | LPCIB_SMB_HD1, b[1]); | | 367 | LPCIB_SMB_HD1, b[1]); |
367 | } | | 368 | } |
368 | | | 369 | |
369 | /* Set SMBus command */ | | 370 | /* Set SMBus command */ |
370 | if (cmdlen == 0) { | | 371 | if (cmdlen == 0) { |
371 | if (len == 0) | | 372 | if (len == 0) |
372 | ctl = LPCIB_SMB_HC_CMD_QUICK; | | 373 | ctl = LPCIB_SMB_HC_CMD_QUICK; |
373 | else | | 374 | else |
374 | ctl = LPCIB_SMB_HC_CMD_BYTE; | | 375 | ctl = LPCIB_SMB_HC_CMD_BYTE; |
375 | } else if (len == 1) | | 376 | } else if (len == 1) |
376 | ctl = LPCIB_SMB_HC_CMD_BDATA; | | 377 | ctl = LPCIB_SMB_HC_CMD_BDATA; |
377 | else if (len == 2) | | 378 | else if (len == 2) |
378 | ctl = LPCIB_SMB_HC_CMD_WDATA; | | 379 | ctl = LPCIB_SMB_HC_CMD_WDATA; |
379 | | | 380 | |
380 | if ((flags & I2C_F_POLL) == 0) | | 381 | if ((flags & I2C_F_POLL) == 0) |
381 | ctl |= LPCIB_SMB_HC_INTREN; | | 382 | ctl |= LPCIB_SMB_HC_INTREN; |
382 | | | 383 | |
383 | /* Start transaction */ | | 384 | /* Start transaction */ |
384 | ctl |= LPCIB_SMB_HC_START; | | 385 | ctl |= LPCIB_SMB_HC_START; |
385 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, ctl); | | 386 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, ctl); |
386 | | | 387 | |
387 | if (flags & I2C_F_POLL) { | | 388 | if (flags & I2C_F_POLL) { |
388 | /* Poll for completion */ | | 389 | /* Poll for completion */ |
389 | DELAY(ICHIIC_DELAY); | | 390 | DELAY(ICHIIC_DELAY); |
390 | for (retries = 1000; retries > 0; retries--) { | | 391 | for (retries = 1000; retries > 0; retries--) { |
391 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 392 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
392 | LPCIB_SMB_HS); | | 393 | LPCIB_SMB_HS); |
393 | if ((st & LPCIB_SMB_HS_BUSY) == 0) | | 394 | if ((st & LPCIB_SMB_HS_BUSY) == 0) |
394 | break; | | 395 | break; |
395 | DELAY(ICHIIC_DELAY); | | 396 | DELAY(ICHIIC_DELAY); |
396 | } | | 397 | } |
397 | if (st & LPCIB_SMB_HS_BUSY) | | 398 | if (st & LPCIB_SMB_HS_BUSY) |
398 | goto timeout; | | 399 | goto timeout; |
399 | ichsmb_intr(sc); | | 400 | ichsmb_intr(sc); |
400 | } else { | | 401 | } else { |
401 | /* Wait for interrupt */ | | 402 | /* Wait for interrupt */ |
402 | while (! sc->sc_i2c_xfer.done) { | | 403 | while (! sc->sc_i2c_xfer.done) { |
403 | if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock, | | 404 | if (cv_timedwait(&sc->sc_exec_wait, &sc->sc_exec_lock, |
404 | ICHIIC_TIMEOUT * hz)) | | 405 | ICHIIC_TIMEOUT * hz)) |
405 | goto timeout; | | 406 | goto timeout; |
406 | } | | 407 | } |
407 | } | | 408 | } |
408 | | | 409 | |
409 | int error = sc->sc_i2c_xfer.error; | | 410 | int error = sc->sc_i2c_xfer.error; |
410 | mutex_exit(&sc->sc_exec_lock); | | 411 | mutex_exit(&sc->sc_exec_lock); |
411 | | | 412 | |
412 | return (error); | | 413 | return (error); |
413 | | | 414 | |
414 | timeout: | | 415 | timeout: |
415 | /* | | 416 | /* |
416 | * Transfer timeout. Kill the transaction and clear status bits. | | 417 | * Transfer timeout. Kill the transaction and clear status bits. |
417 | */ | | 418 | */ |
418 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, | | 419 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HC, |
419 | LPCIB_SMB_HC_KILL); | | 420 | LPCIB_SMB_HC_KILL); |
420 | DELAY(ICHIIC_DELAY); | | 421 | DELAY(ICHIIC_DELAY); |
421 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); | | 422 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); |
422 | if ((st & LPCIB_SMB_HS_FAILED) == 0) { | | 423 | if ((st & LPCIB_SMB_HS_FAILED) == 0) { |
423 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); | | 424 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); |
424 | aprint_error_dev(sc->sc_dev, "abort failed, status %s\n", | | 425 | aprint_error_dev(sc->sc_dev, "abort failed, status %s\n", |
425 | fbuf); | | 426 | fbuf); |
426 | } | | 427 | } |
427 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); | | 428 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); |
428 | mutex_exit(&sc->sc_exec_lock); | | 429 | mutex_exit(&sc->sc_exec_lock); |
429 | return (ETIMEDOUT); | | 430 | return (ETIMEDOUT); |
430 | } | | 431 | } |
431 | | | 432 | |
432 | static int | | 433 | static int |
433 | ichsmb_intr(void *arg) | | 434 | ichsmb_intr(void *arg) |
434 | { | | 435 | { |
435 | struct ichsmb_softc *sc = arg; | | 436 | struct ichsmb_softc *sc = arg; |
436 | uint8_t st; | | 437 | uint8_t st; |
437 | uint8_t *b; | | 438 | uint8_t *b; |
438 | size_t len; | | 439 | size_t len; |
439 | #ifdef ICHIIC_DEBUG | | 440 | #ifdef ICHIIC_DEBUG |
440 | char fbuf[64]; | | 441 | char fbuf[64]; |
441 | #endif | | 442 | #endif |
442 | | | 443 | |
443 | /* Read status */ | | 444 | /* Read status */ |
444 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); | | 445 | st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS); |
445 | | | 446 | |
446 | /* Clear status bits */ | | 447 | /* Clear status bits */ |
447 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); | | 448 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, LPCIB_SMB_HS, st); |
448 | | | 449 | |
449 | /* XXX Ignore SMBALERT# for now */ | | 450 | /* XXX Ignore SMBALERT# for now */ |
450 | if ((st & LPCIB_SMB_HS_BUSY) != 0 || (st & (LPCIB_SMB_HS_INTR | | | 451 | if ((st & LPCIB_SMB_HS_BUSY) != 0 || (st & (LPCIB_SMB_HS_INTR | |
451 | LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED | | | 452 | LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED | |
452 | LPCIB_SMB_HS_BDONE)) == 0) | | 453 | LPCIB_SMB_HS_BDONE)) == 0) |
453 | /* Interrupt was not for us */ | | 454 | /* Interrupt was not for us */ |
454 | return (0); | | 455 | return (0); |
455 | | | 456 | |
456 | #ifdef ICHIIC_DEBUG | | 457 | #ifdef ICHIIC_DEBUG |
457 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); | | 458 | snprintb(fbuf, sizeof(fbuf), LPCIB_SMB_HS_BITS, st); |
458 | printf("%s: intr st %s\n", device_xname(sc->sc_dev), fbuf); | | 459 | printf("%s: intr st %s\n", device_xname(sc->sc_dev), fbuf); |
459 | #endif | | 460 | #endif |
460 | | | 461 | |
461 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) | | 462 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) |
462 | mutex_enter(&sc->sc_exec_lock); | | 463 | mutex_enter(&sc->sc_exec_lock); |
463 | | | 464 | |
464 | /* Check for errors */ | | 465 | /* Check for errors */ |
465 | if (st & (LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED)) { | | 466 | if (st & (LPCIB_SMB_HS_DEVERR | LPCIB_SMB_HS_BUSERR | LPCIB_SMB_HS_FAILED)) { |
466 | sc->sc_i2c_xfer.error = EIO; | | 467 | sc->sc_i2c_xfer.error = EIO; |
467 | goto done; | | 468 | goto done; |
468 | } | | 469 | } |
469 | | | 470 | |
470 | if (st & LPCIB_SMB_HS_INTR) { | | 471 | if (st & LPCIB_SMB_HS_INTR) { |
471 | if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) | | 472 | if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op)) |
472 | goto done; | | 473 | goto done; |
473 | | | 474 | |
474 | /* Read data */ | | 475 | /* Read data */ |
475 | b = sc->sc_i2c_xfer.buf; | | 476 | b = sc->sc_i2c_xfer.buf; |
476 | len = sc->sc_i2c_xfer.len; | | 477 | len = sc->sc_i2c_xfer.len; |
477 | if (len > 0) | | 478 | if (len > 0) |
478 | b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 479 | b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
479 | LPCIB_SMB_HD0); | | 480 | LPCIB_SMB_HD0); |
480 | if (len > 1) | | 481 | if (len > 1) |
481 | b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, | | 482 | b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
482 | LPCIB_SMB_HD1); | | 483 | LPCIB_SMB_HD1); |
483 | } | | 484 | } |
484 | | | 485 | |
485 | done: | | 486 | done: |
486 | sc->sc_i2c_xfer.done = true; | | 487 | sc->sc_i2c_xfer.done = true; |
487 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) { | | 488 | if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0) { |
488 | cv_signal(&sc->sc_exec_wait); | | 489 | cv_signal(&sc->sc_exec_wait); |
489 | mutex_exit(&sc->sc_exec_lock); | | 490 | mutex_exit(&sc->sc_exec_lock); |
490 | } | | 491 | } |
491 | return (1); | | 492 | return (1); |
492 | } | | 493 | } |
493 | | | 494 | |
494 | MODULE(MODULE_CLASS_DRIVER, ichsmb, "pci,iic"); | | 495 | MODULE(MODULE_CLASS_DRIVER, ichsmb, "pci,iic"); |
495 | | | 496 | |
496 | #ifdef _MODULE | | 497 | #ifdef _MODULE |
497 | #include "ioconf.c" | | 498 | #include "ioconf.c" |
498 | #endif | | 499 | #endif |
499 | | | 500 | |
500 | static int | | 501 | static int |
501 | ichsmb_modcmd(modcmd_t cmd, void *opaque) | | 502 | ichsmb_modcmd(modcmd_t cmd, void *opaque) |
502 | { | | 503 | { |
503 | int error = 0; | | 504 | int error = 0; |
504 | | | 505 | |
505 | switch (cmd) { | | 506 | switch (cmd) { |
506 | case MODULE_CMD_INIT: | | 507 | case MODULE_CMD_INIT: |
507 | #ifdef _MODULE | | 508 | #ifdef _MODULE |
508 | error = config_init_component(cfdriver_ioconf_ichsmb, | | 509 | error = config_init_component(cfdriver_ioconf_ichsmb, |
509 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); | | 510 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); |
510 | #endif | | 511 | #endif |
511 | break; | | 512 | break; |
512 | case MODULE_CMD_FINI: | | 513 | case MODULE_CMD_FINI: |
513 | #ifdef _MODULE | | 514 | #ifdef _MODULE |
514 | error = config_fini_component(cfdriver_ioconf_ichsmb, | | 515 | error = config_fini_component(cfdriver_ioconf_ichsmb, |
515 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); | | 516 | cfattach_ioconf_ichsmb, cfdata_ioconf_ichsmb); |
516 | #endif | | 517 | #endif |
517 | break; | | 518 | break; |
518 | default: | | 519 | default: |
519 | #ifdef _MODULE | | 520 | #ifdef _MODULE |
520 | error = ENOTTY; | | 521 | error = ENOTTY; |
521 | #endif | | 522 | #endif |
522 | break; | | 523 | break; |
523 | } | | 524 | } |
524 | | | 525 | |
525 | return error; | | 526 | return error; |
526 | } | | 527 | } |