Expand SMBUS API to add smbus_trans() function.
Differential Revision: https://reviews.freebsd.org/D1955 Reviewed by: adrian, jhb, wblock Approved by: adrian, jhb
This commit is contained in:
parent
c60c12803e
commit
9da00f2a97
@ -1,5 +1,6 @@
|
||||
.\" Copyright (c) 1998, Nicolas Souchu
|
||||
.\" Copyright (c) 2004, Joerg Wunsch
|
||||
.\" Copyright (c) 2015, Michael Gmelin <freebsd@grem.de>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -25,7 +26,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 6, 2009
|
||||
.Dd April 25, 2015
|
||||
.Dt SMB 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -49,21 +50,24 @@ as its argument.
|
||||
#include <sys/types.h>
|
||||
|
||||
struct smbcmd {
|
||||
char cmd;
|
||||
int count;
|
||||
u_char slave;
|
||||
u_char cmd;
|
||||
u_char reserved;
|
||||
u_short op;
|
||||
union {
|
||||
char byte;
|
||||
short word;
|
||||
|
||||
char *byte_ptr;
|
||||
short *word_ptr;
|
||||
|
||||
struct {
|
||||
short sdata;
|
||||
short *rdata;
|
||||
} process;
|
||||
} data;
|
||||
char byte;
|
||||
char buf[2];
|
||||
short word;
|
||||
} wdata;
|
||||
union {
|
||||
char byte;
|
||||
char buf[2];
|
||||
short word;
|
||||
} rdata;
|
||||
int slave;
|
||||
char *wbuf; /* use wdata if NULL */
|
||||
int wcount;
|
||||
char *rbuf; /* use rdata if NULL */
|
||||
int rcount;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
@ -107,14 +111,14 @@ The
|
||||
command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, followed by the byte given in
|
||||
.Fa data.byte .
|
||||
.Fa wdata.byte .
|
||||
.It Dv SMB_WRITEW Ta
|
||||
The
|
||||
.Em WriteWord
|
||||
command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, followed by the word given in
|
||||
.Fa data.word .
|
||||
.Fa wdata.word .
|
||||
Note that the SMBus byte-order is little-endian by definition.
|
||||
.It Dv SMB_READB Ta
|
||||
The
|
||||
@ -123,8 +127,8 @@ command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, and then reads one byte of data from
|
||||
the device.
|
||||
The returned data will be stored in the location pointed to by
|
||||
.Fa data.byte_ptr .
|
||||
The returned data will be stored in
|
||||
.Fa rdata.byte .
|
||||
.It Dv SMB_READW Ta
|
||||
The
|
||||
.Em ReadWord
|
||||
@ -132,29 +136,33 @@ command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, and then reads one word of data from
|
||||
the device.
|
||||
The returned data will be stored in the location pointed to by
|
||||
.Fa data.word_ptr .
|
||||
The returned data will be stored in
|
||||
.Fa rdata.word .
|
||||
.It Dv SMB_PCALL Ta
|
||||
The
|
||||
.Em ProcedureCall
|
||||
command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, followed by the word provided in
|
||||
.Fa data.process.sdata .
|
||||
.Fa wdata.word .
|
||||
It then reads one word of data from the device, and returns it
|
||||
in the location pointed to by
|
||||
.Fa data.process.rdata .
|
||||
in
|
||||
.Fa rdata.word .
|
||||
.It Dv SMB_BWRITE Ta
|
||||
The
|
||||
.Em BlockWrite
|
||||
command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, followed by
|
||||
.Fa count
|
||||
.Fa wcount
|
||||
bytes of data that are taken from the buffer pointed to by
|
||||
.Fa data.byte_ptr .
|
||||
.Fa wbuf .
|
||||
The SMBus specification mandates that no more than 32 bytes of
|
||||
data can be transferred in a single block read or write command.
|
||||
data can be transferred in a single block read or write command,
|
||||
but since
|
||||
.Xr smbus 4
|
||||
is also used to access I2C devices, the limit has been increased
|
||||
to 1024.
|
||||
This value is available in the constant
|
||||
.Dv SMB_MAXBLOCKSIZE .
|
||||
.It Dv SMB_BREAD Ta
|
||||
@ -163,10 +171,38 @@ The
|
||||
command first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, and then reads
|
||||
.Fa count
|
||||
.Fa rcount
|
||||
bytes of data that from the device.
|
||||
These data will be returned in the buffer pointed to by
|
||||
.Fa data.byte_ptr .
|
||||
.Fa rbuf .
|
||||
.It Dv SMB_TRANS Ta
|
||||
The
|
||||
.Em Trans
|
||||
command sends an SMB roll-up transaction with flags that also allow it to
|
||||
be used for (mostly) I2C pass-through and with with 10-bit addresses.
|
||||
This function can be used to roll up all of the above functions.
|
||||
It first sends the byte from the
|
||||
.Fa cmd
|
||||
field to the device, followed by
|
||||
.Fa wcount
|
||||
bytes of data that are taken from the buffer pointed to by
|
||||
.Fa wbuf ,
|
||||
then reads
|
||||
.Fa rcount
|
||||
bytes of data that from the device.
|
||||
These data will be returned in the buffer pointed to by
|
||||
.Fa rbuf .
|
||||
.Pp
|
||||
The following flags are allowed in
|
||||
.Fa op :
|
||||
.Pp
|
||||
.Bd -literal -compact
|
||||
SMB_TRANS_NOSTOP Do not send STOP at end
|
||||
SMB_TRANS_NOCMD Ignore cmd field (do not tx)
|
||||
SMB_TRANS_NOCNT Do not tx or rx count field
|
||||
SMB_TRANS_7BIT Change address mode to 7-bit
|
||||
SMB_TRANS_10BIT Change address mode to 10-bit
|
||||
.Ed
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
@ -201,4 +237,7 @@ manual page first appeared in
|
||||
.Sh AUTHORS
|
||||
This
|
||||
manual page was written by
|
||||
.An Nicolas Souchu .
|
||||
.An Nicolas Souchu
|
||||
and extended by
|
||||
.An Michael Gmelin Aq freebsd@grem.de
|
||||
.
|
||||
|
@ -26,10 +26,6 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_KERNEL_OPTION_HEADERS
|
||||
#include "opt_compat.h"
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
@ -104,19 +100,24 @@ smb_identify(driver_t *driver, device_t parent)
|
||||
static int
|
||||
smb_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "SMBus generic I/O");
|
||||
if (smbus_get_addr(dev) != -1)
|
||||
return (ENXIO);
|
||||
|
||||
return (0);
|
||||
device_set_desc(dev, "SMBus generic I/O");
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
static int
|
||||
smb_attach(device_t dev)
|
||||
{
|
||||
struct smb_softc *sc = device_get_softc(dev);
|
||||
int unit;
|
||||
|
||||
unit = device_get_unit(dev);
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_devnode = make_dev(&smb_cdevsw, device_get_unit(dev),
|
||||
UID_ROOT, GID_WHEEL, 0600, "smb%d", device_get_unit(dev));
|
||||
|
||||
sc->sc_devnode = make_dev(&smb_cdevsw, unit, UID_ROOT, GID_WHEEL,
|
||||
0600, "smb%d", unit);
|
||||
sc->sc_devnode->si_drv1 = sc;
|
||||
mtx_init(&sc->sc_lock, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
@ -174,9 +175,16 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
|
||||
struct smb_softc *sc = dev->si_drv1;
|
||||
device_t smbdev = sc->sc_dev;
|
||||
int error;
|
||||
short w;
|
||||
u_char count;
|
||||
char c;
|
||||
int unit;
|
||||
u_char bcount;
|
||||
|
||||
/*
|
||||
* If a specific slave device is being used, override any passed-in
|
||||
* slave.
|
||||
*/
|
||||
unit = dev2unit(dev);
|
||||
if (unit & 0x0400)
|
||||
s->slave = unit & 0x03ff;
|
||||
|
||||
parent = device_get_parent(smbdev);
|
||||
|
||||
@ -208,77 +216,101 @@ smbioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t
|
||||
|
||||
case SMB_WRITEB:
|
||||
error = smbus_error(smbus_writeb(parent, s->slave, s->cmd,
|
||||
s->data.byte));
|
||||
s->wdata.byte));
|
||||
break;
|
||||
|
||||
case SMB_WRITEW:
|
||||
error = smbus_error(smbus_writew(parent, s->slave,
|
||||
s->cmd, s->data.word));
|
||||
s->cmd, s->wdata.word));
|
||||
break;
|
||||
|
||||
case SMB_READB:
|
||||
if (s->data.byte_ptr) {
|
||||
error = smbus_error(smbus_readb(parent, s->slave,
|
||||
s->cmd, &c));
|
||||
if (error)
|
||||
break;
|
||||
error = copyout(&c, s->data.byte_ptr,
|
||||
sizeof(*(s->data.byte_ptr)));
|
||||
error = smbus_error(smbus_readb(parent, s->slave, s->cmd,
|
||||
&s->rdata.byte));
|
||||
if (error)
|
||||
break;
|
||||
if (s->rbuf && s->rcount >= 1) {
|
||||
error = copyout(&s->rdata.byte, s->rbuf, 1);
|
||||
s->rcount = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SMB_READW:
|
||||
if (s->data.word_ptr) {
|
||||
error = smbus_error(smbus_readw(parent, s->slave,
|
||||
s->cmd, &w));
|
||||
if (error == 0) {
|
||||
error = copyout(&w, s->data.word_ptr,
|
||||
sizeof(*(s->data.word_ptr)));
|
||||
}
|
||||
error = smbus_error(smbus_readw(parent, s->slave, s->cmd,
|
||||
&s->rdata.word));
|
||||
if (error)
|
||||
break;
|
||||
if (s->rbuf && s->rcount >= 2) {
|
||||
buf[0] = (u_char)s->rdata.word;
|
||||
buf[1] = (u_char)(s->rdata.word >> 8);
|
||||
error = copyout(buf, s->rbuf, 2);
|
||||
s->rcount = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SMB_PCALL:
|
||||
if (s->data.process.rdata) {
|
||||
|
||||
error = smbus_error(smbus_pcall(parent, s->slave, s->cmd,
|
||||
s->data.process.sdata, &w));
|
||||
if (error)
|
||||
break;
|
||||
error = copyout(&w, s->data.process.rdata,
|
||||
sizeof(*(s->data.process.rdata)));
|
||||
error = smbus_error(smbus_pcall(parent, s->slave, s->cmd,
|
||||
s->wdata.word, &s->rdata.word));
|
||||
if (error)
|
||||
break;
|
||||
if (s->rbuf && s->rcount >= 2) {
|
||||
buf[0] = (u_char)s->rdata.word;
|
||||
buf[1] = (u_char)(s->rdata.word >> 8);
|
||||
error = copyout(buf, s->rbuf, 2);
|
||||
s->rcount = 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SMB_BWRITE:
|
||||
if (s->count && s->data.byte_ptr) {
|
||||
if (s->count > SMB_MAXBLOCKSIZE)
|
||||
s->count = SMB_MAXBLOCKSIZE;
|
||||
error = copyin(s->data.byte_ptr, buf, s->count);
|
||||
if (error)
|
||||
break;
|
||||
error = smbus_error(smbus_bwrite(parent, s->slave,
|
||||
s->cmd, s->count, buf));
|
||||
if (s->wcount < 0) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (s->wcount > SMB_MAXBLOCKSIZE)
|
||||
s->wcount = SMB_MAXBLOCKSIZE;
|
||||
if (s->wcount)
|
||||
error = copyin(s->wbuf, buf, s->wcount);
|
||||
if (error)
|
||||
break;
|
||||
error = smbus_error(smbus_bwrite(parent, s->slave, s->cmd,
|
||||
s->wcount, buf));
|
||||
break;
|
||||
|
||||
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD6)
|
||||
case SMB_OLD_BREAD:
|
||||
#endif
|
||||
case SMB_BREAD:
|
||||
if (s->count && s->data.byte_ptr) {
|
||||
count = min(s->count, SMB_MAXBLOCKSIZE);
|
||||
error = smbus_error(smbus_bread(parent, s->slave,
|
||||
s->cmd, &count, buf));
|
||||
if (error)
|
||||
break;
|
||||
error = copyout(buf, s->data.byte_ptr,
|
||||
min(count, s->count));
|
||||
s->count = count;
|
||||
if (s->rcount < 0) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (s->rcount > SMB_MAXBLOCKSIZE)
|
||||
s->rcount = SMB_MAXBLOCKSIZE;
|
||||
error = smbus_error(smbus_bread(parent, s->slave, s->cmd,
|
||||
&bcount, buf));
|
||||
if (error)
|
||||
break;
|
||||
if (s->rcount > bcount)
|
||||
s->rcount = bcount;
|
||||
error = copyout(buf, s->rbuf, s->rcount);
|
||||
break;
|
||||
|
||||
case SMB_TRANS:
|
||||
if (s->rcount < 0 || s->wcount < 0) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (s->rcount > SMB_MAXBLOCKSIZE)
|
||||
s->rcount = SMB_MAXBLOCKSIZE;
|
||||
if (s->wcount > SMB_MAXBLOCKSIZE)
|
||||
s->wcount = SMB_MAXBLOCKSIZE;
|
||||
if (s->wcount)
|
||||
error = copyin(s->wbuf, buf, s->wcount);
|
||||
if (error)
|
||||
break;
|
||||
error = smbus_error(smbus_trans(parent, s->slave, s->cmd,
|
||||
s->op, buf, s->wcount, buf, s->rcount, &s->rcount));
|
||||
if (error == 0)
|
||||
error = copyout(buf, s->rbuf, s->rcount);
|
||||
break;
|
||||
default:
|
||||
error = ENOTTY;
|
||||
}
|
||||
|
@ -32,27 +32,33 @@
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
struct smbcmd {
|
||||
char cmd;
|
||||
int count;
|
||||
u_char slave;
|
||||
u_char cmd;
|
||||
u_char reserved;
|
||||
u_short op;
|
||||
union {
|
||||
char byte;
|
||||
short word;
|
||||
|
||||
char *byte_ptr;
|
||||
short *word_ptr;
|
||||
|
||||
struct {
|
||||
short sdata;
|
||||
short *rdata;
|
||||
} process;
|
||||
} data;
|
||||
char byte;
|
||||
char buf[2];
|
||||
short word;
|
||||
} wdata;
|
||||
union {
|
||||
char byte;
|
||||
char buf[2];
|
||||
short word;
|
||||
} rdata;
|
||||
int slave;
|
||||
char *wbuf; /* use wdata if NULL */
|
||||
int wcount;
|
||||
char *rbuf; /* use rdata if NULL */
|
||||
int rcount;
|
||||
};
|
||||
|
||||
/*
|
||||
* SMBus spec 2.0 says block transfers may be at most 32 bytes.
|
||||
* We use SMBus for i2c as well, make the size limit something more
|
||||
* reasonable. Keep in mind that a char buf array is declared on the
|
||||
* kernel stack.
|
||||
*/
|
||||
#define SMB_MAXBLOCKSIZE 32
|
||||
#define SMB_MAXBLOCKSIZE 1024
|
||||
|
||||
#define SMB_QUICK_WRITE _IOW('i', 1, struct smbcmd)
|
||||
#define SMB_QUICK_READ _IOW('i', 2, struct smbcmd)
|
||||
@ -66,5 +72,6 @@ struct smbcmd {
|
||||
#define SMB_BWRITE _IOW('i', 10, struct smbcmd)
|
||||
#define SMB_OLD_BREAD _IOW('i', 11, struct smbcmd)
|
||||
#define SMB_BREAD _IOWR('i', 11, struct smbcmd)
|
||||
#define SMB_TRANS _IOWR('i', 12, struct smbcmd)
|
||||
|
||||
#endif
|
||||
|
@ -67,10 +67,31 @@
|
||||
#define SMB_QWRITE 0x0
|
||||
#define SMB_QREAD 0x1
|
||||
|
||||
/*
|
||||
* smbus transction op with pass-thru capabilities
|
||||
*
|
||||
* This smbus function is capable of doing a smbus command transaction
|
||||
* (read or write), and can be flagged to not issue the 'cmd' and/or
|
||||
* issue or expect a count field as well as flagged for chaining (no STOP),
|
||||
* which gives it an i2c pass-through capability.
|
||||
*
|
||||
* NOSTOP- Caller chaining transactions, do not issue STOP
|
||||
* NOCMD- Do not transmit the command field
|
||||
* NOCNT- Do not transmit (wr) or expect (rd) the count field
|
||||
*/
|
||||
#define SMB_TRANS_NOSTOP 0x0001 /* do not send STOP at end */
|
||||
#define SMB_TRANS_NOCMD 0x0002 /* ignore cmd field (do not tx) */
|
||||
#define SMB_TRANS_NOCNT 0x0004 /* do not tx or rx count field */
|
||||
#define SMB_TRANS_7BIT 0x0008 /* change address mode to 7-bit */
|
||||
#define SMB_TRANS_10BIT 0x0010 /* change address mode to 10-bit */
|
||||
#define SMB_TRANS_NOREPORT 0x0020 /* do not report errors */
|
||||
|
||||
/*
|
||||
* ivars codes
|
||||
*/
|
||||
#define SMBUS_IVAR_ADDR 0x1 /* slave address of the device */
|
||||
enum smbus_ivars {
|
||||
SMBUS_IVAR_ADDR, /* slave address of the device */
|
||||
};
|
||||
|
||||
int smbus_request_bus(device_t, device_t, int);
|
||||
int smbus_release_bus(device_t, device_t);
|
||||
@ -79,7 +100,12 @@ int smbus_error(int error);
|
||||
|
||||
void smbus_intr(device_t, u_char, char low, char high, int error);
|
||||
|
||||
u_char smbus_get_addr(device_t);
|
||||
#define SMBUS_ACCESSOR(var, ivar, type) \
|
||||
__BUS_ACCESSOR(smbus, var, SMBUS, ivar, type)
|
||||
|
||||
SMBUS_ACCESSOR(addr, ADDR, int)
|
||||
|
||||
#undef SMBUS_ACCESSOR
|
||||
|
||||
extern driver_t smbus_driver;
|
||||
extern devclass_t smbus_devclass;
|
||||
@ -104,6 +130,9 @@ extern devclass_t smbus_devclass;
|
||||
(SMBUS_BWRITE(device_get_parent(bus), slave, cmd, count, buf))
|
||||
#define smbus_bread(bus,slave,cmd,count,buf) \
|
||||
(SMBUS_BREAD(device_get_parent(bus), slave, cmd, count, buf))
|
||||
#define smbus_trans(bus,slave,cmd,op,wbuf,wcount,rbuf,rcount,actualp) \
|
||||
(SMBUS_TRANS(device_get_parent(bus), slave, cmd, op, \
|
||||
wbuf, wcount, rbuf, rcount, actualp))
|
||||
|
||||
#define SMBUS_MODVER 1
|
||||
#define SMBUS_MINVER 1
|
||||
|
@ -38,6 +38,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/smbus/smbconf.h>
|
||||
#include <dev/smbus/smbus.h>
|
||||
|
||||
#include "smbus_if.h"
|
||||
#include "bus_if.h"
|
||||
|
||||
|
||||
/*
|
||||
* Autoconfiguration and support routines for System Management bus
|
||||
*/
|
||||
@ -49,6 +53,13 @@ static int smbus_probe(device_t);
|
||||
static int smbus_attach(device_t);
|
||||
static int smbus_detach(device_t);
|
||||
|
||||
static int smbus_child_location_str(device_t parent, device_t child,
|
||||
char *buf, size_t buflen);
|
||||
static int smbus_print_child(device_t parent, device_t child);
|
||||
static void smbus_probe_device(device_t dev, u_char* addr);
|
||||
static int smbus_read_ivar(device_t parent, device_t child, int which,
|
||||
uintptr_t *result);
|
||||
|
||||
static device_method_t smbus_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_probe, smbus_probe),
|
||||
@ -57,6 +68,10 @@ static device_method_t smbus_methods[] = {
|
||||
|
||||
/* bus interface */
|
||||
DEVMETHOD(bus_add_child, bus_generic_add_child),
|
||||
DEVMETHOD(bus_child_location_str, smbus_child_location_str),
|
||||
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
|
||||
DEVMETHOD(bus_print_child, smbus_print_child),
|
||||
DEVMETHOD(bus_read_ivar, smbus_read_ivar),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
@ -87,9 +102,14 @@ static int
|
||||
smbus_attach(device_t dev)
|
||||
{
|
||||
struct smbus_softc *sc = device_get_softc(dev);
|
||||
unsigned char addr;
|
||||
|
||||
mtx_init(&sc->lock, device_get_nameunit(dev), "smbus", MTX_DEF);
|
||||
bus_generic_probe(dev);
|
||||
for (addr = SMBUS_ADDR_MIN; addr < SMBUS_ADDR_MAX; ++addr) {
|
||||
sc->addrs[addr] = addr;
|
||||
smbus_probe_device(dev, &sc->addrs[addr]);
|
||||
}
|
||||
bus_generic_attach(dev);
|
||||
|
||||
return (0);
|
||||
@ -114,4 +134,70 @@ smbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
smbus_probe_device(device_t dev, u_char* addr)
|
||||
{
|
||||
device_t child;
|
||||
int error;
|
||||
u_char cmd;
|
||||
u_char buf[2];
|
||||
|
||||
cmd = 0x01;
|
||||
error = smbus_trans(dev, *addr, cmd,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_NOREPORT,
|
||||
NULL, 0, buf, 1, NULL);
|
||||
if (error == 0) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "Probed address 0x%02x\n", *addr);
|
||||
child = device_add_child(dev, NULL, -1);
|
||||
device_set_ivars(child, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
smbus_child_location_str(device_t parent, device_t child, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
unsigned char *addr;
|
||||
|
||||
addr = device_get_ivars(child);
|
||||
if (addr)
|
||||
snprintf(buf, buflen, "addr=0x%x", *addr);
|
||||
else if (buflen)
|
||||
buf[0] = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbus_print_child(device_t parent, device_t child)
|
||||
{
|
||||
unsigned char *addr;
|
||||
int retval;
|
||||
|
||||
addr = device_get_ivars(child);
|
||||
retval = bus_print_child_header(parent, child);
|
||||
if (addr)
|
||||
retval += printf(" at addr 0x%x", *addr);
|
||||
retval += bus_print_child_footer(parent, child);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static int
|
||||
smbus_read_ivar(device_t parent, device_t child, int which,
|
||||
uintptr_t *result)
|
||||
{
|
||||
unsigned char *addr;
|
||||
|
||||
addr = device_get_ivars(child);
|
||||
switch (which) {
|
||||
case SMBUS_IVAR_ADDR:
|
||||
*result = (addr == NULL) ? -1 : *addr;
|
||||
break;
|
||||
default:
|
||||
return (ENOENT);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
MODULE_VERSION(smbus, SMBUS_MODVER);
|
||||
|
@ -29,9 +29,13 @@
|
||||
#ifndef __SMBUS_H
|
||||
#define __SMBUS_H
|
||||
|
||||
#define SMBUS_ADDR_MIN 0x10
|
||||
#define SMBUS_ADDR_MAX 0x70
|
||||
|
||||
struct smbus_softc {
|
||||
device_t owner; /* smbus owner device structure */
|
||||
struct mtx lock;
|
||||
unsigned char addrs[SMBUS_ADDR_MAX];
|
||||
};
|
||||
|
||||
void smbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err);
|
||||
|
@ -149,3 +149,20 @@ METHOD int bread {
|
||||
u_char *count;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
#
|
||||
# SMB roll-up transaction with flags that also allow it to be
|
||||
# used for (mostly) i2c pass-through and with 10-bit addresses.
|
||||
# This function can be used to roll-up all of the above functions.
|
||||
#
|
||||
METHOD int trans {
|
||||
device_t dev;
|
||||
int slave;
|
||||
char cmd;
|
||||
int op;
|
||||
char *wbuf;
|
||||
int wcount;
|
||||
char *rbuf;
|
||||
int rcount;
|
||||
int *actualp;
|
||||
};
|
||||
|
@ -163,7 +163,8 @@ do_io(void)
|
||||
}
|
||||
if (iflag == 1 && oflag == -1) {
|
||||
/* command + 1 byte input: read byte op. */
|
||||
c.data.byte_ptr = ibuf;
|
||||
c.rbuf = ibuf;
|
||||
c.rcount = iflag;
|
||||
if (ioctl(fd, SMB_READB, &c) == -1)
|
||||
return (-1);
|
||||
printf(fmt, (int)(unsigned char)ibuf[0]);
|
||||
@ -171,11 +172,12 @@ do_io(void)
|
||||
return (0);
|
||||
} else if (iflag == -1 && oflag == 1) {
|
||||
/* command + 1 byte output: write byte op. */
|
||||
c.data.byte = obuf[0];
|
||||
c.wdata.byte = obuf[0];
|
||||
return (ioctl(fd, SMB_WRITEB, &c));
|
||||
} else if (wflag && iflag == 2 && oflag == -1) {
|
||||
/* command + 2 bytes input: read word op. */
|
||||
c.data.word_ptr = &iword;
|
||||
c.rbuf = (char*) &iword;
|
||||
c.rcount = iflag;
|
||||
if (ioctl(fd, SMB_READW, &c) == -1)
|
||||
return (-1);
|
||||
printf(fmt, (int)(unsigned short)iword);
|
||||
@ -183,15 +185,16 @@ do_io(void)
|
||||
return (0);
|
||||
} else if (wflag && iflag == -1 && oflag == 2) {
|
||||
/* command + 2 bytes output: write word op. */
|
||||
c.data.word = oword;
|
||||
c.wdata.word = oword;
|
||||
return (ioctl(fd, SMB_WRITEW, &c));
|
||||
} else if (wflag && iflag == 2 && oflag == 2) {
|
||||
/*
|
||||
* command + 2 bytes output + 2 bytes input:
|
||||
* "process call" op.
|
||||
*/
|
||||
c.data.process.sdata = oword;
|
||||
c.data.process.rdata = &iword;
|
||||
c.wdata.word = oword;
|
||||
c.rbuf = (char*) &iword;
|
||||
c.rcount = iflag;
|
||||
if (ioctl(fd, SMB_PCALL, &c) == -1)
|
||||
return (-1);
|
||||
printf(fmt, (int)(unsigned short)iword);
|
||||
@ -199,8 +202,8 @@ do_io(void)
|
||||
return (0);
|
||||
} else if (iflag > 1 && oflag == -1) {
|
||||
/* command + > 1 bytes of input: block read */
|
||||
c.data.byte_ptr = ibuf;
|
||||
c.count = iflag;
|
||||
c.rbuf = ibuf;
|
||||
c.rcount = iflag;
|
||||
if (ioctl(fd, SMB_BREAD, &c) == -1)
|
||||
return (-1);
|
||||
for (i = 0; i < iflag; i++) {
|
||||
@ -212,8 +215,8 @@ do_io(void)
|
||||
return (0);
|
||||
} else if (iflag == -1 && oflag > 1) {
|
||||
/* command + > 1 bytes of output: block write */
|
||||
c.data.byte_ptr = obuf;
|
||||
c.count = oflag;
|
||||
c.wbuf = obuf;
|
||||
c.wcount = oflag;
|
||||
return (ioctl(fd, SMB_BWRITE, &c));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user