]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pci/nfsmb.c
This commit was generated by cvs2svn to compensate for changes in r178479,
[FreeBSD/FreeBSD.git] / sys / pci / nfsmb.c
1 /*-
2  * Copyright (c) 2005 Ruslan Ermilov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/systm.h>
37
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 #include <sys/rman.h>
41
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcireg.h>
44
45 #include <dev/smbus/smbconf.h>
46 #include "smbus_if.h"
47
48 #define NFSMB_DEBUG(x)  if (nfsmb_debug) (x)
49
50 #ifdef DEBUG
51 static int nfsmb_debug = 1;
52 #else
53 static int nfsmb_debug = 0;
54 #endif
55
56 /* NVIDIA nForce2/3/4 MCP */
57 #define NFSMB_VENDORID_NVIDIA           0x10de
58 #define NFSMB_DEVICEID_NF2_SMB          0x0064
59 #define NFSMB_DEVICEID_NF2_ULTRA_SMB    0x0084
60 #define NFSMB_DEVICEID_NF3_PRO150_SMB   0x00d4
61 #define NFSMB_DEVICEID_NF3_250GB_SMB    0x00e4
62 #define NFSMB_DEVICEID_NF4_SMB          0x0052
63 #define NFSMB_DEVICEID_NF4_04_SMB       0x0034
64 #define NFSMB_DEVICEID_NF4_51_SMB       0x0264
65 #define NFSMB_DEVICEID_NF4_55_SMB       0x0368
66 #define NFSMB_DEVICEID_NF4_61_SMB       0x03eb
67
68 /* PCI Configuration space registers */
69 #define NF2PCI_SMBASE_1         PCIR_BAR(4)
70 #define NF2PCI_SMBASE_2         PCIR_BAR(5)
71
72 /*
73  * ACPI 3.0, Chapter 12, SMBus Host Controller Interface.
74  */
75 #define SMB_PRTCL               0x00    /* protocol */
76 #define SMB_STS                 0x01    /* status */
77 #define SMB_ADDR                0x02    /* address */
78 #define SMB_CMD                 0x03    /* command */
79 #define SMB_DATA                0x04    /* 32 data registers */
80 #define SMB_BCNT                0x24    /* number of data bytes */
81 #define SMB_ALRM_A              0x25    /* alarm address */
82 #define SMB_ALRM_D              0x26    /* 2 bytes alarm data */
83
84 #define SMB_STS_DONE            0x80
85 #define SMB_STS_ALRM            0x40
86 #define SMB_STS_RES             0x20
87 #define SMB_STS_STATUS          0x1f
88 #define SMB_STS_OK              0x00    /* OK */
89 #define SMB_STS_UF              0x07    /* Unknown Failure */
90 #define SMB_STS_DANA            0x10    /* Device Address Not Acknowledged */
91 #define SMB_STS_DED             0x11    /* Device Error Detected */
92 #define SMB_STS_DCAD            0x12    /* Device Command Access Denied */
93 #define SMB_STS_UE              0x13    /* Unknown Error */
94 #define SMB_STS_DAD             0x17    /* Device Access Denied */
95 #define SMB_STS_T               0x18    /* Timeout */
96 #define SMB_STS_HUP             0x19    /* Host Unsupported Protocol */
97 #define SMB_STS_B               0x1A    /* Busy */
98 #define SMB_STS_PEC             0x1F    /* PEC (CRC-8) Error */
99
100 #define SMB_PRTCL_WRITE         0x00
101 #define SMB_PRTCL_READ          0x01
102 #define SMB_PRTCL_QUICK         0x02
103 #define SMB_PRTCL_BYTE          0x04
104 #define SMB_PRTCL_BYTE_DATA     0x06
105 #define SMB_PRTCL_WORD_DATA     0x08
106 #define SMB_PRTCL_BLOCK_DATA    0x0a
107 #define SMB_PRTCL_PROC_CALL     0x0c
108 #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d
109 #define SMB_PRTCL_PEC           0x80
110
111 struct nfsmb_softc {
112         int rid;
113         struct resource *res;
114         bus_space_tag_t smbst;
115         bus_space_handle_t smbsh;
116         device_t smbus;
117         device_t subdev;
118         struct mtx lock;
119 };
120
121 #define NFSMB_LOCK(nfsmb)               mtx_lock(&(nfsmb)->lock)
122 #define NFSMB_UNLOCK(nfsmb)             mtx_unlock(&(nfsmb)->lock)
123 #define NFSMB_LOCK_ASSERT(nfsmb)        mtx_assert(&(nfsmb)->lock, MA_OWNED)
124
125 #define NFSMB_SMBINB(nfsmb, register)                                   \
126         (bus_space_read_1(nfsmb->smbst, nfsmb->smbsh, register))
127 #define NFSMB_SMBOUTB(nfsmb, register, value) \
128         (bus_space_write_1(nfsmb->smbst, nfsmb->smbsh, register, value))
129
130 static int      nfsmb_detach(device_t dev);
131 static int      nfsmbsub_detach(device_t dev);
132
133 static int
134 nfsmbsub_probe(device_t dev)
135 {
136
137         device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
138         return (BUS_PROBE_DEFAULT);
139 }
140
141 static int
142 nfsmb_probe(device_t dev)
143 {
144         u_int16_t vid;
145         u_int16_t did;
146
147         vid = pci_get_vendor(dev);
148         did = pci_get_device(dev);
149
150         if (vid == NFSMB_VENDORID_NVIDIA) {
151                 switch(did) {
152                 case NFSMB_DEVICEID_NF2_SMB:
153                 case NFSMB_DEVICEID_NF2_ULTRA_SMB:
154                 case NFSMB_DEVICEID_NF3_PRO150_SMB:
155                 case NFSMB_DEVICEID_NF3_250GB_SMB:
156                 case NFSMB_DEVICEID_NF4_SMB:
157                 case NFSMB_DEVICEID_NF4_04_SMB:
158                 case NFSMB_DEVICEID_NF4_51_SMB:
159                 case NFSMB_DEVICEID_NF4_55_SMB:
160                 case NFSMB_DEVICEID_NF4_61_SMB:
161                         device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
162                         return (BUS_PROBE_DEFAULT);
163                 }
164         }
165
166         return (ENXIO);
167 }
168
169 static int
170 nfsmbsub_attach(device_t dev)
171 {
172         device_t parent;
173         struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
174
175         parent = device_get_parent(dev);
176
177         nfsmbsub_sc->rid = NF2PCI_SMBASE_2;
178
179         nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT,
180             &nfsmbsub_sc->rid, RF_ACTIVE);
181         if (nfsmbsub_sc->res == NULL) {
182                 /* Older incarnations of the device used non-standard BARs. */
183                 nfsmbsub_sc->rid = 0x54;
184                 nfsmbsub_sc->res = bus_alloc_resource_any(parent,
185                     SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE);
186                 if (nfsmbsub_sc->res == NULL) {
187                         device_printf(dev, "could not map i/o space\n");
188                         return (ENXIO);
189                 }
190         }
191         nfsmbsub_sc->smbst = rman_get_bustag(nfsmbsub_sc->res);
192         nfsmbsub_sc->smbsh = rman_get_bushandle(nfsmbsub_sc->res);
193         mtx_init(&nfsmbsub_sc->lock, device_get_nameunit(dev), "nfsmb",
194             MTX_DEF);
195
196         nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1);
197         if (nfsmbsub_sc->smbus == NULL) {
198                 nfsmbsub_detach(dev);
199                 return (EINVAL);
200         }
201
202         bus_generic_attach(dev);
203
204         return (0);
205 }
206
207 static int
208 nfsmb_attach(device_t dev)
209 {
210         struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
211
212         /* Allocate I/O space */
213         nfsmb_sc->rid = NF2PCI_SMBASE_1;
214
215         nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
216                 &nfsmb_sc->rid, RF_ACTIVE);
217
218         if (nfsmb_sc->res == NULL) {
219                 /* Older incarnations of the device used non-standard BARs. */
220                 nfsmb_sc->rid = 0x50;
221                 nfsmb_sc->res = bus_alloc_resource_any(dev,
222                     SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE);
223                 if (nfsmb_sc->res == NULL) {
224                         device_printf(dev, "could not map i/o space\n");
225                         return (ENXIO);
226                 }
227         }
228
229         nfsmb_sc->smbst = rman_get_bustag(nfsmb_sc->res);
230         nfsmb_sc->smbsh = rman_get_bushandle(nfsmb_sc->res);
231         mtx_init(&nfsmb_sc->lock, device_get_nameunit(dev), "nfsmb", MTX_DEF);
232
233         /* Allocate a new smbus device */
234         nfsmb_sc->smbus = device_add_child(dev, "smbus", -1);
235         if (!nfsmb_sc->smbus) {
236                 nfsmb_detach(dev);
237                 return (EINVAL);
238         }
239
240         nfsmb_sc->subdev = NULL;
241         switch (pci_get_device(dev)) {
242         case NFSMB_DEVICEID_NF2_SMB:
243         case NFSMB_DEVICEID_NF2_ULTRA_SMB:
244         case NFSMB_DEVICEID_NF3_PRO150_SMB:
245         case NFSMB_DEVICEID_NF3_250GB_SMB:
246         case NFSMB_DEVICEID_NF4_SMB:
247         case NFSMB_DEVICEID_NF4_04_SMB:
248         case NFSMB_DEVICEID_NF4_51_SMB:
249         case NFSMB_DEVICEID_NF4_55_SMB:
250         case NFSMB_DEVICEID_NF4_61_SMB:
251                 /* Trying to add secondary device as slave */
252                 nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1);
253                 if (!nfsmb_sc->subdev) {
254                         nfsmb_detach(dev);
255                         return (EINVAL);
256                 }
257                 break;
258         default:
259                 break;
260         }
261
262         bus_generic_attach(dev);
263
264         return (0);
265 }
266
267 static int
268 nfsmbsub_detach(device_t dev)
269 {
270         device_t parent;
271         struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
272
273         parent = device_get_parent(dev);
274
275         if (nfsmbsub_sc->smbus) {
276                 device_delete_child(dev, nfsmbsub_sc->smbus);
277                 nfsmbsub_sc->smbus = NULL;
278         }
279         mtx_destroy(&nfsmbsub_sc->lock);
280         if (nfsmbsub_sc->res) {
281                 bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid,
282                     nfsmbsub_sc->res);
283                 nfsmbsub_sc->res = NULL;
284         }
285         return (0);
286 }
287
288 static int
289 nfsmb_detach(device_t dev)
290 {
291         struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
292
293         if (nfsmb_sc->subdev) {
294                 device_delete_child(dev, nfsmb_sc->subdev);
295                 nfsmb_sc->subdev = NULL;
296         }
297
298         if (nfsmb_sc->smbus) {
299                 device_delete_child(dev, nfsmb_sc->smbus);
300                 nfsmb_sc->smbus = NULL;
301         }
302
303         mtx_destroy(&nfsmb_sc->lock);
304         if (nfsmb_sc->res) {
305                 bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid,
306                     nfsmb_sc->res);
307                 nfsmb_sc->res = NULL;
308         }
309
310         return (0);
311 }
312
313 static int
314 nfsmb_callback(device_t dev, int index, void *data)
315 {
316         int error = 0;
317
318         switch (index) {
319         case SMB_REQUEST_BUS:
320         case SMB_RELEASE_BUS:
321                 break;
322         default:
323                 error = EINVAL;
324         }
325
326         return (error);
327 }
328
329 static int
330 nfsmb_wait(struct nfsmb_softc *sc)
331 {
332         u_char sts;
333         int error, count;
334
335         NFSMB_LOCK_ASSERT(sc);
336         if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0)
337         {
338                 count = 10000;
339                 do {
340                         DELAY(500);
341                 } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--);
342                 if (count == 0)
343                         return (SMB_ETIMEOUT);
344         }
345
346         sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS;
347         NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts));
348
349         switch (sts) {
350         case SMB_STS_OK:
351                 error = SMB_ENOERR;
352                 break;
353         case SMB_STS_DANA:
354                 error = SMB_ENOACK;
355                 break;
356         case SMB_STS_B:
357                 error = SMB_EBUSY;
358                 break;
359         case SMB_STS_T:
360                 error = SMB_ETIMEOUT;
361                 break;
362         case SMB_STS_DCAD:
363         case SMB_STS_DAD:
364         case SMB_STS_HUP:
365                 error = SMB_ENOTSUPP;
366                 break;
367         default:
368                 error = SMB_EBUSERR;
369                 break;
370         }
371
372         return (error);
373 }
374
375 static int
376 nfsmb_quick(device_t dev, u_char slave, int how)
377 {
378         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
379         u_char protocol;
380         int error;
381
382         protocol = SMB_PRTCL_QUICK;
383
384         switch (how) {
385         case SMB_QWRITE:
386                 protocol |= SMB_PRTCL_WRITE;
387                 NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave));
388                 break;
389         case SMB_QREAD:
390                 protocol |= SMB_PRTCL_READ;
391                 NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave));
392                 break;
393         default:
394                 panic("%s: unknown QUICK command (%x)!", __func__, how);
395         }
396
397         NFSMB_LOCK(sc);
398         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
399         NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol);
400
401         error = nfsmb_wait(sc);
402
403         NFSMB_DEBUG(printf(", error=0x%x\n", error));
404         NFSMB_UNLOCK(sc);
405
406         return (error);
407 }
408
409 static int
410 nfsmb_sendb(device_t dev, u_char slave, char byte)
411 {
412         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
413         int error;
414
415         NFSMB_LOCK(sc);
416         NFSMB_SMBOUTB(sc, SMB_CMD, byte);
417         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
418         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE);
419
420         error = nfsmb_wait(sc);
421
422         NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
423         NFSMB_UNLOCK(sc);
424
425         return (error);
426 }
427
428 static int
429 nfsmb_recvb(device_t dev, u_char slave, char *byte)
430 {
431         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
432         int error;
433
434         NFSMB_LOCK(sc);
435         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
436         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE);
437
438         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
439                 *byte = NFSMB_SMBINB(sc, SMB_DATA);
440
441         NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
442         NFSMB_UNLOCK(sc);
443
444         return (error);
445 }
446
447 static int
448 nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
449 {
450         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
451         int error;
452
453         NFSMB_LOCK(sc);
454         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
455         NFSMB_SMBOUTB(sc, SMB_DATA, byte);
456         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
457         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA);
458
459         error = nfsmb_wait(sc);
460
461         NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
462         NFSMB_UNLOCK(sc);
463
464         return (error);
465 }
466
467 static int
468 nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
469 {
470         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
471         int error;
472
473         NFSMB_LOCK(sc);
474         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
475         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
476         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA);
477
478         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
479                 *byte = NFSMB_SMBINB(sc, SMB_DATA);
480
481         NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error));
482         NFSMB_UNLOCK(sc);
483
484         return (error);
485 }
486
487 static int
488 nfsmb_writew(device_t dev, u_char slave, char cmd, short word)
489 {
490         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
491         int error;
492
493         NFSMB_LOCK(sc);
494         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
495         NFSMB_SMBOUTB(sc, SMB_DATA, word);
496         NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8);
497         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
498         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA);
499
500         error = nfsmb_wait(sc);
501
502         NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
503         NFSMB_UNLOCK(sc);
504
505         return (error);
506 }
507
508 static int
509 nfsmb_readw(device_t dev, u_char slave, char cmd, short *word)
510 {
511         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
512         int error;
513
514         NFSMB_LOCK(sc);
515         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
516         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
517         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA);
518
519         if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
520                 *word = NFSMB_SMBINB(sc, SMB_DATA) |
521                     (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8);
522
523         NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error));
524         NFSMB_UNLOCK(sc);
525
526         return (error);
527 }
528
529 static int
530 nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
531 {
532         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
533         u_char i;
534         int error;
535
536         if (count < 1 || count > 32)
537                 return (SMB_EINVAL);
538
539         NFSMB_LOCK(sc);
540         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
541         NFSMB_SMBOUTB(sc, SMB_BCNT, count);
542         for (i = 0; i < count; i++)
543                 NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]);
544         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
545         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA);
546
547         error = nfsmb_wait(sc);
548
549         NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
550         NFSMB_UNLOCK(sc);
551
552         return (error);
553 }
554
555 static int
556 nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
557 {
558         struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
559         u_char data, len, i;
560         int error;
561
562         if (*count < 1 || *count > 32)
563                 return (SMB_EINVAL);
564
565         NFSMB_LOCK(sc);
566         NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
567         NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
568         NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA);
569
570         if ((error = nfsmb_wait(sc)) == SMB_ENOERR) {
571                 len = NFSMB_SMBINB(sc, SMB_BCNT);
572                 for (i = 0; i < len; i++) {
573                         data = NFSMB_SMBINB(sc, SMB_DATA + i);
574                         if (i < *count)
575                                 buf[i] = data;
576                 }
577                 *count = len;
578         }
579
580         NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
581         NFSMB_UNLOCK(sc);
582
583         return (error);
584 }
585
586 static device_method_t nfsmb_methods[] = {
587         /* Device interface */
588         DEVMETHOD(device_probe,         nfsmb_probe),
589         DEVMETHOD(device_attach,        nfsmb_attach),
590         DEVMETHOD(device_detach,        nfsmb_detach),
591
592         /* SMBus interface */
593         DEVMETHOD(smbus_callback,       nfsmb_callback),
594         DEVMETHOD(smbus_quick,          nfsmb_quick),
595         DEVMETHOD(smbus_sendb,          nfsmb_sendb),
596         DEVMETHOD(smbus_recvb,          nfsmb_recvb),
597         DEVMETHOD(smbus_writeb,         nfsmb_writeb),
598         DEVMETHOD(smbus_readb,          nfsmb_readb),
599         DEVMETHOD(smbus_writew,         nfsmb_writew),
600         DEVMETHOD(smbus_readw,          nfsmb_readw),
601         DEVMETHOD(smbus_bwrite,         nfsmb_bwrite),
602         DEVMETHOD(smbus_bread,          nfsmb_bread),
603
604         { 0, 0 }
605 };
606
607 static device_method_t nfsmbsub_methods[] = {
608         /* Device interface */
609         DEVMETHOD(device_probe,         nfsmbsub_probe),
610         DEVMETHOD(device_attach,        nfsmbsub_attach),
611         DEVMETHOD(device_detach,        nfsmbsub_detach),
612
613         /* SMBus interface */
614         DEVMETHOD(smbus_callback,       nfsmb_callback),
615         DEVMETHOD(smbus_quick,          nfsmb_quick),
616         DEVMETHOD(smbus_sendb,          nfsmb_sendb),
617         DEVMETHOD(smbus_recvb,          nfsmb_recvb),
618         DEVMETHOD(smbus_writeb,         nfsmb_writeb),
619         DEVMETHOD(smbus_readb,          nfsmb_readb),
620         DEVMETHOD(smbus_writew,         nfsmb_writew),
621         DEVMETHOD(smbus_readw,          nfsmb_readw),
622         DEVMETHOD(smbus_bwrite,         nfsmb_bwrite),
623         DEVMETHOD(smbus_bread,          nfsmb_bread),
624
625         { 0, 0 }
626 };
627
628 static devclass_t nfsmb_devclass;
629
630 static driver_t nfsmb_driver = {
631         "nfsmb",
632         nfsmb_methods,
633         sizeof(struct nfsmb_softc),
634 };
635
636 static driver_t nfsmbsub_driver = {
637         "nfsmb",
638         nfsmbsub_methods,
639         sizeof(struct nfsmb_softc),
640 };
641
642 DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0);
643 DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0);
644 DRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0);
645
646 MODULE_DEPEND(nfsmb, pci, 1, 1, 1);
647 MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
648 MODULE_VERSION(nfsmb, 1);