summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2008-08-24 11:05:04 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2008-08-24 11:05:04 +0000
commit87a33c84f9a6065aeb32f7da558713c2c03b2b3c (patch)
tree2320732678c58fa0481c22ec3db85a40368b5543
parentee8d4e669568f6dcabfef781c67fab673763fd08 (diff)
Add support for processing unit (e.g. brightness) controls. New V4L2
ioctls therefore are VIDIOC_QUERYCTRL, VIDIOC_G_CTRL, and VIDIOC_S_CTRL.
-rw-r--r--sys/dev/usb/uvideo.c263
-rw-r--r--sys/dev/usb/uvideo.h81
-rw-r--r--sys/dev/video.c12
-rw-r--r--sys/dev/video_if.h4
4 files changed, 354 insertions, 6 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index 9766bbce15f..ed252c54c21 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.82 2008/08/16 18:56:07 mglocker Exp $ */
+/* $OpenBSD: uvideo.c,v 1.83 2008/08/24 11:05:02 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -68,7 +68,15 @@ int uvideo_activate(struct device *, enum devact);
usbd_status uvideo_vc_parse_desc(struct uvideo_softc *);
usbd_status uvideo_vc_parse_desc_header(struct uvideo_softc *,
+ const usb_descriptor_t *);
+usbd_status uvideo_vc_parse_desc_pu(struct uvideo_softc *,
const usb_descriptor_t *);
+usbd_status uvideo_vc_get_ctrl(struct uvideo_softc *, uint8_t *, uint8_t,
+ uint8_t, uint16_t, uint16_t);
+usbd_status uvideo_vc_set_ctrl(struct uvideo_softc *, uint8_t *, uint8_t,
+ uint8_t, uint16_t, uint16_t);
+int uvideo_find_ctrl(struct uvideo_softc *, int);
+
usbd_status uvideo_vs_parse_desc(struct uvideo_softc *,
struct usb_attach_arg *, usb_config_descriptor_t *);
usbd_status uvideo_vs_parse_desc_input_header(struct uvideo_softc *,
@@ -137,6 +145,8 @@ void uvideo_dump_desc_format_uncompressed(struct uvideo_softc *,
const usb_descriptor_t *);
void uvideo_dump_desc_frame_uncompressed(struct uvideo_softc *,
const usb_descriptor_t *);
+void uvideo_dump_desc_processing(struct uvideo_softc *,
+ const usb_descriptor_t *);
void uvideo_dump_desc_extension(struct uvideo_softc *,
const usb_descriptor_t *);
void uvideo_hexdump(void *, int, int);
@@ -162,6 +172,9 @@ int uvideo_dqbuf(void *, struct v4l2_buffer *);
int uvideo_streamon(void *, int);
int uvideo_streamoff(void *, int);
int uvideo_try_fmt(void *, struct v4l2_format *);
+int uvideo_queryctrl(void *, struct v4l2_queryctrl *);
+int uvideo_g_ctrl(void *, struct v4l2_control *);
+int uvideo_s_ctrl(void *, struct v4l2_control *);
/*
* Other hardware interface related functions
@@ -200,7 +213,9 @@ struct video_hw_if uvideo_hw_if = {
uvideo_streamon, /* VIDIOC_STREAMON */
uvideo_streamoff, /* VIDIOC_STREAMOFF */
uvideo_try_fmt, /* VIDIOC_TRY_FMT */
- NULL, /* VIDIOC_QUERYCTRL */
+ uvideo_queryctrl, /* VIDIOC_QUERYCTRL */
+ uvideo_g_ctrl, /* VIDIOC_G_CTRL */
+ uvideo_s_ctrl, /* VIDIOC_S_CTRL */
uvideo_mappage, /* mmap */
uvideo_get_bufsize, /* read */
uvideo_start_read /* start stream for read */
@@ -443,6 +458,12 @@ uvideo_vc_parse_desc(struct uvideo_softc *sc)
return (error);
vc_header_found = 1;
break;
+ case UDESCSUB_VC_PROCESSING_UNIT:
+ /* XXX do correct length calculation */
+ if (desc->bLength < 25) {
+ (void)uvideo_vc_parse_desc_pu(sc, desc);
+ }
+ break;
/* TODO: which VC descriptors do we need else? */
}
@@ -479,6 +500,121 @@ uvideo_vc_parse_desc_header(struct uvideo_softc *sc,
}
usbd_status
+uvideo_vc_parse_desc_pu(struct uvideo_softc *sc,
+ const usb_descriptor_t *desc)
+{
+ struct usb_video_vc_processing_desc *d;
+
+ d = (struct usb_video_vc_processing_desc *)(uint8_t *)desc;
+
+ if (sc->sc_desc_vc_pu_num == UVIDEO_MAX_PU) {
+ printf("%s: too many PU descriptors found!\n", DEVNAME(sc));
+ return (USBD_INVAL);
+ }
+
+ /* XXX support variable bmControls fields */
+ if (d->bControlSize != 2) {
+ printf("%s: just 2 bytes bmControls supported yet!\n",
+ DEVNAME(sc));
+ return (USBD_INVAL);
+ }
+
+ sc->sc_desc_vc_pu[sc->sc_desc_vc_pu_num] = d;
+ sc->sc_desc_vc_pu_num++;
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+uvideo_vc_get_ctrl(struct uvideo_softc *sc, uint8_t *ctrl_data,
+ uint8_t request, uint8_t unitid, uint16_t ctrl_selector, uint16_t ctrl_len)
+{
+ usb_device_request_t req;
+ usbd_status error;
+
+ req.bmRequestType = UVIDEO_GET_IF;
+ req.bRequest = request;
+ USETW(req.wValue, (ctrl_selector << 8));
+ USETW(req.wIndex, (unitid << 8));
+ USETW(req.wLength, ctrl_len);
+
+ error = usbd_do_request(sc->sc_udev, &req, ctrl_data);
+ if (error) {
+ DPRINTF(1, "%s: %s: could not GET ctrl request: %s\n",
+ DEVNAME(sc), __func__, usbd_errstr(error));
+ return (USBD_INVAL);
+ }
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+uvideo_vc_set_ctrl(struct uvideo_softc *sc, uint8_t *ctrl_data,
+ uint8_t request, uint8_t unitid, uint16_t ctrl_selector, uint16_t ctrl_len)
+{
+ usb_device_request_t req;
+ usbd_status error;
+
+ req.bmRequestType = UVIDEO_SET_IF;
+ req.bRequest = request;
+ USETW(req.wValue, (ctrl_selector << 8));
+ USETW(req.wIndex, (unitid << 8));
+ USETW(req.wLength, ctrl_len);
+
+ error = usbd_do_request(sc->sc_udev, &req, ctrl_data);
+ if (error) {
+ DPRINTF(1, "%s: %s: could not SET ctrl request: %s\n",
+ DEVNAME(sc), __func__, usbd_errstr(error));
+ return (USBD_INVAL);
+ }
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+int
+uvideo_find_ctrl(struct uvideo_softc *sc, int id)
+{
+ int i, j, found;
+
+ if (sc->sc_desc_vc_pu_num == 0) {
+ /* no processing unit descriptors found */
+ DPRINTF(1, "%s: %s: no processing unit descriptors found!\n",
+ DEVNAME(sc), __func__);
+ return (EINVAL);
+ }
+
+ /* do we support this control? */
+ for (found = 0, i = 0; uvideo_ctrls[i].cid != 0; i++) {
+ if (id == uvideo_ctrls[i].cid) {
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0) {
+ DPRINTF(1, "%s: %s: control not supported by driver!\n",
+ DEVNAME(sc), __func__);
+ return (EINVAL);
+ }
+
+ /* does the device support this control? */
+ for (found = 0, j = 0; i < sc->sc_desc_vc_pu_num; j++) {
+ if (UGETW(sc->sc_desc_vc_pu[j]->bmControls) &
+ uvideo_ctrls[i].ctrl_bitmap) {
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0) {
+ DPRINTF(1, "%s: %s: control not supported by device!\n",
+ DEVNAME(sc), __func__);
+ return (EINVAL);
+ }
+ sc->sc_desc_vc_pu_cur = sc->sc_desc_vc_pu[j];
+
+ return (i);
+}
+
+usbd_status
uvideo_vs_parse_desc(struct uvideo_softc *sc, struct usb_attach_arg *uaa,
usb_config_descriptor_t *cdesc)
{
@@ -1647,7 +1783,8 @@ uvideo_dump_desc_all(struct uvideo_softc *sc)
} else {
printf(" (UDESCSUB_VC_PROCESSING_"
"UNIT)\n");
- /* TODO */
+ printf("|\n");
+ uvideo_dump_desc_processing(sc, desc);
}
break;
case UDESCSUB_VC_EXTENSION_UNIT:
@@ -2000,6 +2137,26 @@ uvideo_dump_desc_format_uncompressed(struct uvideo_softc *sc,
}
void
+uvideo_dump_desc_processing(struct uvideo_softc *sc,
+ const usb_descriptor_t *desc)
+{
+ struct usb_video_vc_processing_desc *d;
+
+ d = (struct usb_video_vc_processing_desc *)(uint8_t *)desc;
+
+ printf("bLength=%d\n", d->bLength);
+ printf("bDescriptorType=0x%02x\n", d->bDescriptorType);
+ printf("bDescriptorSubtype=0x%02x\n", d->bDescriptorSubtype);
+ printf("bUnitID=0x%02x\n", d->bUnitID);
+ printf("bSourceID=0x%02x\n", d->bSourceID);
+ printf("wMaxMultiplier=%d\n", UGETW(d->wMaxMultiplier));
+ printf("bControlSize=%d\n", d->bControlSize);
+ printf("bmControls=0x%02x\n", UGETW(d->bmControls));
+ printf("iProcessing=0x%02x\n", d->iProcessing);
+ printf("bmVideoStandards=0x%02x\n", d->bmVideoStandards);
+}
+
+void
uvideo_dump_desc_extension(struct uvideo_softc *sc,
const usb_descriptor_t *desc)
{
@@ -2461,6 +2618,106 @@ uvideo_streamoff(void *v, int type)
}
int
+uvideo_queryctrl(void *v, struct v4l2_queryctrl *qctrl)
+{
+ struct uvideo_softc *sc = v;
+ int i;
+ usbd_status error;
+ uint8_t ctrl_data[2];
+
+ i = uvideo_find_ctrl(sc, qctrl->id);
+ if (i == EINVAL)
+ return (i);
+
+ /* set type */
+ qctrl->type = uvideo_ctrls[i].type;
+
+ /* set description name */
+ strlcpy(qctrl->name, uvideo_ctrls[i].name, sizeof(qctrl->name));
+
+ /* set minimum */
+ error = uvideo_vc_get_ctrl(sc, ctrl_data, GET_MIN,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+ qctrl->minimum = letoh16(*(uint16_t *)ctrl_data);
+
+ /* set maximum */
+ error = uvideo_vc_get_ctrl(sc, ctrl_data, GET_MAX,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+ qctrl->maximum = letoh16(*(uint16_t *)ctrl_data);
+
+ /* set resolution */
+ error = uvideo_vc_get_ctrl(sc, ctrl_data, GET_RES,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+ qctrl->step = letoh16(*(uint16_t *)ctrl_data);
+
+ /* set default */
+ error = uvideo_vc_get_ctrl(sc, ctrl_data, GET_DEF,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+ qctrl->default_value = letoh16(*(uint16_t *)ctrl_data);
+
+ /* set flags */
+ qctrl->flags = 0;
+
+ return (0);
+}
+
+int
+uvideo_g_ctrl(void *v, struct v4l2_control *gctrl)
+{
+ struct uvideo_softc *sc = v;
+ int i;
+ usbd_status error;
+ uint8_t ctrl_data[2];
+
+ i = uvideo_find_ctrl(sc, gctrl->id);
+ if (i == EINVAL)
+ return (i);
+
+ error = uvideo_vc_get_ctrl(sc, ctrl_data, GET_CUR,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+ gctrl->value = letoh16(*(uint16_t *)ctrl_data);
+
+ return (0);
+}
+
+int
+uvideo_s_ctrl(void *v, struct v4l2_control *sctrl)
+{
+ struct uvideo_softc *sc = v;
+ int i;
+ usbd_status error;
+ uint8_t ctrl_data[2];
+
+ i = uvideo_find_ctrl(sc, sctrl->id);
+ if (i == EINVAL)
+ return (i);
+
+ *(uint16_t *)ctrl_data = htole16(sctrl->value);
+ error = uvideo_vc_set_ctrl(sc, ctrl_data, SET_CUR,
+ sc->sc_desc_vc_pu_cur->bUnitID,
+ uvideo_ctrls[i].ctrl_selector, uvideo_ctrls[i].ctrl_len);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (EINVAL);
+
+ return (0);
+}
+
+int
uvideo_try_fmt(void *v, struct v4l2_format *fmt)
{
struct uvideo_softc *sc = v;
diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h
index 0132e82150e..0fead8a5781 100644
--- a/sys/dev/usb/uvideo.h
+++ b/sys/dev/usb/uvideo.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.h,v 1.27 2008/08/02 21:52:37 mglocker Exp $ */
+/* $OpenBSD: uvideo.h,v 1.28 2008/08/24 11:05:03 mglocker Exp $ */
/*
* Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
@@ -208,6 +208,20 @@ struct usb_video_camera_terminal_desc {
uByte *bmControls;
};
+/* Table 3-8: VC Processing Unit Descriptor */
+struct usb_video_vc_processing_desc {
+ uByte bLength;
+ uByte bDescriptorType;
+ uByte bDescriptorSubtype;
+ uByte bUnitID;
+ uByte bSourceID;
+ uWord wMaxMultiplier;
+ uByte bControlSize;
+ uWord bmControls; /* XXX must be variable size of bControlSize */
+ uByte iProcessing;
+ uByte bmVideoStandards;
+} __packed;
+
/* Table 3-9: VC Extension Unit Descriptor */
struct usb_video_vc_extension_desc {
uByte bLength;
@@ -453,6 +467,66 @@ struct uvideo_res {
int fidx;
} __packed;
+struct uvideo_controls {
+ int cid;
+ int type;
+ char name[32];
+ uint16_t ctrl_bitmap;
+ uint16_t ctrl_selector;
+ uint16_t ctrl_len;
+} uvideo_ctrls[] = {
+ /* TODO complete control list */
+ {
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Brightness",
+ (1 << 0),
+ PU_BRIGHTNESS_CONTROL,
+ 2
+ },
+ {
+ V4L2_CID_CONTRAST,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Contrast",
+ (1 << 1),
+ PU_CONTRAST_CONTROL,
+ 2
+ },
+ {
+ V4L2_CID_HUE,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Hue",
+ (1 << 2),
+ PU_HUE_CONTROL,
+ 2
+ },
+ {
+ V4L2_CID_SATURATION,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Saturation",
+ (1 << 3),
+ PU_SATURATION_CONTROL,
+ 2
+ },
+ {
+ V4L2_CID_GAMMA,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Gamma",
+ (1 << 5),
+ PU_GAMMA_CONTROL,
+ 2
+ },
+ {
+ V4L2_CID_GAIN,
+ V4L2_CTRL_TYPE_INTEGER,
+ "Gain",
+ (1 << 9),
+ PU_GAIN_CONTROL,
+ 2,
+ },
+ { 0, 0, "", 0, 0, 0 }
+};
+
struct uvideo_softc {
struct device sc_dev;
usbd_device_handle sc_udev;
@@ -500,6 +574,11 @@ struct uvideo_softc {
struct usb_video_header_desc_all sc_desc_vc_header;
struct usb_video_input_header_desc_all sc_desc_vs_input_header;
+#define UVIDEO_MAX_PU 8
+ int sc_desc_vc_pu_num;
+ struct usb_video_vc_processing_desc *sc_desc_vc_pu_cur;
+ struct usb_video_vc_processing_desc *sc_desc_vc_pu[UVIDEO_MAX_PU];
+
#define UVIDEO_MAX_FORMAT 8
int sc_fmtgrp_idx;
int sc_fmtgrp_num;
diff --git a/sys/dev/video.c b/sys/dev/video.c
index 0f8e3cc2414..61067d2df06 100644
--- a/sys/dev/video.c
+++ b/sys/dev/video.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: video.c,v 1.21 2008/08/13 20:29:34 mglocker Exp $ */
+/* $OpenBSD: video.c,v 1.22 2008/08/24 11:05:02 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
* Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
@@ -271,6 +271,16 @@ videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
error = (sc->hw_if->queryctrl)(sc->hw_hdl,
(struct v4l2_queryctrl *)data);
break;
+ case VIDIOC_G_CTRL:
+ if (sc->hw_if->g_ctrl)
+ error = (sc->hw_if->g_ctrl)(sc->hw_hdl,
+ (struct v4l2_control *)data);
+ break;
+ case VIDIOC_S_CTRL:
+ if (sc->hw_if->s_ctrl)
+ error = (sc->hw_if->s_ctrl)(sc->hw_hdl,
+ (struct v4l2_control *)data);
+ break;
default:
error = (ENOTTY);
}
diff --git a/sys/dev/video_if.h b/sys/dev/video_if.h
index ea8836aa61a..bef02d9e1ae 100644
--- a/sys/dev/video_if.h
+++ b/sys/dev/video_if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: video_if.h,v 1.15 2008/08/13 20:29:34 mglocker Exp $ */
+/* $OpenBSD: video_if.h,v 1.16 2008/08/24 11:05:02 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
* Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
@@ -50,6 +50,8 @@ struct video_hw_if {
int (*streamoff)(void *, int);
int (*try_fmt)(void *, struct v4l2_format *);
int (*queryctrl)(void *, struct v4l2_queryctrl *);
+ int (*g_ctrl)(void *, struct v4l2_control *);
+ int (*s_ctrl)(void *, struct v4l2_control *);
caddr_t (*mappage)(void *, off_t, int);
/* other functions */