Skip to content

Commit

Permalink
Expand SMBUS API to add smbus_trans() function.
Browse files Browse the repository at this point in the history
Differential Revision:	https://reviews.freebsd.org/D1955
Reviewed by:	adrian, jhb, wblock
Approved by:	adrian, jhb
  • Loading branch information
grembo committed Apr 25, 2015
1 parent a9467c3 commit 202379a
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 116 deletions.
99 changes: 69 additions & 30 deletions share/man/man4/smb.4
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.\" Copyright (c) 1998, Nicolas Souchu
.\" Copyright (c) 2004, Joerg Wunsch
.\" Copyright (c) 2015, Michael Gmelin <[email protected]>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
Expand All @@ -25,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 6, 2009
.Dd April 25, 2015
.Dt SMB 4
.Os
.Sh NAME
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -123,38 +127,42 @@ 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
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
Expand All @@ -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 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 data.byte_ptr .
.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
Expand Down Expand Up @@ -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 [email protected]
.
148 changes: 90 additions & 58 deletions sys/dev/smbus/smb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 202379a

Please sign in to comment.