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