From nobody Mon Apr 13 12:33:45 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fvRfR1Hlcz6Z6ks for ; Mon, 13 Apr 2026 12:33:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fvRfR0VlLz3bZL for ; Mon, 13 Apr 2026 12:33:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776083631; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5OhIV6F0eFPfcLZUSwCf27mD0Ezr2X6AzjjKziASgz8=; b=AugtU5uTRdY0QlCAcdXsFP8+mFJO5QOobHof7XbLdjaUPvZgbZwI7bqWS2Pr2CYX2Qi5tH YdE8H4fK/MKRxKrZwYQmuRb2p9+L9acdSMc6kibGpSdrhpyKOHBN1GTD09DeoH+gqJscnm 36o/rP8SUfnD4capAZ5Ra+az00yGK/W/q0v1JMSRfDnV3zfk3oep8AVcEV0Vzmf4FA9ecL sSGQ5mAA1fyNypO3DdBhNL0tiuSa/powQ9mCDZ0unl6Mke+ofQ4NY6Lp419cEjj26S4aTd pfAoP8OK4uXxyIy1hLfT9qt45joRk2z2nm4wHQcjSdYsxIYaiYYJffwUOHXiig== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1776083631; a=rsa-sha256; cv=none; b=j1dQCoixWN78bIF6qgUiYSgbU7WZ5rjFpFPMAFTERz/x6pzsEZvDb8JJCNiPNG7IfZjelK Ug+1q98ZpxSdOAsdCumVpMh+00PRh+hznLToDt1+4P1dnA4RZ1oTCcoxnWclK8AiJ03Tj5 Q0PfTytlN2q7NV9qgHaOnBnVyLP8FVYTihpG1AVOob7CDni2ZOIDrJJ8m/MAqQRNuKkWZf zocstOkaAsNaOXwD8bxuFSZnJ8LyAbmCvoBVFAq51uUf1EOzETXWwiuyI3vMPjVQ6SWu7s XGDCs5aUqvDN9QJcLbfHh0j6M1ukVXQMycJOMepPwijDklz3XTS9LeTqC6uiHg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1776083631; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5OhIV6F0eFPfcLZUSwCf27mD0Ezr2X6AzjjKziASgz8=; b=jBXkhaGpkyf3o/seLXvXgcnUa1Q/Q6Lpi4ovfqxpizLeQ7kQ6QRAbA5+G0HgsixU9lm3G0 6aiDkTi8kM2GnR5I2gpD76Vlrd9fbAYTFgMVWkPv4qF9OsVXKSeFrTGDQmqMlZ+OQtkPXM vmLNaGqk9/yIIRlhrbyiZNHgNB5ZO+/WQ3SDNwF8sHXlb2+HhBIIUOcQ+IrKjqJ3KxPWfJ ZFio/VY1+LlZe0Gka+0cLEYURC/NPhSx+F8rROxkhrdv8fv11C835b7o/6oJW7pTPOme1j d7G6OX5WuyRrLbsjo57DT1pguXPGdvwBEIuxNKchf7MCNGqGqKkPLeW7dO3LkA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fvRfR03MZz13xn for ; Mon, 13 Apr 2026 12:33:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3c629 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 13 Apr 2026 12:33:45 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: YAO, Xin From: Pouria Mousavizadeh Tehrani Subject: git: 26740e8f80da - main - compat/linux: Add Linux i2c-dev ioctl compatibility support List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 26740e8f80da17c78bee6fa322e6bb1f2669be5c Auto-Submitted: auto-generated Date: Mon, 13 Apr 2026 12:33:45 +0000 Message-Id: <69dce2a9.3c629.544d35cd@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=26740e8f80da17c78bee6fa322e6bb1f2669be5c commit 26740e8f80da17c78bee6fa322e6bb1f2669be5c Author: YAO, Xin AuthorDate: 2026-04-13 12:28:48 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-04-13 12:31:47 +0000 compat/linux: Add Linux i2c-dev ioctl compatibility support Implement Linux I2C ioctl translation in the Linux compatibility layer and wire iicbus cdevs up for in-kernel rdwr handling. Support common i2c-dev requests including SLAVE, FUNCS, and RDWR, while rejecting unsupported 10-bit and SMBus operations. Signed-off-by: YAO, Xin Reviewed by: imp, adrian, pouria Differential Revision: https://reviews.freebsd.org/D56251 --- sys/compat/linux/linux_ioctl.c | 115 +++++++++++++++++++++++++++++++++++++++++ sys/compat/linux/linux_ioctl.h | 24 +++++++++ sys/dev/iicbus/iic.c | 39 ++++++++++++-- sys/dev/iicbus/iic.h | 8 +++ 4 files changed, 182 insertions(+), 4 deletions(-) diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index d2fa0331026b..b68e950a2dcf 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ #include #include +#include #include #ifdef COMPAT_LINUX32 @@ -100,6 +102,7 @@ DEFINE_LINUX_IOCTL_SET(vfat, VFAT); 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 @@ struct linux_hd_big_geometry { 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 @@ linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args) } #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/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 116a4e676228..769f56b7de51 100644 --- 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/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c index efb8569a23c0..c3fcb2dbdaed 100644 --- a/sys/dev/iicbus/iic.c +++ b/sys/dev/iicbus/iic.c @@ -31,11 +31,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -96,7 +98,10 @@ static void iic_identify(driver_t *driver, device_t parent); 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 @@ iic_attach(device_t dev) return (ENXIO); } sc->sc_devnode->si_drv1 = sc; + sc->sc_devnode->si_drv2 = (void *)iic_linux_rdwr; return (0); } @@ -341,7 +347,7 @@ iic_copyinmsgs32(struct iic_rdwr_data *d, struct iic_msg *buf) 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 @@ iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags, 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 @@ iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags, 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 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t compat32 = false; #endif error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags, - compat32); + compat32, false); break; diff --git a/sys/dev/iicbus/iic.h b/sys/dev/iicbus/iic.h index f6e9360186e0..badfb76e92eb 100644 --- a/sys/dev/iicbus/iic.h +++ b/sys/dev/iicbus/iic.h @@ -31,6 +31,14 @@ #include +#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 {