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
51static int nfsmb_debug = 1;
52#else
53static 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#define	NFSMB_DEVICEID_NF4_65_SMB	0x0446
68#define	NFSMB_DEVICEID_NF4_67_SMB	0x0542
69#define	NFSMB_DEVICEID_NF4_73_SMB	0x07d8
70#define	NFSMB_DEVICEID_NF4_78S_SMB	0x0752
71#define	NFSMB_DEVICEID_NF4_79_SMB	0x0aa2
72
73/* PCI Configuration space registers */
74#define	NF2PCI_SMBASE_1		PCIR_BAR(4)
75#define	NF2PCI_SMBASE_2		PCIR_BAR(5)
76
77/*
78 * ACPI 3.0, Chapter 12, SMBus Host Controller Interface.
79 */
80#define	SMB_PRTCL		0x00	/* protocol */
81#define	SMB_STS			0x01	/* status */
82#define	SMB_ADDR		0x02	/* address */
83#define	SMB_CMD			0x03	/* command */
84#define	SMB_DATA		0x04	/* 32 data registers */
85#define	SMB_BCNT		0x24	/* number of data bytes */
86#define	SMB_ALRM_A		0x25	/* alarm address */
87#define	SMB_ALRM_D		0x26	/* 2 bytes alarm data */
88
89#define	SMB_STS_DONE		0x80
90#define	SMB_STS_ALRM		0x40
91#define	SMB_STS_RES		0x20
92#define	SMB_STS_STATUS		0x1f
93#define	SMB_STS_OK		0x00	/* OK */
94#define	SMB_STS_UF		0x07	/* Unknown Failure */
95#define	SMB_STS_DANA		0x10	/* Device Address Not Acknowledged */
96#define	SMB_STS_DED		0x11	/* Device Error Detected */
97#define	SMB_STS_DCAD		0x12	/* Device Command Access Denied */
98#define	SMB_STS_UE		0x13	/* Unknown Error */
99#define	SMB_STS_DAD		0x17	/* Device Access Denied */
100#define	SMB_STS_T		0x18	/* Timeout */
101#define	SMB_STS_HUP		0x19	/* Host Unsupported Protocol */
102#define	SMB_STS_B		0x1A	/* Busy */
103#define	SMB_STS_PEC		0x1F	/* PEC (CRC-8) Error */
104
105#define	SMB_PRTCL_WRITE		0x00
106#define	SMB_PRTCL_READ		0x01
107#define	SMB_PRTCL_QUICK		0x02
108#define	SMB_PRTCL_BYTE		0x04
109#define	SMB_PRTCL_BYTE_DATA	0x06
110#define	SMB_PRTCL_WORD_DATA	0x08
111#define	SMB_PRTCL_BLOCK_DATA	0x0a
112#define	SMB_PRTCL_PROC_CALL	0x0c
113#define	SMB_PRTCL_BLOCK_PROC_CALL 0x0d
114#define	SMB_PRTCL_PEC		0x80
115
116struct nfsmb_softc {
117	int rid;
118	struct resource *res;
119	device_t smbus;
120	device_t subdev;
121	struct mtx lock;
122};
123
124#define	NFSMB_LOCK(nfsmb)		mtx_lock(&(nfsmb)->lock)
125#define	NFSMB_UNLOCK(nfsmb)		mtx_unlock(&(nfsmb)->lock)
126#define	NFSMB_LOCK_ASSERT(nfsmb)	mtx_assert(&(nfsmb)->lock, MA_OWNED)
127
128#define	NFSMB_SMBINB(nfsmb, register)					\
129	(bus_read_1(nfsmb->res, register))
130#define	NFSMB_SMBOUTB(nfsmb, register, value) \
131	(bus_write_1(nfsmb->res, register, value))
132
133static int	nfsmb_detach(device_t dev);
134static int	nfsmbsub_detach(device_t dev);
135
136static int
137nfsmbsub_probe(device_t dev)
138{
139
140	device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
141	return (BUS_PROBE_DEFAULT);
142}
143
144static int
145nfsmb_probe(device_t dev)
146{
147	u_int16_t vid;
148	u_int16_t did;
149
150	vid = pci_get_vendor(dev);
151	did = pci_get_device(dev);
152
153	if (vid == NFSMB_VENDORID_NVIDIA) {
154		switch(did) {
155		case NFSMB_DEVICEID_NF2_SMB:
156		case NFSMB_DEVICEID_NF2_ULTRA_SMB:
157		case NFSMB_DEVICEID_NF3_PRO150_SMB:
158		case NFSMB_DEVICEID_NF3_250GB_SMB:
159		case NFSMB_DEVICEID_NF4_SMB:
160		case NFSMB_DEVICEID_NF4_04_SMB:
161		case NFSMB_DEVICEID_NF4_51_SMB:
162		case NFSMB_DEVICEID_NF4_55_SMB:
163		case NFSMB_DEVICEID_NF4_61_SMB:
164		case NFSMB_DEVICEID_NF4_65_SMB:
165		case NFSMB_DEVICEID_NF4_67_SMB:
166		case NFSMB_DEVICEID_NF4_73_SMB:
167		case NFSMB_DEVICEID_NF4_78S_SMB:
168		case NFSMB_DEVICEID_NF4_79_SMB:
169			device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller");
170			return (BUS_PROBE_DEFAULT);
171		}
172	}
173
174	return (ENXIO);
175}
176
177static int
178nfsmbsub_attach(device_t dev)
179{
180	device_t parent;
181	struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
182
183	parent = device_get_parent(dev);
184
185	nfsmbsub_sc->rid = NF2PCI_SMBASE_2;
186
187	nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT,
188	    &nfsmbsub_sc->rid, RF_ACTIVE);
189	if (nfsmbsub_sc->res == NULL) {
190		/* Older incarnations of the device used non-standard BARs. */
191		nfsmbsub_sc->rid = 0x54;
192		nfsmbsub_sc->res = bus_alloc_resource_any(parent,
193		    SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE);
194		if (nfsmbsub_sc->res == NULL) {
195			device_printf(dev, "could not map i/o space\n");
196			return (ENXIO);
197		}
198	}
199	mtx_init(&nfsmbsub_sc->lock, device_get_nameunit(dev), "nfsmb",
200	    MTX_DEF);
201
202	nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1);
203	if (nfsmbsub_sc->smbus == NULL) {
204		nfsmbsub_detach(dev);
205		return (EINVAL);
206	}
207
208	bus_generic_attach(dev);
209
210	return (0);
211}
212
213static int
214nfsmb_attach(device_t dev)
215{
216	struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
217
218	/* Allocate I/O space */
219	nfsmb_sc->rid = NF2PCI_SMBASE_1;
220
221	nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
222		&nfsmb_sc->rid, RF_ACTIVE);
223
224	if (nfsmb_sc->res == NULL) {
225		/* Older incarnations of the device used non-standard BARs. */
226		nfsmb_sc->rid = 0x50;
227		nfsmb_sc->res = bus_alloc_resource_any(dev,
228		    SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE);
229		if (nfsmb_sc->res == NULL) {
230			device_printf(dev, "could not map i/o space\n");
231			return (ENXIO);
232		}
233	}
234
235	mtx_init(&nfsmb_sc->lock, device_get_nameunit(dev), "nfsmb", MTX_DEF);
236
237	/* Allocate a new smbus device */
238	nfsmb_sc->smbus = device_add_child(dev, "smbus", -1);
239	if (!nfsmb_sc->smbus) {
240		nfsmb_detach(dev);
241		return (EINVAL);
242	}
243
244	nfsmb_sc->subdev = NULL;
245	switch (pci_get_device(dev)) {
246	case NFSMB_DEVICEID_NF2_SMB:
247	case NFSMB_DEVICEID_NF2_ULTRA_SMB:
248	case NFSMB_DEVICEID_NF3_PRO150_SMB:
249	case NFSMB_DEVICEID_NF3_250GB_SMB:
250	case NFSMB_DEVICEID_NF4_SMB:
251	case NFSMB_DEVICEID_NF4_04_SMB:
252	case NFSMB_DEVICEID_NF4_51_SMB:
253	case NFSMB_DEVICEID_NF4_55_SMB:
254	case NFSMB_DEVICEID_NF4_61_SMB:
255	case NFSMB_DEVICEID_NF4_65_SMB:
256	case NFSMB_DEVICEID_NF4_67_SMB:
257	case NFSMB_DEVICEID_NF4_73_SMB:
258	case NFSMB_DEVICEID_NF4_78S_SMB:
259	case NFSMB_DEVICEID_NF4_79_SMB:
260		/* Trying to add secondary device as slave */
261		nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1);
262		if (!nfsmb_sc->subdev) {
263			nfsmb_detach(dev);
264			return (EINVAL);
265		}
266		break;
267	default:
268		break;
269	}
270
271	bus_generic_attach(dev);
272
273	return (0);
274}
275
276static int
277nfsmbsub_detach(device_t dev)
278{
279	device_t parent;
280	struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev);
281
282	parent = device_get_parent(dev);
283
284	if (nfsmbsub_sc->smbus) {
285		device_delete_child(dev, nfsmbsub_sc->smbus);
286		nfsmbsub_sc->smbus = NULL;
287	}
288	mtx_destroy(&nfsmbsub_sc->lock);
289	if (nfsmbsub_sc->res) {
290		bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid,
291		    nfsmbsub_sc->res);
292		nfsmbsub_sc->res = NULL;
293	}
294	return (0);
295}
296
297static int
298nfsmb_detach(device_t dev)
299{
300	struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
301
302	if (nfsmb_sc->subdev) {
303		device_delete_child(dev, nfsmb_sc->subdev);
304		nfsmb_sc->subdev = NULL;
305	}
306
307	if (nfsmb_sc->smbus) {
308		device_delete_child(dev, nfsmb_sc->smbus);
309		nfsmb_sc->smbus = NULL;
310	}
311
312	mtx_destroy(&nfsmb_sc->lock);
313	if (nfsmb_sc->res) {
314		bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid,
315		    nfsmb_sc->res);
316		nfsmb_sc->res = NULL;
317	}
318
319	return (0);
320}
321
322static int
323nfsmb_callback(device_t dev, int index, void *data)
324{
325	int error = 0;
326
327	switch (index) {
328	case SMB_REQUEST_BUS:
329	case SMB_RELEASE_BUS:
330		break;
331	default:
332		error = EINVAL;
333	}
334
335	return (error);
336}
337
338static int
339nfsmb_wait(struct nfsmb_softc *sc)
340{
341	u_char sts;
342	int error, count;
343
344	NFSMB_LOCK_ASSERT(sc);
345	if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0)
346	{
347		count = 10000;
348		do {
349			DELAY(500);
350		} while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--);
351		if (count == 0)
352			return (SMB_ETIMEOUT);
353	}
354
355	sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS;
356	NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts));
357
358	switch (sts) {
359	case SMB_STS_OK:
360		error = SMB_ENOERR;
361		break;
362	case SMB_STS_DANA:
363		error = SMB_ENOACK;
364		break;
365	case SMB_STS_B:
366		error = SMB_EBUSY;
367		break;
368	case SMB_STS_T:
369		error = SMB_ETIMEOUT;
370		break;
371	case SMB_STS_DCAD:
372	case SMB_STS_DAD:
373	case SMB_STS_HUP:
374		error = SMB_ENOTSUPP;
375		break;
376	default:
377		error = SMB_EBUSERR;
378		break;
379	}
380
381	return (error);
382}
383
384static int
385nfsmb_quick(device_t dev, u_char slave, int how)
386{
387	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
388	u_char protocol;
389	int error;
390
391	protocol = SMB_PRTCL_QUICK;
392
393	switch (how) {
394	case SMB_QWRITE:
395		protocol |= SMB_PRTCL_WRITE;
396		NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave));
397		break;
398	case SMB_QREAD:
399		protocol |= SMB_PRTCL_READ;
400		NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave));
401		break;
402	default:
403		panic("%s: unknown QUICK command (%x)!", __func__, how);
404	}
405
406	NFSMB_LOCK(sc);
407	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
408	NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol);
409
410	error = nfsmb_wait(sc);
411
412	NFSMB_DEBUG(printf(", error=0x%x\n", error));
413	NFSMB_UNLOCK(sc);
414
415	return (error);
416}
417
418static int
419nfsmb_sendb(device_t dev, u_char slave, char byte)
420{
421	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
422	int error;
423
424	NFSMB_LOCK(sc);
425	NFSMB_SMBOUTB(sc, SMB_CMD, byte);
426	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
427	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE);
428
429	error = nfsmb_wait(sc);
430
431	NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
432	NFSMB_UNLOCK(sc);
433
434	return (error);
435}
436
437static int
438nfsmb_recvb(device_t dev, u_char slave, char *byte)
439{
440	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
441	int error;
442
443	NFSMB_LOCK(sc);
444	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
445	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE);
446
447	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
448		*byte = NFSMB_SMBINB(sc, SMB_DATA);
449
450	NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
451	NFSMB_UNLOCK(sc);
452
453	return (error);
454}
455
456static int
457nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
458{
459	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
460	int error;
461
462	NFSMB_LOCK(sc);
463	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
464	NFSMB_SMBOUTB(sc, SMB_DATA, byte);
465	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
466	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA);
467
468	error = nfsmb_wait(sc);
469
470	NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
471	NFSMB_UNLOCK(sc);
472
473	return (error);
474}
475
476static int
477nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
478{
479	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
480	int error;
481
482	NFSMB_LOCK(sc);
483	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
484	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
485	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA);
486
487	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
488		*byte = NFSMB_SMBINB(sc, SMB_DATA);
489
490	NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error));
491	NFSMB_UNLOCK(sc);
492
493	return (error);
494}
495
496static int
497nfsmb_writew(device_t dev, u_char slave, char cmd, short word)
498{
499	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
500	int error;
501
502	NFSMB_LOCK(sc);
503	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
504	NFSMB_SMBOUTB(sc, SMB_DATA, word);
505	NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8);
506	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
507	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA);
508
509	error = nfsmb_wait(sc);
510
511	NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
512	NFSMB_UNLOCK(sc);
513
514	return (error);
515}
516
517static int
518nfsmb_readw(device_t dev, u_char slave, char cmd, short *word)
519{
520	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
521	int error;
522
523	NFSMB_LOCK(sc);
524	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
525	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
526	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA);
527
528	if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
529		*word = NFSMB_SMBINB(sc, SMB_DATA) |
530		    (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8);
531
532	NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error));
533	NFSMB_UNLOCK(sc);
534
535	return (error);
536}
537
538static int
539nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
540{
541	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
542	u_char i;
543	int error;
544
545	if (count < 1 || count > 32)
546		return (SMB_EINVAL);
547
548	NFSMB_LOCK(sc);
549	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
550	NFSMB_SMBOUTB(sc, SMB_BCNT, count);
551	for (i = 0; i < count; i++)
552		NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]);
553	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
554	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA);
555
556	error = nfsmb_wait(sc);
557
558	NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
559	NFSMB_UNLOCK(sc);
560
561	return (error);
562}
563
564static int
565nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
566{
567	struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
568	u_char data, len, i;
569	int error;
570
571	if (*count < 1 || *count > 32)
572		return (SMB_EINVAL);
573
574	NFSMB_LOCK(sc);
575	NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
576	NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
577	NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA);
578
579	if ((error = nfsmb_wait(sc)) == SMB_ENOERR) {
580		len = NFSMB_SMBINB(sc, SMB_BCNT);
581		for (i = 0; i < len; i++) {
582			data = NFSMB_SMBINB(sc, SMB_DATA + i);
583			if (i < *count)
584				buf[i] = data;
585		}
586		*count = len;
587	}
588
589	NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
590	NFSMB_UNLOCK(sc);
591
592	return (error);
593}
594
595static device_method_t nfsmb_methods[] = {
596	/* Device interface */
597	DEVMETHOD(device_probe,		nfsmb_probe),
598	DEVMETHOD(device_attach,	nfsmb_attach),
599	DEVMETHOD(device_detach,	nfsmb_detach),
600
601	/* SMBus interface */
602	DEVMETHOD(smbus_callback,	nfsmb_callback),
603	DEVMETHOD(smbus_quick,		nfsmb_quick),
604	DEVMETHOD(smbus_sendb,		nfsmb_sendb),
605	DEVMETHOD(smbus_recvb,		nfsmb_recvb),
606	DEVMETHOD(smbus_writeb,		nfsmb_writeb),
607	DEVMETHOD(smbus_readb,		nfsmb_readb),
608	DEVMETHOD(smbus_writew,		nfsmb_writew),
609	DEVMETHOD(smbus_readw,		nfsmb_readw),
610	DEVMETHOD(smbus_bwrite,		nfsmb_bwrite),
611	DEVMETHOD(smbus_bread,		nfsmb_bread),
612
613	{ 0, 0 }
614};
615
616static device_method_t nfsmbsub_methods[] = {
617	/* Device interface */
618	DEVMETHOD(device_probe,		nfsmbsub_probe),
619	DEVMETHOD(device_attach,	nfsmbsub_attach),
620	DEVMETHOD(device_detach,	nfsmbsub_detach),
621
622	/* SMBus interface */
623	DEVMETHOD(smbus_callback,	nfsmb_callback),
624	DEVMETHOD(smbus_quick,		nfsmb_quick),
625	DEVMETHOD(smbus_sendb,		nfsmb_sendb),
626	DEVMETHOD(smbus_recvb,		nfsmb_recvb),
627	DEVMETHOD(smbus_writeb,		nfsmb_writeb),
628	DEVMETHOD(smbus_readb,		nfsmb_readb),
629	DEVMETHOD(smbus_writew,		nfsmb_writew),
630	DEVMETHOD(smbus_readw,		nfsmb_readw),
631	DEVMETHOD(smbus_bwrite,		nfsmb_bwrite),
632	DEVMETHOD(smbus_bread,		nfsmb_bread),
633
634	{ 0, 0 }
635};
636
637static devclass_t nfsmb_devclass;
638
639static driver_t nfsmb_driver = {
640	"nfsmb",
641	nfsmb_methods,
642	sizeof(struct nfsmb_softc),
643};
644
645static driver_t nfsmbsub_driver = {
646	"nfsmb",
647	nfsmbsub_methods,
648	sizeof(struct nfsmb_softc),
649};
650
651DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0);
652DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0);
653DRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0);
654
655MODULE_DEPEND(nfsmb, pci, 1, 1, 1);
656MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
657MODULE_VERSION(nfsmb, 1);
658