kernel: Remove newlines from the panic messages that have one.
[dragonfly.git] / sys / dev / powermng / ichsmb / ichsmb.c
1 /*-
2  * ichsmb.c
3  *
4  * Author: Archie Cobbs <archie@freebsd.org>
5  * Copyright (c) 2000 Whistle Communications, Inc.
6  * All rights reserved.
7  *
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  *
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * $FreeBSD: src/sys/dev/ichsmb/ichsmb.c,v 1.20 2009/02/03 16:14:37 jhb Exp $
38  */
39
40 /*
41  * Support for the SMBus controller logical device which is part of the
42  * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips.
43  *
44  * This driver assumes that the generic SMBus code will ensure that
45  * at most one process at a time calls into the SMBus methods below.
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/errno.h>
52 #include <sys/globaldata.h>
53 #include <sys/lock.h>
54 #include <sys/module.h>
55 #include <sys/syslog.h>
56 #include <sys/bus.h>
57
58 #include <sys/rman.h>
59
60 #include <bus/smbus/smbconf.h>
61
62 #include <dev/powermng/ichsmb/ichsmb_var.h>
63 #include <dev/powermng/ichsmb/ichsmb_reg.h>
64
65 /*
66  * Enable debugging by defining ICHSMB_DEBUG to a non-zero value.
67  */
68 #define ICHSMB_DEBUG    0
69 #if ICHSMB_DEBUG != 0 && defined(__CC_SUPPORTS___FUNC__)
70 #define DBG(fmt, args...)       \
71         do { kprintf("%s: " fmt, __func__ , ## args); } while (0)
72 #else
73 #define DBG(fmt, args...)       do { } while (0)
74 #endif
75
76 /*
77  * Our child device driver name
78  */
79 #define DRIVER_SMBUS    "smbus"
80
81 /*
82  * Internal functions
83  */
84 static int ichsmb_wait(sc_p sc);
85
86 /********************************************************************
87                 BUS-INDEPENDENT BUS METHODS
88 ********************************************************************/
89
90 /*
91  * Handle probe-time duties that are independent of the bus
92  * our device lives on.
93  */
94 int
95 ichsmb_probe(device_t dev)
96 {
97         return (BUS_PROBE_DEFAULT);
98 }
99
100 /*
101  * Handle attach-time duties that are independent of the bus
102  * our device lives on.
103  */
104 int
105 ichsmb_attach(device_t dev)
106 {
107         const sc_p sc = device_get_softc(dev);
108         int error;
109
110         /* Create mutex */
111         lockinit(&sc->mutex, "ichsmb", 0, LK_CANRECURSE);
112
113         /* Add child: an instance of the "smbus" device */
114         if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) {
115                 device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS);
116                 error = ENXIO;
117                 goto fail;
118         }
119
120         /* Clear interrupt conditions */
121         bus_write_1(sc->io_res, ICH_HST_STA, 0xff);
122
123         /* Set up interrupt handler */
124         error = bus_setup_intr(dev, sc->irq_res, 0,
125             ichsmb_device_intr, sc, &sc->irq_handle, NULL);
126         if (error != 0) {
127                 device_printf(dev, "can't setup irq\n");
128                 goto fail;
129         }
130
131         /* Attach "smbus" child */
132         if ((error = bus_generic_attach(dev)) != 0) {
133                 device_printf(dev, "failed to attach child: %d\n", error);
134                 goto fail;
135         }
136
137         return (0);
138
139 fail:
140         lockuninit(&sc->mutex);
141         return (error);
142 }
143
144 /********************************************************************
145                         SMBUS METHODS
146 ********************************************************************/
147
148 int
149 ichsmb_callback(device_t dev, int index, void *data)
150 {
151         int smb_error = 0;
152
153         DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
154         switch (index) {
155         case SMB_REQUEST_BUS:
156                 break;
157         case SMB_RELEASE_BUS:
158                 break;
159         default:
160                 smb_error = SMB_EABORT; /* XXX */
161                 break;
162         }
163         DBG("smb_error=%d\n", smb_error);
164         return (smb_error);
165 }
166
167 int
168 ichsmb_quick(device_t dev, u_char slave, int how)
169 {
170         const sc_p sc = device_get_softc(dev);
171         int smb_error;
172
173         DBG("slave=0x%02x how=%d\n", slave, how);
174         KASSERT(sc->ich_cmd == -1,
175             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
176         switch (how) {
177         case SMB_QREAD:
178         case SMB_QWRITE:
179                 lockmgr(&sc->mutex, LK_EXCLUSIVE);
180                 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
181                 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
182                     slave | (how == SMB_QREAD ?
183                         ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
184                 bus_write_1(sc->io_res, ICH_HST_CNT,
185                     ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
186                 smb_error = ichsmb_wait(sc);
187                 lockmgr(&sc->mutex, LK_RELEASE);
188                 break;
189         default:
190                 smb_error = SMB_ENOTSUPP;
191         }
192         DBG("smb_error=%d\n", smb_error);
193         return (smb_error);
194 }
195
196 int
197 ichsmb_sendb(device_t dev, u_char slave, char byte)
198 {
199         const sc_p sc = device_get_softc(dev);
200         int smb_error;
201
202         DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
203         KASSERT(sc->ich_cmd == -1,
204             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
205         lockmgr(&sc->mutex, LK_EXCLUSIVE);
206         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
207         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
208             slave | ICH_XMIT_SLVA_WRITE);
209         bus_write_1(sc->io_res, ICH_HST_CMD, byte);
210         bus_write_1(sc->io_res, ICH_HST_CNT,
211             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
212         smb_error = ichsmb_wait(sc);
213         lockmgr(&sc->mutex, LK_RELEASE);
214         DBG("smb_error=%d\n", smb_error);
215         return (smb_error);
216 }
217
218 int
219 ichsmb_recvb(device_t dev, u_char slave, char *byte)
220 {
221         const sc_p sc = device_get_softc(dev);
222         int smb_error;
223
224         DBG("slave=0x%02x\n", slave);
225         KASSERT(sc->ich_cmd == -1,
226             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
227         lockmgr(&sc->mutex, LK_EXCLUSIVE);
228         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
229         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
230             slave | ICH_XMIT_SLVA_READ);
231         bus_write_1(sc->io_res, ICH_HST_CNT,
232             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
233         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
234                 *byte = bus_read_1(sc->io_res, ICH_D0);
235         lockmgr(&sc->mutex, LK_RELEASE);
236         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
237         return (smb_error);
238 }
239
240 int
241 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
242 {
243         const sc_p sc = device_get_softc(dev);
244         int smb_error;
245
246         DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
247             slave, (u_char)cmd, (u_char)byte);
248         KASSERT(sc->ich_cmd == -1,
249             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
250         lockmgr(&sc->mutex, LK_EXCLUSIVE);
251         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
252         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
253             slave | ICH_XMIT_SLVA_WRITE);
254         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
255         bus_write_1(sc->io_res, ICH_D0, byte);
256         bus_write_1(sc->io_res, ICH_HST_CNT,
257             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
258         smb_error = ichsmb_wait(sc);
259         lockmgr(&sc->mutex, LK_RELEASE);
260         DBG("smb_error=%d\n", smb_error);
261         return (smb_error);
262 }
263
264 int
265 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
266 {
267         const sc_p sc = device_get_softc(dev);
268         int smb_error;
269
270         DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
271             slave, (u_char)cmd, (u_int16_t)word);
272         KASSERT(sc->ich_cmd == -1,
273             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
274         lockmgr(&sc->mutex, LK_EXCLUSIVE);
275         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
276         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
277             slave | ICH_XMIT_SLVA_WRITE);
278         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
279         bus_write_1(sc->io_res, ICH_D0, word & 0xff);
280         bus_write_1(sc->io_res, ICH_D1, word >> 8);
281         bus_write_1(sc->io_res, ICH_HST_CNT,
282             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
283         smb_error = ichsmb_wait(sc);
284         lockmgr(&sc->mutex, LK_RELEASE);
285         DBG("smb_error=%d\n", smb_error);
286         return (smb_error);
287 }
288
289 int
290 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
291 {
292         const sc_p sc = device_get_softc(dev);
293         int smb_error;
294
295         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
296         KASSERT(sc->ich_cmd == -1,
297             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
298         lockmgr(&sc->mutex, LK_EXCLUSIVE);
299         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
300         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
301             slave | ICH_XMIT_SLVA_READ);
302         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
303         bus_write_1(sc->io_res, ICH_HST_CNT,
304             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
305         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
306                 *byte = bus_read_1(sc->io_res, ICH_D0);
307         lockmgr(&sc->mutex, LK_RELEASE);
308         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
309         return (smb_error);
310 }
311
312 int
313 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
314 {
315         const sc_p sc = device_get_softc(dev);
316         int smb_error;
317
318         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
319         KASSERT(sc->ich_cmd == -1,
320             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
321         lockmgr(&sc->mutex, LK_EXCLUSIVE);
322         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
323         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
324             slave | ICH_XMIT_SLVA_READ);
325         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
326         bus_write_1(sc->io_res, ICH_HST_CNT,
327             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
328         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
329                 *word = (bus_read_1(sc->io_res,
330                         ICH_D0) & 0xff)
331                   | (bus_read_1(sc->io_res,
332                         ICH_D1) << 8);
333         }
334         lockmgr(&sc->mutex, LK_RELEASE);
335         DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
336         return (smb_error);
337 }
338
339 int
340 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
341 {
342         const sc_p sc = device_get_softc(dev);
343         int smb_error;
344
345         DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
346             slave, (u_char)cmd, (u_int16_t)sdata);
347         KASSERT(sc->ich_cmd == -1,
348             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
349         lockmgr(&sc->mutex, LK_EXCLUSIVE);
350         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
351         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
352             slave | ICH_XMIT_SLVA_WRITE);
353         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
354         bus_write_1(sc->io_res, ICH_D0, sdata & 0xff);
355         bus_write_1(sc->io_res, ICH_D1, sdata >> 8);
356         bus_write_1(sc->io_res, ICH_HST_CNT,
357             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
358         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
359                 *rdata = (bus_read_1(sc->io_res,
360                         ICH_D0) & 0xff)
361                   | (bus_read_1(sc->io_res,
362                         ICH_D1) << 8);
363         }
364         lockmgr(&sc->mutex, LK_RELEASE);
365         DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
366         return (smb_error);
367 }
368
369 int
370 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
371 {
372         const sc_p sc = device_get_softc(dev);
373         int smb_error;
374
375         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
376 #if ICHSMB_DEBUG
377 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
378         {
379             u_char *p;
380
381             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
382                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
383                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
384                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
385                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]),
386                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
387             }
388         }
389 #undef DISP
390 #endif
391         KASSERT(sc->ich_cmd == -1,
392             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
393         if (count < 1 || count > 32)
394                 return (SMB_EINVAL);
395         bcopy(buf, sc->block_data, count);
396         sc->block_count = count;
397         sc->block_index = 1;
398         sc->block_write = 1;
399
400         lockmgr(&sc->mutex, LK_EXCLUSIVE);
401         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
402         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
403             slave | ICH_XMIT_SLVA_WRITE);
404         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
405         bus_write_1(sc->io_res, ICH_D0, count);
406         bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]);
407         bus_write_1(sc->io_res, ICH_HST_CNT,
408             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
409         smb_error = ichsmb_wait(sc);
410         lockmgr(&sc->mutex, LK_RELEASE);
411         DBG("smb_error=%d\n", smb_error);
412         return (smb_error);
413 }
414
415 int
416 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
417 {
418         const sc_p sc = device_get_softc(dev);
419         int smb_error;
420
421         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
422         KASSERT(sc->ich_cmd == -1,
423             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
424         if (*count < 1 || *count > 32)
425                 return (SMB_EINVAL);
426         bzero(sc->block_data, sizeof(sc->block_data));
427         sc->block_count = 0;
428         sc->block_index = 0;
429         sc->block_write = 0;
430
431         lockmgr(&sc->mutex, LK_EXCLUSIVE);
432         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
433         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
434             slave | ICH_XMIT_SLVA_READ);
435         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
436         bus_write_1(sc->io_res, ICH_D0, *count); /* XXX? */
437         bus_write_1(sc->io_res, ICH_HST_CNT,
438             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
439         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
440                 bcopy(sc->block_data, buf, min(sc->block_count, *count));
441                 *count = sc->block_count;
442         }
443         lockmgr(&sc->mutex, LK_RELEASE);
444         DBG("smb_error=%d\n", smb_error);
445 #if ICHSMB_DEBUG
446 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
447         {
448             u_char *p;
449
450             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
451                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
452                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
453                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
454                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]),
455                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
456             }
457         }
458 #undef DISP
459 #endif
460         return (smb_error);
461 }
462
463 /********************************************************************
464                         OTHER FUNCTIONS
465 ********************************************************************/
466
467 /*
468  * This table describes what interrupts we should ever expect to
469  * see after each ICH command, not including the SMBALERT interrupt.
470  */
471 static const u_int8_t ichsmb_state_irqs[] = {
472         /* quick */
473         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
474         /* byte */
475         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
476         /* byte data */
477         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
478         /* word data */
479         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
480         /* process call */
481         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
482         /* block */
483         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
484             | ICH_HST_STA_BYTE_DONE_STS),
485         /* i2c read (not used) */
486         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
487             | ICH_HST_STA_BYTE_DONE_STS)
488 };
489
490 /*
491  * Interrupt handler. This handler is bus-independent. Note that our
492  * interrupt may be shared, so we must handle "false" interrupts.
493  */
494 void
495 ichsmb_device_intr(void *cookie)
496 {
497         const sc_p sc = cookie;
498         const device_t dev = sc->dev;
499         const int maxloops = 16;
500         u_int8_t status;
501         u_int8_t ok_bits;
502         int cmd_index;
503         int count;
504
505         lockmgr(&sc->mutex, LK_EXCLUSIVE);
506         for (count = 0; count < maxloops; count++) {
507
508                 /* Get and reset status bits */
509                 status = bus_read_1(sc->io_res, ICH_HST_STA);
510 #if ICHSMB_DEBUG
511                 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
512                     || count > 0) {
513                         DBG("%d stat=0x%02x\n", count, status);
514                 }
515 #endif
516                 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY);
517                 if (status == 0)
518                         break;
519
520                 /* Check for unexpected interrupt */
521                 ok_bits = ICH_HST_STA_SMBALERT_STS;
522                 cmd_index = sc->ich_cmd >> 2;
523                 if (sc->ich_cmd != -1) {
524                         KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
525                             ("%s: ich_cmd=%d", device_get_nameunit(dev),
526                             sc->ich_cmd));
527                         ok_bits |= ichsmb_state_irqs[cmd_index];
528                 }
529                 if ((status & ~ok_bits) != 0) {
530                         device_printf(dev, "irq 0x%02x during %d\n", status,
531                             cmd_index);
532                         bus_write_1(sc->io_res,
533                             ICH_HST_STA, (status & ~ok_bits));
534                         continue;
535                 }
536
537                 /* Handle SMBALERT interrupt */
538                 if (status & ICH_HST_STA_SMBALERT_STS) {
539                         static int smbalert_count = 16;
540                         if (smbalert_count > 0) {
541                                 device_printf(dev, "SMBALERT# rec'd\n");
542                                 if (--smbalert_count == 0) {
543                                         device_printf(dev,
544                                             "not logging anymore\n");
545                                 }
546                         }
547                 }
548
549                 /* Check for bus error */
550                 if (status & ICH_HST_STA_BUS_ERR) {
551                         sc->smb_error = SMB_ECOLLI;     /* XXX SMB_EBUSERR? */
552                         goto finished;
553                 }
554
555                 /* Check for device error */
556                 if (status & ICH_HST_STA_DEV_ERR) {
557                         sc->smb_error = SMB_ENOACK;     /* or SMB_ETIMEOUT? */
558                         goto finished;
559                 }
560
561                 /* Check for byte completion in block transfer */
562                 if (status & ICH_HST_STA_BYTE_DONE_STS) {
563                         if (sc->block_write) {
564                                 if (sc->block_index < sc->block_count) {
565
566                                         /* Write next byte */
567                                         bus_write_1(sc->io_res,
568                                             ICH_BLOCK_DB,
569                                             sc->block_data[sc->block_index++]);
570                                 }
571                         } else {
572
573                                 /* First interrupt, get the count also */
574                                 if (sc->block_index == 0) {
575                                         sc->block_count = bus_read_1(
576                                             sc->io_res, ICH_D0);
577                                 }
578
579                                 /* Get next byte, if any */
580                                 if (sc->block_index < sc->block_count) {
581
582                                         /* Read next byte */
583                                         sc->block_data[sc->block_index++] =
584                                             bus_read_1(sc->io_res,
585                                               ICH_BLOCK_DB);
586
587                                         /* Set "LAST_BYTE" bit before reading
588                                            the last byte of block data */
589                                         if (sc->block_index
590                                             >= sc->block_count - 1) {
591                                                 bus_write_1(sc->io_res,
592                                                     ICH_HST_CNT,
593                                                     ICH_HST_CNT_LAST_BYTE
594                                                         | ICH_HST_CNT_INTREN
595                                                         | sc->ich_cmd);
596                                         }
597                                 }
598                         }
599                 }
600
601                 /* Check command completion */
602                 if (status & ICH_HST_STA_INTR) {
603                         sc->smb_error = SMB_ENOERR;
604 finished:
605                         sc->ich_cmd = -1;
606                         bus_write_1(sc->io_res,
607                             ICH_HST_STA, status);
608                         wakeup(sc);
609                         break;
610                 }
611
612                 /* Clear status bits and try again */
613                 bus_write_1(sc->io_res, ICH_HST_STA, status);
614         }
615         lockmgr(&sc->mutex, LK_RELEASE);
616
617         /* Too many loops? */
618         if (count == maxloops) {
619                 device_printf(dev, "interrupt loop, status=0x%02x\n",
620                     bus_read_1(sc->io_res, ICH_HST_STA));
621         }
622 }
623
624 /*
625  * Wait for command completion. Assumes mutex is held.
626  * Returns an SMB_* error code.
627  */
628 static int
629 ichsmb_wait(sc_p sc)
630 {
631         const device_t dev = sc->dev;
632         int error, smb_error;
633
634         KASSERT(sc->ich_cmd != -1,
635             ("%s: ich_cmd=%d", __func__ , sc->ich_cmd));
636         KKASSERT(lockstatus(&sc->mutex, curthread) != 0);
637         error = lksleep(sc, &sc->mutex, 0, "ichsmb", hz / 4);
638         DBG("msleep -> %d\n", error);
639         switch (error) {
640         case 0:
641                 smb_error = sc->smb_error;
642                 break;
643         case EWOULDBLOCK:
644                 device_printf(dev, "device timeout, status=0x%02x\n",
645                     bus_read_1(sc->io_res, ICH_HST_STA));
646                 sc->ich_cmd = -1;
647                 smb_error = SMB_ETIMEOUT;
648                 break;
649         default:
650                 smb_error = SMB_EABORT;
651                 break;
652         }
653         return (smb_error);
654 }
655
656 /*
657  * Release resources associated with device.
658  */
659 void
660 ichsmb_release_resources(sc_p sc)
661 {
662         const device_t dev = sc->dev;
663
664         if (sc->irq_handle != NULL) {
665                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
666                 sc->irq_handle = NULL;
667         }
668         if (sc->irq_res != NULL) {
669                 bus_release_resource(dev,
670                     SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
671                 sc->irq_res = NULL;
672         }
673         if (sc->io_res != NULL) {
674                 bus_release_resource(dev,
675                     SYS_RES_IOPORT, sc->io_rid, sc->io_res);
676                 sc->io_res = NULL;
677         }
678 }
679
680 int
681 ichsmb_detach(device_t dev)
682 {
683         const sc_p sc = device_get_softc(dev);
684         int error;
685
686         error = bus_generic_detach(dev);
687         if (error)
688                 return (error);
689         device_delete_child(dev, sc->smb);
690         ichsmb_release_resources(sc);
691         lockuninit(&sc->mutex);
692
693         return 0;
694 }
695
696 DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, NULL, NULL);