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