diff options
-rw-r--r-- | sys/compat/linux/linux_ioctl.c | 306 | ||||
-rw-r--r-- | sys/compat/linux/linux_ioctl.h | 97 |
2 files changed, 403 insertions, 0 deletions
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 4237f6f..770969c 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -59,6 +59,9 @@ __FBSDID("$FreeBSD$"); #include <sys/sx.h> #include <sys/tty.h> #include <sys/uio.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/resourcevar.h> #include <net/if.h> #include <net/if_dl.h> @@ -83,6 +86,9 @@ __FBSDID("$FreeBSD$"); #include <compat/linux/linux_videodev.h> #include <compat/linux/linux_videodev_compat.h> +#include <compat/linux/linux_videodev2.h> +#include <compat/linux/linux_videodev2_compat.h> + CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ); static linux_ioctl_function_t linux_ioctl_cdrom; @@ -97,6 +103,7 @@ static linux_ioctl_function_t linux_ioctl_private; static linux_ioctl_function_t linux_ioctl_drm; static linux_ioctl_function_t linux_ioctl_sg; static linux_ioctl_function_t linux_ioctl_v4l; +static linux_ioctl_function_t linux_ioctl_v4l2; static linux_ioctl_function_t linux_ioctl_special; static linux_ioctl_function_t linux_ioctl_fbsd_usb; @@ -124,6 +131,8 @@ static struct linux_ioctl_handler sg_handler = { linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX }; static struct linux_ioctl_handler video_handler = { linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX }; +static struct linux_ioctl_handler video2_handler = +{ linux_ioctl_v4l2, LINUX_IOCTL_VIDEO2_MIN, LINUX_IOCTL_VIDEO2_MAX }; static struct linux_ioctl_handler fbsd_usb = { linux_ioctl_fbsd_usb, FBSD_LUSB_MIN, FBSD_LUSB_MAX }; @@ -139,6 +148,7 @@ DATA_SET(linux_ioctl_handler_set, private_handler); DATA_SET(linux_ioctl_handler_set, drm_handler); DATA_SET(linux_ioctl_handler_set, sg_handler); DATA_SET(linux_ioctl_handler_set, video_handler); +DATA_SET(linux_ioctl_handler_set, video2_handler); DATA_SET(linux_ioctl_handler_set, fbsd_usb); struct handler_element @@ -2988,6 +2998,302 @@ linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args) return (error); } +static int +linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd) +{ + vstd->index = lvstd->index; + vstd->id = lvstd->id; + memcpy(&vstd->name, &lvstd->name, sizeof(*lvstd) - offsetof(struct l_v4l2_standard, name)); + return (0); +} + +static int +bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd) +{ + lvstd->index = vstd->index; + lvstd->id = vstd->id; + memcpy(&lvstd->name, &vstd->name, sizeof(*lvstd) - offsetof(struct l_v4l2_standard, name)); + return (0); +} + +static int +linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb) +{ + vb->index = lvb->index; + vb->type = lvb->type; + vb->bytesused = lvb->bytesused; + vb->flags = lvb->flags; + vb->field = lvb->field; + vb->timestamp.tv_sec = lvb->timestamp.tv_sec; + vb->timestamp.tv_usec = lvb->timestamp.tv_usec; + memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode)); + vb->sequence = lvb->sequence; + vb->memory = lvb->memory; + if (lvb->memory == V4L2_MEMORY_USERPTR) + /* possible pointer size conversion */ + vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr); + else + vb->m.offset = lvb->m.offset; + vb->length = lvb->length; + vb->input = lvb->input; + vb->reserved = lvb->reserved; + return (0); +} + +static int +bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb) +{ + lvb->index = vb->index; + lvb->type = vb->type; + lvb->bytesused = vb->bytesused; + lvb->flags = vb->flags; + lvb->field = vb->field; + lvb->timestamp.tv_sec = vb->timestamp.tv_sec; + lvb->timestamp.tv_usec = vb->timestamp.tv_usec; + memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode)); + lvb->sequence = vb->sequence; + lvb->memory = vb->memory; + if (vb->memory == V4L2_MEMORY_USERPTR) + /* possible pointer size conversion */ + lvb->m.userptr = PTROUT(vb->m.userptr); + else + lvb->m.offset = vb->m.offset; + lvb->length = vb->length; + lvb->input = vb->input; + lvb->reserved = vb->reserved; + return (0); +} + +static int +linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf) +{ + vf->type = lvf->type; + if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY +#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + || lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY +#endif + ) + /* + * XXX TODO - needs 32 -> 64 bit conversion: + * (unused by webcams?) + */ + return EINVAL; + memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt)); + return 0; +} + +static int +bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf) +{ + lvf->type = vf->type; + if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY +#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY + || vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY +#endif + ) + /* + * XXX TODO - needs 32 -> 64 bit conversion: + * (unused by webcams?) + */ + return EINVAL; + memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt)); + return 0; +} +static int +linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args) +{ + struct file *fp; + int error; + struct v4l2_format vformat; + struct l_v4l2_format l_vformat; + struct v4l2_standard vstd; + struct l_v4l2_standard l_vstd; + struct l_v4l2_buffer l_vbuf; + struct v4l2_buffer vbuf; + struct v4l2_input vinp; + + switch (args->cmd & 0xffff) { + case LINUX_VIDIOC_RESERVED: + case LINUX_VIDIOC_LOG_STATUS: + if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID) + return ENOIOCTL; + args->cmd = (args->cmd & 0xffff) | IOC_VOID; + break; + + case LINUX_VIDIOC_OVERLAY: + case LINUX_VIDIOC_STREAMON: + case LINUX_VIDIOC_STREAMOFF: + case LINUX_VIDIOC_S_STD: + case LINUX_VIDIOC_S_TUNER: + case LINUX_VIDIOC_S_AUDIO: + case LINUX_VIDIOC_S_AUDOUT: + case LINUX_VIDIOC_S_MODULATOR: + case LINUX_VIDIOC_S_FREQUENCY: + case LINUX_VIDIOC_S_CROP: + case LINUX_VIDIOC_S_JPEGCOMP: + case LINUX_VIDIOC_S_PRIORITY: + case LINUX_VIDIOC_DBG_S_REGISTER: + case LINUX_VIDIOC_S_HW_FREQ_SEEK: + case LINUX_VIDIOC_SUBSCRIBE_EVENT: + case LINUX_VIDIOC_UNSUBSCRIBE_EVENT: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN; + break; + + case LINUX_VIDIOC_QUERYCAP: + case LINUX_VIDIOC_G_STD: + case LINUX_VIDIOC_G_AUDIO: + case LINUX_VIDIOC_G_INPUT: + case LINUX_VIDIOC_G_OUTPUT: + case LINUX_VIDIOC_G_AUDOUT: + case LINUX_VIDIOC_G_JPEGCOMP: + case LINUX_VIDIOC_QUERYSTD: + case LINUX_VIDIOC_G_PRIORITY: + case LINUX_VIDIOC_QUERY_DV_PRESET: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT; + break; + + case LINUX_VIDIOC_ENUM_FMT: + case LINUX_VIDIOC_REQBUFS: + case LINUX_VIDIOC_G_PARM: + case LINUX_VIDIOC_S_PARM: + case LINUX_VIDIOC_G_CTRL: + case LINUX_VIDIOC_S_CTRL: + case LINUX_VIDIOC_G_TUNER: + case LINUX_VIDIOC_QUERYCTRL: + case LINUX_VIDIOC_QUERYMENU: + case LINUX_VIDIOC_S_INPUT: + case LINUX_VIDIOC_S_OUTPUT: + case LINUX_VIDIOC_ENUMOUTPUT: + case LINUX_VIDIOC_G_MODULATOR: + case LINUX_VIDIOC_G_FREQUENCY: + case LINUX_VIDIOC_CROPCAP: + case LINUX_VIDIOC_G_CROP: + case LINUX_VIDIOC_ENUMAUDIO: + case LINUX_VIDIOC_ENUMAUDOUT: + case LINUX_VIDIOC_G_SLICED_VBI_CAP: +#ifdef VIDIOC_ENUM_FRAMESIZES + case LINUX_VIDIOC_ENUM_FRAMESIZES: + case LINUX_VIDIOC_ENUM_FRAMEINTERVALS: + case LINUX_VIDIOC_ENCODER_CMD: + case LINUX_VIDIOC_TRY_ENCODER_CMD: +#endif + case LINUX_VIDIOC_DBG_G_REGISTER: + case LINUX_VIDIOC_DBG_G_CHIP_IDENT: + case LINUX_VIDIOC_ENUM_DV_PRESETS: + case LINUX_VIDIOC_S_DV_PRESET: + case LINUX_VIDIOC_G_DV_PRESET: + case LINUX_VIDIOC_S_DV_TIMINGS: + case LINUX_VIDIOC_G_DV_TIMINGS: + args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT; + break; + + case LINUX_VIDIOC_G_FMT: + case LINUX_VIDIOC_S_FMT: + case LINUX_VIDIOC_TRY_FMT: + error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat)); + if (error) + return (error); + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) + error = EINVAL; + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT) + error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat, + td->td_ucred, td); + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT) + error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat, + td->td_ucred, td); + else + error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat, + td->td_ucred, td); + bsd_to_linux_v4l2_format(&vformat, &l_vformat); + copyout(&l_vformat, (void *)args->arg, sizeof(l_vformat)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_ENUMSTD: + error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd)); + if (error) + return (error); + linux_to_bsd_v4l2_standard(&l_vstd, &vstd); + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, + td->td_ucred, td); + if (error) { + fdrop(fp, td); + return (error); + } + bsd_to_linux_v4l2_standard(&vstd, &l_vstd); + error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_ENUMINPUT: + /* + * The Linux struct l_v4l2_input differs only in size, + * it has no padding at the end. + */ + error = copyin((void *)args->arg, &vinp, + sizeof(struct l_v4l2_input)); + if (error != 0) + return (error); + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, + td->td_ucred, td); + if (error) { + fdrop(fp, td); + return (error); + } + error = copyout(&vinp, (void *)args->arg, + sizeof(struct l_v4l2_input)); + fdrop(fp, td); + return (error); + + case LINUX_VIDIOC_QUERYBUF: + case LINUX_VIDIOC_QBUF: + case LINUX_VIDIOC_DQBUF: + error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf)); + if (error) + return (error); + if ((error = fget(td, args->fd, &fp)) != 0) + return (error); + linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); + if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) + error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf, + td->td_ucred, td); + else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF) + error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf, + td->td_ucred, td); + else + error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf, + td->td_ucred, td); + bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf); + copyout(&l_vbuf, (void *)args->arg, sizeof(l_vbuf)); + fdrop(fp, td); + return (error); + + /* + * XXX TODO - these need 32 -> 64 bit conversion: + * (are any of them needed for webcams?) + */ + case LINUX_VIDIOC_G_FBUF: + case LINUX_VIDIOC_S_FBUF: + + case LINUX_VIDIOC_G_EXT_CTRLS: + case LINUX_VIDIOC_S_EXT_CTRLS: + case LINUX_VIDIOC_TRY_EXT_CTRLS: + + case LINUX_VIDIOC_DQEVENT: + + default: return (ENOIOCTL); + } + + error = ioctl(td, (struct ioctl_args *)args); + return (error); +} + /* * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros * instead of USB* ones. This lets us to provide correct values for cmd. diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h index 08ccf88..c075231 100644 --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -32,6 +32,17 @@ #define _LINUX_IOCTL_H_ /* + * ioctl + * + * XXX comments in Linux' <asm-generic/ioctl.h> indicate these + * could be arch-dependant... + */ +#define LINUX_IOC_VOID 0 +#define LINUX_IOC_IN 0x40000000 +#define LINUX_IOC_OUT 0x80000000 +#define LINUX_IOC_INOUT (LINUX_IOC_IN|LINUX_IOC_OUT) + +/* * disk */ #define LINUX_BLKROSET 0x125d @@ -612,6 +623,92 @@ int linux_ifname(struct ifnet *, char *, size_t); #define LINUX_IOCTL_VIDEO_MIN LINUX_VIDIOCGCAP #define LINUX_IOCTL_VIDEO_MAX LINUX_VIDIOCSVBIFMT +/* videodev2 aka V4L2 */ + +#define LINUX_VIDIOC_QUERYCAP 0x5600 /* 0x80685600 */ +#define LINUX_VIDIOC_RESERVED 0x5601 /* 0x00005601 */ +#define LINUX_VIDIOC_ENUM_FMT 0x5602 /* 0xc0405602 */ +#define LINUX_VIDIOC_G_FMT 0x5604 /* 0xc0cc5604 */ +#define LINUX_VIDIOC_S_FMT 0x5605 /* 0xc0cc5605 */ +#define LINUX_VIDIOC_REQBUFS 0x5608 /* 0xc0145608 */ +#define LINUX_VIDIOC_QUERYBUF 0x5609 /* 0xc0445609 */ +#define LINUX_VIDIOC_G_FBUF 0x560a /* 0x802c560a */ +#define LINUX_VIDIOC_S_FBUF 0x560b /* 0x402c560b */ +#define LINUX_VIDIOC_OVERLAY 0x560e /* 0x4004560e */ +#define LINUX_VIDIOC_QBUF 0x560f /* 0xc044560f */ +#define LINUX_VIDIOC_DQBUF 0x5611 /* 0xc0445611 */ +#define LINUX_VIDIOC_STREAMON 0x5612 /* 0x40045612 */ +#define LINUX_VIDIOC_STREAMOFF 0x5613 /* 0x40045613 */ +#define LINUX_VIDIOC_G_PARM 0x5615 /* 0xc0cc5615 */ +#define LINUX_VIDIOC_S_PARM 0x5616 /* 0xc0cc5616 */ +#define LINUX_VIDIOC_G_STD 0x5617 /* 0x80085617 */ +#define LINUX_VIDIOC_S_STD 0x5618 /* 0x40085618 */ +#define LINUX_VIDIOC_ENUMSTD 0x5619 /* 0xc0405619 */ +#define LINUX_VIDIOC_ENUMINPUT 0x561a /* 0xc04c561a */ +#define LINUX_VIDIOC_G_CTRL 0x561b /* 0xc008561b */ +#define LINUX_VIDIOC_S_CTRL 0x561c /* 0xc008561c */ +#define LINUX_VIDIOC_G_TUNER 0x561d /* 0xc054561d */ +#define LINUX_VIDIOC_S_TUNER 0x561e /* 0x4054561e */ +#define LINUX_VIDIOC_G_AUDIO 0x5621 /* 0x80345621 */ +#define LINUX_VIDIOC_S_AUDIO 0x5622 /* 0x40345622 */ +#define LINUX_VIDIOC_QUERYCTRL 0x5624 /* 0xc0445624 */ +#define LINUX_VIDIOC_QUERYMENU 0x5625 /* 0xc02c5625 */ +#define LINUX_VIDIOC_G_INPUT 0x5626 /* 0x80045626 */ +#define LINUX_VIDIOC_S_INPUT 0x5627 /* 0xc0045627 */ +#define LINUX_VIDIOC_G_OUTPUT 0x562e /* 0x8004562e */ +#define LINUX_VIDIOC_S_OUTPUT 0x562f /* 0xc004562f */ +#define LINUX_VIDIOC_ENUMOUTPUT 0x5630 /* 0xc0485630 */ +#define LINUX_VIDIOC_G_AUDOUT 0x5631 /* 0x80345631 */ +#define LINUX_VIDIOC_S_AUDOUT 0x5632 /* 0x40345632 */ +#define LINUX_VIDIOC_G_MODULATOR 0x5636 /* 0xc0445636 */ +#define LINUX_VIDIOC_S_MODULATOR 0x5637 /* 0x40445637 */ +#define LINUX_VIDIOC_G_FREQUENCY 0x5638 /* 0xc02c5638 */ +#define LINUX_VIDIOC_S_FREQUENCY 0x5639 /* 0x402c5639 */ +#define LINUX_VIDIOC_CROPCAP 0x563a /* 0xc02c563a */ +#define LINUX_VIDIOC_G_CROP 0x563b /* 0xc014563b */ +#define LINUX_VIDIOC_S_CROP 0x563c /* 0x4014563c */ +#define LINUX_VIDIOC_G_JPEGCOMP 0x563d /* 0x808c563d */ +#define LINUX_VIDIOC_S_JPEGCOMP 0x563e /* 0x408c563e */ +#define LINUX_VIDIOC_QUERYSTD 0x563f /* 0x8008563f */ +#define LINUX_VIDIOC_TRY_FMT 0x5640 /* 0xc0cc5640 */ +#define LINUX_VIDIOC_ENUMAUDIO 0x5641 /* 0xc0345641 */ +#define LINUX_VIDIOC_ENUMAUDOUT 0x5642 /* 0xc0345642 */ +#define LINUX_VIDIOC_G_PRIORITY 0x5643 /* 0x80045643 */ +#define LINUX_VIDIOC_S_PRIORITY 0x5644 /* 0x40045644 */ +#define LINUX_VIDIOC_G_SLICED_VBI_CAP 0x5645 /* 0xc0745645 */ +#define LINUX_VIDIOC_LOG_STATUS 0x5646 /* 0x00005646 */ +#define LINUX_VIDIOC_G_EXT_CTRLS 0x5647 /* 0xc0185647 */ +#define LINUX_VIDIOC_S_EXT_CTRLS 0x5648 /* 0xc0185648 */ +#define LINUX_VIDIOC_TRY_EXT_CTRLS 0x5649 /* 0xc0185649 */ +#define LINUX_VIDIOC_ENUM_FRAMESIZES 0x564a /* 0xc02c564a */ +#define LINUX_VIDIOC_ENUM_FRAMEINTERVALS 0x564b /* 0xc034564b */ +#define LINUX_VIDIOC_G_ENC_INDEX 0x564c /* 0x8818564c */ +#define LINUX_VIDIOC_ENCODER_CMD 0x564d /* 0xc028564d */ +#define LINUX_VIDIOC_TRY_ENCODER_CMD 0x564e /* 0xc028564e */ +#define LINUX_VIDIOC_DBG_S_REGISTER 0x564f /* 0x4038564f */ +#define LINUX_VIDIOC_DBG_G_REGISTER 0x5650 /* 0xc0385650 */ +#define LINUX_VIDIOC_DBG_G_CHIP_IDENT 0x5651 /* 0xc02c5651 */ +#define LINUX_VIDIOC_S_HW_FREQ_SEEK 0x5652 /* 0x40305652 */ +#define LINUX_VIDIOC_ENUM_DV_PRESETS 0x5653 /* 0xc0405653 */ +#define LINUX_VIDIOC_S_DV_PRESET 0x5654 /* 0xc0145654 */ +#define LINUX_VIDIOC_G_DV_PRESET 0x5655 /* 0xc0145655 */ +#define LINUX_VIDIOC_QUERY_DV_PRESET 0x5656 /* 0x80145656 */ +#define LINUX_VIDIOC_S_DV_TIMINGS 0x5657 /* 0xc0845657 */ +#define LINUX_VIDIOC_G_DV_TIMINGS 0x5658 /* 0xc0845658 */ +#define LINUX_VIDIOC_DQEVENT 0x5659 /* 0x80785659 */ +#define LINUX_VIDIOC_SUBSCRIBE_EVENT 0x565a /* 0x4020565a */ +#define LINUX_VIDIOC_UNSUBSCRIBE_EVENT 0x565b /* 0x4020565b */ + +#define LINUX_VIDIOC_OVERLAY_OLD 0x560e /* 0xc004560e */ +#define LINUX_VIDIOC_S_PARM_OLD 0x5616 /* 0x40cc5616 */ +#define LINUX_VIDIOC_S_CTRL_OLD 0x561c /* 0x4008561c */ +#define LINUX_VIDIOC_G_AUDIO_OLD 0x5621 /* 0xc0345621 */ +#define LINUX_VIDIOC_G_AUDOUT_OLD 0x5631 /* 0xc0345631 */ +#define LINUX_VIDIOC_CROPCAP_OLD 0x563a /* 0x802c563a */ + +#define LINUX_IOCTL_VIDEO2_MIN LINUX_VIDIOC_QUERYCAP +#define LINUX_IOCTL_VIDEO2_MAX LINUX_VIDIOC_UNSUBSCRIBE_EVENT + /* * Our libusb(8) calls emulated within linux(4). */ |