Index: arch/amd64/amd64/conf.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/conf.c,v retrieving revision 1.71 diff -u -p -r1.71 conf.c --- arch/amd64/amd64/conf.c 6 Jul 2020 04:32:25 -0000 1.71 +++ arch/amd64/amd64/conf.c 14 Sep 2020 23:55:07 -0000 @@ -158,6 +158,8 @@ cdev_decl(nvram); cdev_decl(drm); #include "viocon.h" cdev_decl(viocon); +#include "iic.h" +cdev_decl(iic); #include "wsdisplay.h" #include "wskbd.h" @@ -295,6 +297,7 @@ struct cdevsw cdevsw[] = cdev_switch_init(NSWITCH,switch), /* 97: switch(4) control interface */ cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security keys */ cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ + cdev_iic_init(NIIC,iic), /* 100: I2C (iic) access */ }; int nchrdev = nitems(cdevsw); Index: dev/i2c/files.i2c =================================================================== RCS file: /cvs/src/sys/dev/i2c/files.i2c,v retrieving revision 1.66 diff -u -p -r1.66 files.i2c --- dev/i2c/files.i2c 18 Jun 2020 18:05:00 -0000 1.66 +++ dev/i2c/files.i2c 14 Sep 2020 23:55:08 -0000 @@ -4,7 +4,7 @@ define i2c {[addr = -1], [size = -1]} device iic: i2c attach iic at i2cbus -file dev/i2c/i2c.c iic | i2cbus +file dev/i2c/i2c.c iic | i2cbus needs-flag file dev/i2c/i2c_exec.c iic | i2cbus file dev/i2c/i2c_scan.c iic | i2cbus Index: dev/i2c/i2c.c =================================================================== RCS file: /cvs/src/sys/dev/i2c/i2c.c,v retrieving revision 1.16 diff -u -p -r1.16 i2c.c --- dev/i2c/i2c.c 14 Mar 2015 03:38:47 -0000 1.16 +++ dev/i2c/i2c.c 14 Sep 2020 23:55:08 -0000 @@ -143,3 +143,109 @@ iic_attach(struct device *parent, struct else iic_scan(self, aux); } + +static struct iic_softc * +iic_lookup(dev_t dev) +{ + unsigned int unit = minor(dev); + unsigned int master = IIC_MASTER(unit); + + if (master > iic_cd.cd_ndevs) + return (NULL); + + return (iic_cd.cd_devs[master]); +} + +int +iicopen(dev_t dev, int flags, int mode, struct proc *p) +{ + struct iic_softc *sc; + unsigned int unit = minor(dev); + + sc = iic_lookup(dev); + if (sc == NULL) + return (ENXIO); + + if (IIC_ADDR_TYPE(unit) != IIC_ADDR_TYPE_7B) { + /* XXX */ + return (ENXIO); + } + + return (0); +} + +static int +iic_ioc_exec(struct iic_softc *sc, i2c_addr_t addr, struct iic_ioc_op *iio) +{ + uint8_t cmd[IIC_CMD_MAXLEN]; + uint8_t buf[IIC_CMD_MAXLEN]; + int error; + + if (iio->iio_cmdlen > sizeof(cmd)) + return (ENOBUFS); /* wat */ + if (iio->iio_buflen > sizeof(buf)) + return (ENOBUFS); + + if (iio->iio_cmdlen > 0) { + error = copyin(iio->iio_cmd, cmd, iio->iio_cmdlen); + if (error != 0) + return (error); + } + + if (iio->iio_buflen > 0 && I2C_OP_WRITE_P(iio->iio_op)) { + error = copyin(iio->iio_buf, buf, iio->iio_buflen); + if (error != 0) + return (error); + } + + error = iic_acquire_bus(sc->sc_tag, 0); + if (error != 0) + return (error); + + if (iic_exec(sc->sc_tag, iio->iio_op, addr, + cmd, iio->iio_cmdlen, buf, iio->iio_buflen, 0) != 0) + error = EIO; + + iic_release_bus(sc->sc_tag, 0); + + if (error != 0) + return (error); + + if (iio->iio_buflen > 0 && I2C_OP_READ_P(iio->iio_op)) { + error = copyout(buf, iio->iio_buf, iio->iio_buflen); + if (error != 0) + return (error); + } + + return (0); +} + +int +iicioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) +{ + struct iic_softc *sc; + unsigned int unit = minor(dev); + int error = 0; + + sc = iic_lookup(dev); + if (sc == NULL) + return (ENXIO); + + switch (cmd) { + case I2C_IOCTL_EXEC: + error = iic_ioc_exec(sc, IIC_ADDR(unit), + (struct iic_ioc_op *)addr); + break; + default: + error = ENOTTY; + break; + } + + return (error); +} + +int +iicclose(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} Index: dev/i2c/i2c_io.h =================================================================== RCS file: /cvs/src/sys/dev/i2c/i2c_io.h,v retrieving revision 1.2 diff -u -p -r1.2 i2c_io.h --- dev/i2c/i2c_io.h 11 Jan 2020 11:30:47 -0000 1.2 +++ dev/i2c/i2c_io.h 14 Sep 2020 23:55:08 -0000 @@ -86,24 +86,40 @@ typedef enum { * I2C_OP_WRITE and I2C_OP_READ. */ -#ifdef notyet /* - * I2C_IOCTL_EXEC: - * - * User ioctl to execute an i2c operation. + * The iic(4) dev_t minor is split into parts that identify the + * master (ie, which iic(4) device) and a slave attached to that + * master. The slave portion is big enough to hold a 10 bit address, + * plus a flag that identifies if it is a 10bit address or not. */ -typedef struct i2c_ioctl_exec { - i2c_op_t iie_op; /* operation to perform */ - i2c_addr_t iie_addr; /* address of device */ - const void *iie_cmd; /* pointer to command */ - size_t iie_cmdlen; /* length of command */ - void *iie_buf; /* pointer to data buffer */ - size_t iie_buflen; /* length of data buffer */ -} i2c_ioctl_exec_t; -#define I2C_EXEC_MAX_CMDLEN 32 -#define I2C_EXEC_MAX_BUFLEN 32 -#define I2C_IOCTL_EXEC _IOW('I', 0, i2c_ioctl_exec_t) -#endif +#define IIC_SLAVE_BITS 12 + +#define IIC_MASTER(_u) ((_u) >> IIC_SLAVE_BITS) +#define IIC_SLAVE(_u) ((_u) & ((1 << IIC_SLAVE_BITS) - 1)) + +#define IIC_ADDR_BITS 10 +#define IIC_ADDR_MASK ((1 << IIC_ADDR_BITS) - 1) +#define IIC_ADDR(_u) ((_u) & IIC_ADDR_MASK) + +#define IIC_ADDR_TYPE_SHIFT (IIC_ADDR_BITS + 1) +#define IIC_ADDR_TYPE_MASK (1U << IIC_ADDR_TYPE_SHIFT) +#define IIC_ADDR_TYPE(_a) ((_a) & IIC_ADDR_TYPE_MASK) +#define IIC_ADDR_TYPE_7B (0U << IIC_ADDR_TYPE_SHIFT) +#define IIC_ADDR_TYPE_10B (1U << IIC_ADDR_TYPE_SHIFT) + +#define IIC_CMD_MAXLEN 32 +#define IIC_BUF_MAXLEN 32 + +struct iic_ioc_op { + i2c_op_t iio_op; + i2c_addr_t iio_addr; + const void *iio_cmd; + size_t iio_cmdlen; + void *iio_buf; + size_t iio_buflen; +}; + +#define I2C_IOCTL_EXEC _IOW('2', 0, struct iic_ioc_op) #endif /* _DEV_I2C_I2C_IO_H_ */ Index: sys/conf.h =================================================================== RCS file: /cvs/src/sys/sys/conf.h,v retrieving revision 1.155 diff -u -p -r1.155 conf.h --- sys/conf.h 6 Jul 2020 04:11:26 -0000 1.155 +++ sys/conf.h 14 Sep 2020 23:55:09 -0000 @@ -300,6 +300,13 @@ extern struct cdevsw cdevsw[]; (dev_type_stop((*))) enodev, 0, selfalse, \ (dev_type_mmap((*))) enodev } +/* open, close, ioctl */ +#define cdev_iic_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, selfalse, \ + (dev_type_mmap((*))) enodev } + /* open, close, ioctl, mmap */ #define cdev_fb_init(c,n) { \ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \