]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ichsmb/ichsmb.c
This commit was generated by cvs2svn to compensate for changes in r142403,
[FreeBSD/FreeBSD.git] / sys / dev / 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
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 /*
42  * Support for the SMBus controller logical device which is part of the
43  * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips.
44  *
45  * This driver assumes that the generic SMBus code will ensure that
46  * at most one process at a time calls into the SMBus methods below.
47  */
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/errno.h>
53 #include <sys/lock.h>
54 #include <sys/mutex.h>
55 #include <sys/syslog.h>
56 #include <sys/bus.h>
57
58 #include <machine/bus.h>
59 #include <sys/rman.h>
60 #include <machine/resource.h>
61
62 #include <dev/smbus/smbconf.h>
63
64 #include <dev/ichsmb/ichsmb_var.h>
65 #include <dev/ichsmb/ichsmb_reg.h>
66
67 /*
68  * Enable debugging by defining ICHSMB_DEBUG to a non-zero value.
69  */
70 #define ICHSMB_DEBUG    0
71 #if ICHSMB_DEBUG != 0 && (defined(__GNUC__) || defined(__INTEL_COMPILER))
72 #define DBG(fmt, args...)       \
73         do { log(LOG_DEBUG, "%s: " fmt, __func__ , ## args); } while (0)
74 #else
75 #define DBG(fmt, args...)       do { } while (0)
76 #endif
77
78 /*
79  * Our child device driver name
80  */
81 #define DRIVER_SMBUS    "smbus"
82
83 /*
84  * Internal functions
85  */
86 static int ichsmb_wait(sc_p sc);
87
88 /********************************************************************
89                 BUS-INDEPENDENT BUS METHODS
90 ********************************************************************/
91
92 /*
93  * Handle probe-time duties that are independent of the bus
94  * our device lives on.
95  */
96 int
97 ichsmb_probe(device_t dev)
98 {
99         device_t smb;
100
101         /* Add child: an instance of the "smbus" device */
102         if ((smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) {
103                 log(LOG_ERR, "%s: no \"%s\" child found\n",
104                     device_get_nameunit(dev), DRIVER_SMBUS);
105                 return (ENXIO);
106         }
107         return (0);
108 }
109
110 /*
111  * Handle attach-time duties that are independent of the bus
112  * our device lives on.
113  */
114 int
115 ichsmb_attach(device_t dev)
116 {
117         const sc_p sc = device_get_softc(dev);
118         int error;
119
120         /* Clear interrupt conditions */
121         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff);
122
123         /* Add "smbus" child */
124         if ((error = bus_generic_attach(dev)) != 0) {
125                 log(LOG_ERR, "%s: failed to attach child: %d\n",
126                     device_get_nameunit(dev), error);
127                 return (ENXIO);
128         }
129
130         /* Create mutex */
131         mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF);
132         return (0);
133 }
134
135 /********************************************************************
136                         SMBUS METHODS
137 ********************************************************************/
138
139 int 
140 ichsmb_callback(device_t dev, int index, caddr_t data)
141 {
142         int smb_error = 0;
143
144         DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
145         switch (index) {
146         case SMB_REQUEST_BUS:
147                 break;
148         case SMB_RELEASE_BUS:
149                 break;
150         default:
151                 smb_error = SMB_EABORT; /* XXX */
152                 break;
153         }
154         DBG("smb_error=%d\n", smb_error);
155         return (smb_error);
156 }
157
158 int
159 ichsmb_quick(device_t dev, u_char slave, int how)
160 {
161         const sc_p sc = device_get_softc(dev);
162         int smb_error;
163
164         DBG("slave=0x%02x how=%d\n", slave, how);
165         KASSERT(sc->ich_cmd == -1,
166             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
167         switch (how) {
168         case SMB_QREAD:
169         case SMB_QWRITE:
170                 mtx_lock(&sc->mutex);
171                 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
172                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
173                     (slave << 1) | (how == SMB_QREAD ?
174                         ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
175                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
176                     ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
177                 smb_error = ichsmb_wait(sc);
178                 mtx_unlock(&sc->mutex);
179                 break;
180         default:
181                 smb_error = SMB_ENOTSUPP;
182         }
183         DBG("smb_error=%d\n", smb_error);
184         return (smb_error);
185 }
186
187 int
188 ichsmb_sendb(device_t dev, u_char slave, char byte)
189 {
190         const sc_p sc = device_get_softc(dev);
191         int smb_error;
192
193         DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
194         KASSERT(sc->ich_cmd == -1,
195             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
196         mtx_lock(&sc->mutex);
197         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
198         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
199             (slave << 1) | ICH_XMIT_SLVA_WRITE);
200         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte);
201         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
202             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
203         smb_error = ichsmb_wait(sc);
204         mtx_unlock(&sc->mutex);
205         DBG("smb_error=%d\n", smb_error);
206         return (smb_error);
207 }
208
209 int
210 ichsmb_recvb(device_t dev, u_char slave, char *byte)
211 {
212         const sc_p sc = device_get_softc(dev);
213         int smb_error;
214
215         DBG("slave=0x%02x\n", slave);
216         KASSERT(sc->ich_cmd == -1,
217             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
218         mtx_lock(&sc->mutex);
219         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
220         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
221             (slave << 1) | ICH_XMIT_SLVA_READ);
222         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
223             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
224         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
225                 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0);
226         mtx_unlock(&sc->mutex);
227         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
228         return (smb_error);
229 }
230
231 int
232 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
233 {
234         const sc_p sc = device_get_softc(dev);
235         int smb_error;
236
237         DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
238             slave, (u_char)cmd, (u_char)byte);
239         KASSERT(sc->ich_cmd == -1,
240             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
241         mtx_lock(&sc->mutex);
242         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
243         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
244             (slave << 1) | ICH_XMIT_SLVA_WRITE);
245         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
246         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte);
247         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
248             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
249         smb_error = ichsmb_wait(sc);
250         mtx_unlock(&sc->mutex);
251         DBG("smb_error=%d\n", smb_error);
252         return (smb_error);
253 }
254
255 int
256 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
257 {
258         const sc_p sc = device_get_softc(dev);
259         int smb_error;
260
261         DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
262             slave, (u_char)cmd, (u_int16_t)word);
263         KASSERT(sc->ich_cmd == -1,
264             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
265         mtx_lock(&sc->mutex);
266         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
267         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
268             (slave << 1) | ICH_XMIT_SLVA_WRITE);
269         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
270         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff);
271         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8);
272         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
273             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
274         smb_error = ichsmb_wait(sc);
275         mtx_unlock(&sc->mutex);
276         DBG("smb_error=%d\n", smb_error);
277         return (smb_error);
278 }
279
280 int
281 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
282 {
283         const sc_p sc = device_get_softc(dev);
284         int smb_error;
285
286         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
287         KASSERT(sc->ich_cmd == -1,
288             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
289         mtx_lock(&sc->mutex);
290         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
291         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
292             (slave << 1) | ICH_XMIT_SLVA_READ);
293         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
294         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
295             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
296         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
297                 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0);
298         mtx_unlock(&sc->mutex);
299         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
300         return (smb_error);
301 }
302
303 int
304 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
305 {
306         const sc_p sc = device_get_softc(dev);
307         int smb_error;
308
309         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
310         KASSERT(sc->ich_cmd == -1,
311             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
312         mtx_lock(&sc->mutex);
313         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
314         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
315             (slave << 1) | ICH_XMIT_SLVA_READ);
316         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
317         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
318             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
319         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
320                 *word = (bus_space_read_1(sc->io_bst,
321                         sc->io_bsh, ICH_D0) & 0xff)
322                   | (bus_space_read_1(sc->io_bst,
323                         sc->io_bsh, ICH_D1) << 8);
324         }
325         mtx_unlock(&sc->mutex);
326         DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
327         return (smb_error);
328 }
329
330 int
331 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
332 {
333         const sc_p sc = device_get_softc(dev);
334         int smb_error;
335
336         DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
337             slave, (u_char)cmd, (u_int16_t)sdata);
338         KASSERT(sc->ich_cmd == -1,
339             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
340         mtx_lock(&sc->mutex);
341         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
342         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
343             (slave << 1) | ICH_XMIT_SLVA_WRITE);
344         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
345         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff);
346         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8);
347         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
348             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
349         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
350                 *rdata = (bus_space_read_1(sc->io_bst,
351                         sc->io_bsh, ICH_D0) & 0xff)
352                   | (bus_space_read_1(sc->io_bst,
353                         sc->io_bsh, ICH_D1) << 8);
354         }
355         mtx_unlock(&sc->mutex);
356         DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
357         return (smb_error);
358 }
359
360 int
361 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
362 {
363         const sc_p sc = device_get_softc(dev);
364         int smb_error;
365
366         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
367 #if ICHSMB_DEBUG
368 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
369         {
370             u_char *p;
371
372             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
373                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
374                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
375                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
376                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
377                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
378             }
379         }
380 #undef DISP
381 #endif
382         KASSERT(sc->ich_cmd == -1,
383             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
384         if (count < 1 || count > 32)
385                 return (EINVAL);
386         bcopy(buf, sc->block_data, count);
387         sc->block_count = count;
388         sc->block_index = 1;
389         sc->block_write = 1;
390
391         mtx_lock(&sc->mutex);
392         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
393         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
394             (slave << 1) | ICH_XMIT_SLVA_WRITE);
395         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
396         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count);
397         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]);
398         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
399             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
400         smb_error = ichsmb_wait(sc);
401         mtx_unlock(&sc->mutex);
402         DBG("smb_error=%d\n", smb_error);
403         return (smb_error);
404 }
405
406 int
407 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
408 {
409         const sc_p sc = device_get_softc(dev);
410         int smb_error;
411
412         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
413         KASSERT(sc->ich_cmd == -1,
414             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
415         if (count < 1 || count > 32)
416                 return (EINVAL);
417         bzero(sc->block_data, sizeof(sc->block_data));
418         sc->block_count = count;
419         sc->block_index = 0;
420         sc->block_write = 0;
421
422         mtx_lock(&sc->mutex);
423         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
424         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
425             (slave << 1) | ICH_XMIT_SLVA_READ);
426         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
427         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); /* XXX? */
428         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
429             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
430         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
431                 bcopy(sc->block_data, buf, sc->block_count);
432         mtx_unlock(&sc->mutex);
433         DBG("smb_error=%d\n", smb_error);
434 #if ICHSMB_DEBUG
435 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
436         {
437             u_char *p;
438
439             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
440                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
441                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
442                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
443                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
444                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
445             }
446         }
447 #undef DISP
448 #endif
449         return (smb_error);
450 }
451
452 /********************************************************************
453                         OTHER FUNCTIONS
454 ********************************************************************/
455
456 /*
457  * This table describes what interrupts we should ever expect to
458  * see after each ICH command, not including the SMBALERT interrupt.
459  */
460 static const u_int8_t ichsmb_state_irqs[] = {
461         /* quick */
462         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
463         /* byte */
464         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
465         /* byte data */
466         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
467         /* word data */
468         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
469         /* process call */
470         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
471         /* block */
472         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
473             | ICH_HST_STA_BYTE_DONE_STS),
474         /* i2c read (not used) */
475         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
476             | ICH_HST_STA_BYTE_DONE_STS)
477 };
478
479 /*
480  * Interrupt handler. This handler is bus-independent. Note that our
481  * interrupt may be shared, so we must handle "false" interrupts.
482  */
483 void
484 ichsmb_device_intr(void *cookie)
485 {
486         const sc_p sc = cookie;
487         const device_t dev = sc->dev;
488         const int maxloops = 16;
489         u_int8_t status;
490         u_int8_t ok_bits;
491         int cmd_index;
492         int count;
493
494         mtx_lock(&sc->mutex);
495         for (count = 0; count < maxloops; count++) {
496
497                 /* Get and reset status bits */
498                 status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA);
499 #if ICHSMB_DEBUG
500                 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
501                     || count > 0) {
502                         DBG("%d stat=0x%02x\n", count, status);
503                 }
504 #endif
505                 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY);
506                 if (status == 0)
507                         break;
508
509                 /* Check for unexpected interrupt */
510                 ok_bits = ICH_HST_STA_SMBALERT_STS;
511                 cmd_index = sc->ich_cmd >> 2;
512                 if (sc->ich_cmd != -1) {
513                         KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
514                             ("%s: ich_cmd=%d", device_get_nameunit(dev),
515                             sc->ich_cmd));
516                         ok_bits |= ichsmb_state_irqs[cmd_index];
517                 }
518                 if ((status & ~ok_bits) != 0) {
519                         log(LOG_ERR, "%s: irq 0x%02x during %d\n",
520                             device_get_nameunit(dev), status, cmd_index);
521                         bus_space_write_1(sc->io_bst, sc->io_bsh,
522                             ICH_HST_STA, (status & ~ok_bits));
523                         continue;
524                 }
525
526                 /* Handle SMBALERT interrupt */
527                 if (status & ICH_HST_STA_SMBALERT_STS) {
528                         static int smbalert_count = 16;
529                         if (smbalert_count > 0) {
530                                 log(LOG_WARNING, "%s: SMBALERT# rec'd\n",
531                                     device_get_nameunit(dev));
532                                 if (--smbalert_count == 0) {
533                                         log(LOG_WARNING,
534                                             "%s: not logging anymore\n",
535                                             device_get_nameunit(dev));
536                                 }
537                         }
538                 }
539
540                 /* Check for bus error */
541                 if (status & ICH_HST_STA_BUS_ERR) {
542                         sc->smb_error = SMB_ECOLLI;     /* XXX SMB_EBUSERR? */
543                         goto finished;
544                 }
545
546                 /* Check for device error */
547                 if (status & ICH_HST_STA_DEV_ERR) {
548                         sc->smb_error = SMB_ENOACK;     /* or SMB_ETIMEOUT? */
549                         goto finished;
550                 }
551
552                 /* Check for byte completion in block transfer */
553                 if (status & ICH_HST_STA_BYTE_DONE_STS) {
554                         if (sc->block_write) {
555                                 if (sc->block_index < sc->block_count) {
556
557                                         /* Write next byte */
558                                         bus_space_write_1(sc->io_bst,
559                                             sc->io_bsh, ICH_BLOCK_DB,
560                                             sc->block_data[sc->block_index++]);
561                                 }
562                         } else {
563
564                                 /* First interrupt, get the count also */
565                                 if (sc->block_index == 0) {
566                                         sc->block_count = bus_space_read_1(
567                                             sc->io_bst, sc->io_bsh, ICH_D0);
568                                 }
569
570                                 /* Get next byte, if any */
571                                 if (sc->block_index < sc->block_count) {
572
573                                         /* Read next byte */
574                                         sc->block_data[sc->block_index++] =
575                                             bus_space_read_1(sc->io_bst,
576                                               sc->io_bsh, ICH_BLOCK_DB);
577
578                                         /* Set "LAST_BYTE" bit before reading
579                                            the last byte of block data */
580                                         if (sc->block_index
581                                             >= sc->block_count - 1) {
582                                                 bus_space_write_1(sc->io_bst,
583                                                     sc->io_bsh, ICH_HST_CNT,
584                                                     ICH_HST_CNT_LAST_BYTE
585                                                         | ICH_HST_CNT_INTREN
586                                                         | sc->ich_cmd);
587                                         }
588                                 }
589                         }
590                 }
591
592                 /* Check command completion */
593                 if (status & ICH_HST_STA_INTR) {
594                         sc->smb_error = SMB_ENOERR;
595 finished:
596                         sc->ich_cmd = -1;
597                         bus_space_write_1(sc->io_bst, sc->io_bsh,
598                             ICH_HST_STA, status);
599                         wakeup(sc);
600                         break;
601                 }
602
603                 /* Clear status bits and try again */
604                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status);
605         }
606         mtx_unlock(&sc->mutex);
607
608         /* Too many loops? */
609         if (count == maxloops) {
610                 log(LOG_ERR, "%s: interrupt loop, status=0x%02x\n",
611                     device_get_nameunit(dev),
612                     bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA));
613         }
614 }
615
616 /*
617  * Wait for command completion. Assumes mutex is held.
618  * Returns an SMB_* error code.
619  */
620 static int
621 ichsmb_wait(sc_p sc)
622 {
623         const device_t dev = sc->dev;
624         int error, smb_error;
625
626         KASSERT(sc->ich_cmd != -1,
627             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
628         mtx_assert(&sc->mutex, MA_OWNED);
629 sleep:
630         error = msleep(sc, &sc->mutex, PZERO | PCATCH, "ichsmb", hz / 4);
631         DBG("msleep -> %d\n", error);
632         switch (error) {
633         case ERESTART:
634                 if (sc->ich_cmd != -1)
635                         goto sleep;
636                 /* FALLTHROUGH */
637         case 0:
638                 smb_error = sc->smb_error;
639                 break;
640         case EWOULDBLOCK:
641                 log(LOG_ERR, "%s: device timeout, status=0x%02x\n",
642                     device_get_nameunit(dev),
643                     bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA));
644                 sc->ich_cmd = -1;
645                 smb_error = SMB_ETIMEOUT;
646                 break;
647         default:
648                 smb_error = SMB_EABORT;
649                 break;
650         }
651         return (smb_error);
652 }
653
654 /*
655  * Release resources associated with device.
656  */
657 void
658 ichsmb_release_resources(sc_p sc)
659 {
660         const device_t dev = sc->dev;
661
662         if (sc->irq_handle != NULL) {
663                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
664                 sc->irq_handle = NULL;
665         }
666         if (sc->irq_res != NULL) {
667                 bus_release_resource(dev,
668                     SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
669                 sc->irq_res = NULL;
670         }
671         if (sc->io_res != NULL) {
672                 bus_release_resource(dev,
673                     SYS_RES_IOPORT, sc->io_rid, sc->io_res);
674                 sc->io_res = NULL;
675         }
676 }
677