Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167236873
D56251.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D56251.id.diff
View Options
diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h
--- a/sys/compat/linux/linux_ioctl.h
+++ b/sys/compat/linux/linux_ioctl.h
@@ -71,6 +71,30 @@
#define LINUX_IOCTL_HDIO_MIN LINUX_HDIO_GET_GEO
#define LINUX_IOCTL_HDIO_MAX LINUX_HDIO_GET_GEO_BIG
+/*
+ * i2c
+ */
+#define LINUX_I2C_RETRIES 0x0701
+#define LINUX_I2C_TIMEOUT 0x0702
+#define LINUX_I2C_SLAVE 0x0703
+#define LINUX_I2C_TENBIT 0x0704
+#define LINUX_I2C_FUNCS 0x0705
+#define LINUX_I2C_SLAVE_FORCE 0x0706
+#define LINUX_I2C_RDWR 0x0707
+#define LINUX_I2C_PEC 0x0708
+#define LINUX_I2C_SMBUS 0x0720
+
+#define LINUX_IOCTL_I2C_MIN LINUX_I2C_RETRIES
+#define LINUX_IOCTL_I2C_MAX LINUX_I2C_SMBUS
+
+#define LINUX_I2C_M_RD 0x0001
+#define LINUX_I2C_M_TEN 0x0010
+#define LINUX_I2C_M_NOSTART 0x4000
+
+#define LINUX_I2C_FUNC_I2C 0x00000001UL
+#define LINUX_I2C_FUNC_10BIT_ADDR 0x00000002UL
+#define LINUX_I2C_FUNC_NOSTART 0x00000010UL
+
/*
* cdrom
*/
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -43,6 +43,7 @@
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/proc.h>
+#include <sys/vnode.h>
#include <sys/sbuf.h>
#include <sys/sockio.h>
#include <sys/soundcard.h>
@@ -59,6 +60,7 @@
#include <dev/evdev/input.h>
#include <dev/hid/hidraw.h>
+#include <dev/iicbus/iic.h>
#include <dev/usb/usb_ioctl.h>
#ifdef COMPAT_LINUX32
@@ -100,6 +102,7 @@
DEFINE_LINUX_IOCTL_SET(console, CONSOLE);
DEFINE_LINUX_IOCTL_SET(hdio, HDIO);
DEFINE_LINUX_IOCTL_SET(disk, DISK);
+DEFINE_LINUX_IOCTL_SET(i2c, I2C);
DEFINE_LINUX_IOCTL_SET(socket, SOCKET);
DEFINE_LINUX_IOCTL_SET(sound, SOUND);
DEFINE_LINUX_IOCTL_SET(termio, TERMIO);
@@ -160,6 +163,18 @@
uint32_t start;
};
+struct linux_i2c_msg {
+ uint16_t addr;
+ uint16_t flags;
+ uint16_t len;
+ l_uintptr_t buf;
+};
+
+struct linux_i2c_rdwr_data {
+ l_uintptr_t msgs;
+ l_uint nmsgs;
+};
+
static int
linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
{
@@ -3639,6 +3654,106 @@
}
#endif
+static int
+linux_ioctl_i2c(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct linux_i2c_rdwr_data lrdwr;
+ struct linux_i2c_msg *lmsgs = NULL;
+ struct iic_rdwr_data rdwr;
+ struct iic_msg *msgs = NULL;
+ struct file *fp;
+ iic_linux_rdwr_t *linux_rdwr;
+ l_ulong funcs;
+ uint16_t lflags;
+ uint8_t addr;
+ int error;
+ l_uint i;
+
+ error = fget(td, args->fd, &cap_ioctl_rights, &fp);
+ if (error != 0)
+ return (error);
+
+ linux_rdwr = NULL;
+ if (fp->f_type == DTYPE_VNODE && fp->f_vnode != NULL &&
+ fp->f_vnode->v_rdev != NULL)
+ linux_rdwr = (iic_linux_rdwr_t *)fp->f_vnode->v_rdev->si_drv2;
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_I2C_RETRIES:
+ case LINUX_I2C_TIMEOUT:
+ case LINUX_I2C_PEC:
+ error = 0;
+ break;
+ case LINUX_I2C_TENBIT:
+ error = (args->arg == 0) ? 0 : ENOTSUP;
+ break;
+ case LINUX_I2C_FUNCS:
+ funcs = LINUX_I2C_FUNC_I2C | LINUX_I2C_FUNC_NOSTART;
+ error = copyout(&funcs, (void *)args->arg, sizeof(funcs));
+ break;
+ case LINUX_I2C_SLAVE:
+ case LINUX_I2C_SLAVE_FORCE:
+ if (args->arg > 0x7f) {
+ error = EINVAL;
+ break;
+ }
+ addr = (uint8_t)(args->arg << 1);
+ error = fo_ioctl(fp, I2CSADDR, (caddr_t)&addr, td->td_ucred, td);
+ break;
+ case LINUX_I2C_RDWR:
+ error = copyin((void *)args->arg, &lrdwr, sizeof(lrdwr));
+ if (error != 0)
+ break;
+ if (lrdwr.nmsgs > IIC_RDRW_MAX_MSGS) {
+ error = EINVAL;
+ break;
+ }
+ lmsgs = malloc(sizeof(*lmsgs) * lrdwr.nmsgs, M_TEMP, M_WAITOK);
+ msgs = malloc(sizeof(*msgs) * lrdwr.nmsgs, M_TEMP, M_WAITOK);
+ error = copyin((void *)(uintptr_t)lrdwr.msgs, lmsgs,
+ sizeof(*lmsgs) * lrdwr.nmsgs);
+ if (error != 0)
+ break;
+ for (i = 0; i < lrdwr.nmsgs; i++) {
+ lflags = lmsgs[i].flags;
+ if (lmsgs[i].addr > 0x7f || (lflags & LINUX_I2C_M_TEN) != 0) {
+ error = ENOTSUP;
+ break;
+ }
+ if ((lflags & ~(LINUX_I2C_M_RD | LINUX_I2C_M_NOSTART)) != 0) {
+ error = ENOTSUP;
+ break;
+ }
+ msgs[i].slave = lmsgs[i].addr << 1;
+ msgs[i].flags = (lflags & LINUX_I2C_M_RD) ? IIC_M_RD : IIC_M_WR;
+ if ((lflags & LINUX_I2C_M_NOSTART) != 0)
+ msgs[i].flags |= IIC_M_NOSTART;
+ msgs[i].len = lmsgs[i].len;
+ msgs[i].buf = (uint8_t *)(uintptr_t)lmsgs[i].buf;
+ }
+ if (error == 0) {
+ if (linux_rdwr == NULL) {
+ error = ENOTTY;
+ } else {
+ rdwr.msgs = msgs;
+ rdwr.nmsgs = lrdwr.nmsgs;
+ error = linux_rdwr(fp, &rdwr, fp->f_flag, td);
+ if (error == 0)
+ td->td_retval[0] = lrdwr.nmsgs;
+ }
+ }
+ break;
+ case LINUX_I2C_SMBUS:
+ default:
+ error = ENOTSUP;
+ break;
+ }
+ free(msgs, M_TEMP);
+ free(lmsgs, M_TEMP);
+ fdrop(fp, td);
+ return (error);
+}
+
static int
linux_ioctl_hidraw(struct thread *td, struct linux_ioctl_args *args)
{
diff --git a/sys/dev/iicbus/iic.h b/sys/dev/iicbus/iic.h
--- a/sys/dev/iicbus/iic.h
+++ b/sys/dev/iicbus/iic.h
@@ -31,6 +31,14 @@
#include <sys/ioccom.h>
+#ifdef _KERNEL
+struct file;
+struct iic_rdwr_data;
+struct thread;
+typedef int iic_linux_rdwr_t(struct file *fp, struct iic_rdwr_data *d,
+ int flags, struct thread *td);
+#endif
+
/* Designed to be compatible with linux's struct i2c_msg */
struct iic_msg
{
diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c
--- a/sys/dev/iicbus/iic.c
+++ b/sys/dev/iicbus/iic.c
@@ -31,11 +31,13 @@
#include <sys/abi_compat.h>
#include <sys/bus.h>
#include <sys/conf.h>
+#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/proc.h>
#include <sys/sx.h>
#include <sys/systm.h>
#include <sys/uio.h>
@@ -96,7 +98,10 @@
static void iicdtor(void *data);
static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);
static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);
-static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags, bool compat32);
+static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d,
+ int flags, bool compat32, bool kernel_msgs);
+static int iic_linux_rdwr(struct file *fp, struct iic_rdwr_data *d,
+ int flags, struct thread *td);
static device_method_t iic_methods[] = {
/* device interface */
@@ -163,6 +168,7 @@
return (ENXIO);
}
sc->sc_devnode->si_drv1 = sc;
+ sc->sc_devnode->si_drv2 = (void *)iic_linux_rdwr;
return (0);
}
@@ -341,7 +347,7 @@
static int
iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags,
- bool compat32 __unused)
+ bool compat32 __unused, bool kernel_msgs)
{
#ifdef COMPAT_FREEBSD32
struct iic_rdwr_data dswab;
@@ -375,7 +381,11 @@
error = iic_copyinmsgs32(d, buf);
else
#endif
- error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
+ if (kernel_msgs)
+ memcpy(buf, d->msgs, sizeof(*d->msgs) * d->nmsgs);
+ else
+ error = copyin(d->msgs, buf,
+ sizeof(*d->msgs) * d->nmsgs);
if (error != 0) {
free(buf, M_IIC);
return (error);
@@ -424,6 +434,27 @@
return (error);
}
+static int
+iic_linux_rdwr(struct file *fp, struct iic_rdwr_data *d, int flags,
+ struct thread *td)
+{
+ struct file *saved_fp;
+ struct iic_cdevpriv *priv;
+ int error;
+
+ saved_fp = td->td_fpop;
+ td->td_fpop = fp;
+ error = devfs_get_cdevpriv((void **)&priv);
+ td->td_fpop = saved_fp;
+ if (error != 0)
+ return (error);
+
+ IIC_LOCK(priv);
+ error = iicrdwr(priv, d, flags, false, true);
+ IIC_UNLOCK(priv);
+ return (error);
+}
+
static int
iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
{
@@ -582,7 +613,7 @@
compat32 = false;
#endif
error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags,
- compat32);
+ compat32, false);
break;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 21, 5:40 AM (1 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37022656
Default Alt Text
D56251.id.diff (7 KB)
Attached To
Mode
D56251: linux: add Linux i2c-dev ioctl compatibility support
Attached
Detach File
Event Timeline
Log In to Comment