summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2008-04-16 12:19:12 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2008-04-16 12:19:12 +0000
commit9d1654827a4dd0ac617386996890012f1ac16696 (patch)
tree4a6baff7e5eef6b215d0310eda78ddb47a64548d /sys/dev/usb
parent2afe337cd746b0bac06dafbca60ee0005b7d1d4b (diff)
Start to make device initialization automatic instead all the static
games. Tested by robert@ and myself
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/uvideo.c647
-rw-r--r--sys/dev/usb/uvideo.h85
2 files changed, 549 insertions, 183 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index 20fbc8fffc0..40407cd37c2 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.5 2008/04/12 10:09:12 mglocker Exp $ */
+/* $OpenBSD: uvideo.c,v 1.6 2008/04/16 12:19:11 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -46,7 +46,7 @@
#define UVIDEO_DEBUG
#ifdef UVIDEO_DEBUG
-int uvideo_debug = 1;
+int uvideo_debug = 2;
#define DPRINTF(l, x...) do { if ((l) <= uvideo_debug) printf(x); } while (0)
#else
#define DPRINTF(l, x...)
@@ -58,16 +58,36 @@ void uvideo_disable(void *);
int uvideo_open(void *, int);
int uvideo_close(void *);
-int uvideo_find_vs_if(struct uvideo_softc *,
+int uvideo_vc_parse_desc(struct uvideo_softc *);
+int uvideo_vc_parse_desc_header(struct uvideo_softc *,
+ const usb_descriptor_t *);
+
+int uvideo_vs_parse_desc(struct uvideo_softc *,
struct usb_attach_arg *, usb_config_descriptor_t *);
+int uvideo_vs_parse_desc_alt(struct uvideo_softc *,
+ struct usb_attach_arg *uaa, int, int, int);
+
+
+int uvideo_vs_set_alt(struct uvideo_softc *,
+ struct usb_attach_arg *, int, int);
+int uvideo_vs_parse_format_desc(struct uvideo_softc *);
+int uvideo_vs_parse_format_desc_mjpeg(struct uvideo_softc *,
+ const usb_descriptor_t *);
+
+int uvideo_vs_parse_frame_desc(struct uvideo_softc *);
+int uvideo_vs_parse_frame_desc_mjpeg(struct uvideo_softc *,
+ const usb_descriptor_t *);
+
+usbd_status uvideo_vs_alloc_sample(struct uvideo_softc *);
usbd_status uvideo_vs_alloc(struct uvideo_softc *);
-usbd_status uvideo_vs_open(struct uvideo_softc *);
+usbd_status uvideo_vs_open(struct uvideo_softc *, struct usb_attach_arg *);
void uvideo_vs_start(struct uvideo_softc *);
void uvideo_vs_cb(usbd_xfer_handle, usbd_private_handle,
usbd_status);
-int uvideo_vs_set_probe(struct uvideo_softc *, uint8_t *);
-int uvideo_vs_get_probe(struct uvideo_softc *, uint8_t *);
-int uvideo_vs_set_probe_commit(struct uvideo_softc *, uint8_t *);
+usbd_status uvideo_vs_negotation(struct uvideo_softc *);
+usbd_status uvideo_vs_set_probe(struct uvideo_softc *, uint8_t *);
+usbd_status uvideo_vs_get_probe(struct uvideo_softc *, uint8_t *);
+usbd_status uvideo_vs_set_commit(struct uvideo_softc *, uint8_t *);
int uvideo_vs_decode_stream_header(struct uvideo_softc *,
uint8_t *, int);
@@ -94,6 +114,8 @@ void uvideo_dump_desc_frame_mjpeg(struct uvideo_softc *,
void uvideo_dump_desc_format_mjpeg(struct uvideo_softc *,
const usb_descriptor_t *);
+int uvideo_desc_len(int, int, int);
+
int uvideo_debug_file_open(struct uvideo_softc *);
void uvideo_debug_file_write_sample(void *);
@@ -166,9 +188,7 @@ uvideo_attach(struct device * parent, struct device * self, void *aux)
struct uvideo_softc *sc = (struct uvideo_softc *) self;
struct usb_attach_arg *uaa = aux;
usb_config_descriptor_t *cdesc;
- usbd_status err;
- uint8_t probe_data[34];
- struct uvideo_sample_buffer *fb = &sc->sc_sample_buffer;
+ usbd_status error;
sc->sc_udev = uaa->device;
@@ -179,33 +199,53 @@ uvideo_attach(struct device * parent, struct device * self, void *aux)
DEVNAME(sc));
return;
}
-
+#ifdef UVIDEO_DEBUG
uvideo_dump_desc_all(sc);
+#endif
+ /* parse video control descriptors */
+ error = uvideo_vc_parse_desc(sc);
+ if (error != USBD_NORMAL_COMPLETION)
+ return;
- bzero(probe_data, sizeof(probe_data));
- if (uvideo_vs_set_probe(sc, probe_data))
+ /* parse video stream format descriptors */
+ error = uvideo_vs_parse_format_desc(sc);
+ if (error != USBD_NORMAL_COMPLETION)
return;
- bzero(probe_data, sizeof(probe_data));
- if (uvideo_vs_get_probe(sc, probe_data))
+
+ /* parse video stream frame descriptors */
+ error = uvideo_vs_parse_frame_desc(sc);
+ if (error != USBD_NORMAL_COMPLETION)
return;
- if (uvideo_vs_set_probe_commit(sc, probe_data))
+
+ /* parse video stream descriptors */
+ error = uvideo_vs_parse_desc(sc, uaa, cdesc);
+ if (error != USBD_NORMAL_COMPLETION)
return;
- uvideo_find_vs_if(sc, uaa, cdesc);
+ /* do device negotation */
+ error = uvideo_vs_negotation(sc);
+ if (error != USBD_NORMAL_COMPLETION)
+ return;
- err = uvideo_vs_alloc(sc);
- if (err != USBD_NORMAL_COMPLETION)
+ /* open video stream pipe */
+ error = uvideo_vs_open(sc, uaa);
+ if (error != USBD_NORMAL_COMPLETION)
return;
- err = uvideo_vs_open(sc);
- if (err != USBD_NORMAL_COMPLETION)
+ /* allocate video stream xfer buffer */
+ error = uvideo_vs_alloc(sc);
+ if (error != USBD_NORMAL_COMPLETION)
return;
- fb->buf = malloc(32000, M_TEMP, M_NOWAIT);
+ /* allocate video stream sample buffer */
+ error = uvideo_vs_alloc_sample(sc);
+ if (error != USBD_NORMAL_COMPLETION)
+ return;
+#ifdef UVIDEO_DEBUG
uvideo_debug_file_open(sc);
usb_init_task(&sc->sc_task_write, uvideo_debug_file_write_sample, sc);
-
+#endif
uvideo_vs_start(sc);
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, &sc->sc_dev);
@@ -299,175 +339,451 @@ uvideo_open(void *addr, int flags)
int
uvideo_close(void *addr)
{
+#if 0
struct uvideo_softc *sc = addr;
DPRINTF(1, "uvideo_close: sc=%p\n", sc);
+#endif
+
+ return (0);
+}
+
+int
+uvideo_vc_parse_desc(struct uvideo_softc *sc)
+{
+ usbd_desc_iter_t iter;
+ const usb_descriptor_t *desc;
+ int vc_header_found;
+
+ vc_header_found = 0;
+
+ usb_desc_iter_init(sc->sc_udev, &iter);
+ desc = usb_desc_iter_next(&iter);
+ while (desc) {
+ if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
+ desc = usb_desc_iter_next(&iter);
+ continue;
+ }
+
+ switch (desc->bDescriptorSubtype) {
+ case UDESCSUB_VC_HEADER:
+ /* XXX length can vary, do better calculation */
+ if (desc->bLength != 13)
+ break;
+ if (vc_header_found) {
+ printf("%s: too many VC_HEADERs!\n",
+ DEVNAME(sc));
+ return (-1);
+ }
+ if (uvideo_vc_parse_desc_header(sc, desc) != 0)
+ return (-1);
+ vc_header_found = 1;
+ break;
+
+ /* TODO which VC descriptors do we need else? */
+ }
+
+ desc = usb_desc_iter_next(&iter);
+ }
+
+ if (vc_header_found == 0) {
+ printf("%s: no VC_HEADER found!\n", DEVNAME(sc));
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+uvideo_vc_parse_desc_header(struct uvideo_softc *sc,
+ const usb_descriptor_t *desc)
+{
+ struct usb_video_header_desc *d;
+
+ d = (struct usb_video_header_desc *)(uint8_t *)desc;
+
+ if (d->bInCollection == 0) {
+ printf("%s: no VS interface found!\n",
+ DEVNAME(sc));
+ return (-1);
+ }
+
+ sc->sc_desc_vc_header.fix = d;
+ sc->sc_desc_vc_header.baInterfaceNr = (uByte *)(d + 1);
return (0);
}
int
-uvideo_find_vs_if(struct uvideo_softc *sc, struct usb_attach_arg *uaa,
+uvideo_vs_parse_desc(struct uvideo_softc *sc, struct usb_attach_arg *uaa,
usb_config_descriptor_t *cdesc)
{
- struct uvideo_stream_if *si = &sc->sc_curr_strm;
+ usb_interface_descriptor_t *id;
+ int i, iface, numalts;
+
+ DPRINTF(1, "%s: number of total interfaces=%d\n",
+ DEVNAME(sc), uaa->nifaces);
+ DPRINTF(1, "%s: number of VS interfaces=%d\n",
+ DEVNAME(sc), sc->sc_desc_vc_header.fix->bInCollection);
+
+ /* parse interface collection */
+ for (i = 0; i < sc->sc_desc_vc_header.fix->bInCollection; i++) {
+ iface = sc->sc_desc_vc_header.baInterfaceNr[i];
+
+ id = usbd_get_interface_descriptor(uaa->ifaces[iface]);
+ if (id == NULL) {
+ printf("%s: can't get VS interface %d!\n",
+ DEVNAME(sc), iface);
+ return (USBD_INVAL);
+ }
+
+ numalts = usbd_get_no_alts(cdesc, id->bInterfaceNumber);
+
+ DPRINTF(1, "%s: VS interface %d, ", DEVNAME(sc), i);
+ DPRINTF(1, "bInterfaceNumber=0x%02x, numalts=%d\n",
+ id->bInterfaceNumber, numalts);
+
+ uvideo_vs_parse_desc_alt(sc, uaa, i, iface, numalts);
+ }
+
+ /* XXX for now always use the first video stream */
+ sc->sc_vs_curr = &sc->sc_vs_coll[0];
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+int
+uvideo_vs_parse_desc_alt(struct uvideo_softc *sc, struct usb_attach_arg *uaa,
+ int vs_nr, int iface, int numalts)
+{
+ struct uvideo_vs_iface *vs;
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
- int i, numalts;
+ int i;
+ usbd_status error;
- printf("%s: nifaces=%d\n", DEVNAME(sc), uaa->nifaces);
+ vs = &sc->sc_vs_coll[vs_nr];
- for (i = 0; i < uaa->nifaces; i++) {
- if (uaa->ifaces[i] == NULL)
- continue;
+ for (i = 0; i < numalts; i++) {
+ error = usbd_set_interface(uaa->ifaces[iface], i);
+ if (error) {
+ printf("%s: could not set alternate interface %d!\n",
+ DEVNAME(sc), i);
+ return (USBD_INVAL);
+ }
- id = usbd_get_interface_descriptor(uaa->ifaces[i]);
+ id = usbd_get_interface_descriptor(uaa->ifaces[iface]);
if (id == NULL)
continue;
- printf("%s: bInterfaceNumber=%d, bAlternateSetting=%d, ",
- DEVNAME(sc),
- id->bInterfaceNumber, id->bAlternateSetting);
-
- numalts = usbd_get_no_alts(cdesc, id->bInterfaceNumber);
- printf("numalts=%d\n", numalts);
- if (id->bInterfaceNumber == 1) { /* XXX baInterfaceNr */
- si->in_ifaceh = uaa->ifaces[i];
- si->numalts = numalts;
- }
+ DPRINTF(1, "%s: bAlternateSetting=0x%02x, ",
+ DEVNAME(sc), id->bAlternateSetting);
- ed = usbd_interface2endpoint_descriptor(uaa->ifaces[i], i);
+ ed = usbd_interface2endpoint_descriptor(uaa->ifaces[iface], 0);
if (ed == NULL) {
- printf("%s: no endpoint descriptor for iface %d\n",
- DEVNAME(sc), i);
+ DPRINTF(1, "no endpoint descriptor\n");
continue;
}
- printf("%s: bEndpointAddress=0x%02x\n",
- DEVNAME(sc), ed->bEndpointAddress);
+
+ DPRINTF(1, "bEndpointAddress=0x%02x, ", ed->bEndpointAddress);
+ DPRINTF(1, "wMaxPacketSize=%d\n", UGETW(ed->wMaxPacketSize));
+
+ if (UGETW(ed->wMaxPacketSize) > vs->max_packet_size) {
+ vs->ifaceh = uaa->ifaces[iface];
+ vs->endpoint = ed->bEndpointAddress;
+ vs->numalts = numalts;
+ vs->curalt = id->bAlternateSetting;
+ vs->max_packet_size = UGETW(ed->wMaxPacketSize);
+ vs->iface = iface;
+ }
+ }
+
+ /* set back first alternate, otherwise negotation can fail */
+ error = usbd_set_interface(uaa->ifaces[iface], 0);
+ if (error) {
+ printf("%s: could not set alternate interface 0!\n",
+ DEVNAME(sc));
+ return (USBD_INVAL);
}
- for (i = 0; i < si->numalts; i++) {
- if (usbd_set_interface(si->in_ifaceh, i)) {
- printf("%s: could not set alt iface %d\n",
+ return (USBD_NORMAL_COMPLETION);
+}
+
+int
+uvideo_vs_set_alt(struct uvideo_softc *sc, struct usb_attach_arg *uaa,
+ int iface, int max_packet_size)
+{
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ int i;
+ usbd_status error;
+
+ for (i = 0; i < sc->sc_vs_curr->numalts; i++) {
+ error = usbd_set_interface(uaa->ifaces[iface], i);
+ if (error) {
+ printf("%s: could not set alternate interface %d!\n",
DEVNAME(sc), i);
- return (1);
+ return (USBD_INVAL);
}
- ed = usbd_interface2endpoint_descriptor(si->in_ifaceh, 0);
- if (ed == NULL) {
- printf("%s: no endpoint descriptor for VS iface\n",
- DEVNAME(sc));
+ id = usbd_get_interface_descriptor(uaa->ifaces[iface]);
+ if (id == NULL)
continue;
+
+ ed = usbd_interface2endpoint_descriptor(uaa->ifaces[iface], 0);
+ if (ed == NULL)
+ continue;
+
+ if (UGETW(ed->wMaxPacketSize) == max_packet_size) {
+ sc->sc_vs_curr->endpoint = ed->bEndpointAddress;
+ sc->sc_vs_curr->curalt = id->bAlternateSetting;
+ sc->sc_vs_curr->max_packet_size =
+ UGETW(ed->wMaxPacketSize);
+
+ DPRINTF(1, "%s: set alternate iface to ", DEVNAME(sc));
+ DPRINTF(1, "bAlternateSetting=0x%02x\n",
+ id->bAlternateSetting);
+
+ return (USBD_NORMAL_COMPLETION);
}
- printf("%s: VS iface alt iface bEndpointAddress=0x%02x, "
- "wMaxPacketSize=%d\n",
- DEVNAME(sc),
- ed->bEndpointAddress,
- UGETW(ed->wMaxPacketSize));
+ }
+
+ return (USBD_INVAL);
+}
+
+int
+uvideo_vs_parse_format_desc(struct uvideo_softc *sc)
+{
+ usbd_desc_iter_t iter;
+ const usb_descriptor_t *desc;
+
+ DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
- si->endpoint = ed->bEndpointAddress;
+ usb_desc_iter_init(sc->sc_udev, &iter);
+ desc = usb_desc_iter_next(&iter);
+ while (desc) {
+ if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
+ desc = usb_desc_iter_next(&iter);
+ continue;
+ }
+
+ switch (desc->bDescriptorSubtype) {
+ case UDESCSUB_VS_FORMAT_MJPEG:
+ if (desc->bLength == 11) {
+ uvideo_vs_parse_format_desc_mjpeg(sc, desc);
+ }
+ break;
+ }
+
+ desc = usb_desc_iter_next(&iter);
}
return (0);
}
+int
+uvideo_vs_parse_format_desc_mjpeg(struct uvideo_softc *sc,
+ const usb_descriptor_t *desc)
+{
+ struct usb_video_format_mjpeg_desc *d;
+
+ d = (struct usb_video_format_mjpeg_desc *)(uint8_t *)desc;
+
+ if (d->bNumFrameDescriptors == 0) {
+ printf("%s: no MJPEG frame descriptors found!\n",
+ DEVNAME(sc));
+ return (-1);
+ }
+
+ sc->sc_desc_format_mjpeg = d;
+
+ return (0);
+}
+
+int
+uvideo_vs_parse_frame_desc(struct uvideo_softc *sc)
+{
+ usbd_desc_iter_t iter;
+ const usb_descriptor_t *desc;
+
+ DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
+
+ usb_desc_iter_init(sc->sc_udev, &iter);
+ desc = usb_desc_iter_next(&iter);
+ while (desc) {
+ if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
+ desc = usb_desc_iter_next(&iter);
+ continue;
+ }
+
+ switch (desc->bDescriptorSubtype) {
+ case UDESCSUB_VS_FRAME_MJPEG:
+ if (uvideo_vs_parse_frame_desc_mjpeg(sc, desc) == 0)
+ return (0);
+ break;
+ }
+
+ desc = usb_desc_iter_next(&iter);
+ }
+
+ printf("%s: no default frame descriptor found!\n", DEVNAME(sc));
+
+ return (1);
+}
+
+int
+uvideo_vs_parse_frame_desc_mjpeg(struct uvideo_softc *sc,
+ const usb_descriptor_t *desc)
+{
+ struct usb_video_frame_mjpeg_desc *d;
+
+ d = (struct usb_video_frame_mjpeg_desc *)(uint8_t *)desc;
+
+ /* choose default frame index */
+ if (d->bFrameIndex != sc->sc_desc_format_mjpeg->bDefaultFrameIndex)
+ return (1);
+
+ sc->sc_desc_frame_mjpeg = d;
+
+ return (0);
+}
+
+usbd_status
+uvideo_vs_alloc_sample(struct uvideo_softc *sc)
+{
+ struct uvideo_sample_buffer *fb = &sc->sc_sample_buffer;
+
+ DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
+
+ fb->buf = malloc(32000, M_TEMP, M_NOWAIT); /* XXX find proper size */
+ if (fb->buf == NULL) {
+ printf("%s: can't allocate sample buffer!\n", DEVNAME(sc));
+ return (USBD_NOMEM);
+ }
+
+ fb->fragment = 0;
+ fb->fid = 0;
+ fb->offset = 0;
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
usbd_status
uvideo_vs_alloc(struct uvideo_softc *sc)
{
- struct uvideo_stream_if *si = &sc->sc_curr_strm;
+ int size;
DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
- si->sc = sc;
+ sc->sc_vs_curr->sc = sc;
- si->xfer = usbd_alloc_xfer(sc->sc_udev);
- if (si->xfer == NULL) {
- printf("%s: could not allocate VideoStream xfer!\n",
- DEVNAME(sc));
+ sc->sc_vs_curr->xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_vs_curr->xfer == NULL) {
+ printf("%s: could not allocate VS xfer!\n", DEVNAME(sc));
return (USBD_NOMEM);
}
- si->buf = usbd_alloc_buffer(si->xfer, 384 * UVIDEO_NFRAMES);
- if (si->buf == NULL) {
- printf("%s: could not allocate VideoStream buffer!\n",
- DEVNAME(sc));
+ size = sc->sc_vs_curr->max_packet_size * sc->sc_nframes;
+
+ sc->sc_vs_curr->buf = usbd_alloc_buffer(sc->sc_vs_curr->xfer, size);
+ if (sc->sc_vs_curr->buf == NULL) {
+ printf("%s: could not allocate VS buffer!\n", DEVNAME(sc));
return (USBD_NOMEM);
}
+ DPRINTF(1, "%s: allocated %d bytes VS xfer buffer\n",
+ DEVNAME(sc), size);
return (USBD_NORMAL_COMPLETION);
}
usbd_status
-uvideo_vs_open(struct uvideo_softc *sc)
+uvideo_vs_open(struct uvideo_softc *sc, struct usb_attach_arg *uaa)
{
- struct uvideo_stream_if *si = &sc->sc_curr_strm;
usb_endpoint_descriptor_t *ed;
- usbd_status err;
+ usbd_status error;
DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__);
-
- err = usbd_set_interface(si->in_ifaceh, 2);
- if (err != 0) {
+#if 0
+ error = usbd_set_interface(sc->sc_vs_curr->ifaceh,
+ sc->sc_vs_curr->curalt);
+ if (error != USBD_NORMAL_COMPLETION) {
+ printf("%s: could not set alternate interface!\n",
+ DEVNAME(sc));
+ return (error);
+ }
+#endif
+ error = uvideo_vs_set_alt(sc, uaa, sc->sc_vs_curr->iface,
+ UGETDW(sc->sc_desc_probe.dwMaxPayloadTransferSize));
+ if (error != USBD_NORMAL_COMPLETION) {
printf("%s: could not set alternate interface!\n",
DEVNAME(sc));
- return (err);
+ return (error);
}
- ed = usbd_interface2endpoint_descriptor(si->in_ifaceh, 0);
+ ed = usbd_interface2endpoint_descriptor(sc->sc_vs_curr->ifaceh, 0);
if (ed == NULL) {
printf("%s: no endpoint descriptor for VS iface\n",
DEVNAME(sc));
- return (USBD_NOMEM);
+ return (USBD_INVAL);
}
- printf("%s: open pipe for bEndpointAddress=0x%02x (0x%02x), "
- "wMaxPacketSize=%d\n",
- DEVNAME(sc),
+ DPRINTF(1, "%s: open pipe for ", DEVNAME(sc));
+ DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize=%d (%d)\n",
ed->bEndpointAddress,
- si->endpoint,
- UGETW(ed->wMaxPacketSize));
-
- err = usbd_open_pipe(si->in_ifaceh, si->endpoint, USBD_EXCLUSIVE_USE,
- &si->in_pipeh);
- if (err) {
+ sc->sc_vs_curr->endpoint,
+ UGETW(ed->wMaxPacketSize),
+ sc->sc_vs_curr->max_packet_size);
+
+ error = usbd_open_pipe(
+ sc->sc_vs_curr->ifaceh,
+ sc->sc_vs_curr->endpoint,
+ USBD_EXCLUSIVE_USE,
+ &sc->sc_vs_curr->pipeh);
+ if (error != USBD_NORMAL_COMPLETION) {
printf("%s: could not open VS pipe: %s\n",
- DEVNAME(sc), usbd_errstr(err));
- return (err);
+ DEVNAME(sc), usbd_errstr(error));
+ return (error);
}
+ /* calculate optimal isoc xfer size */
+ sc->sc_nframes = UVIDEO_SFRAMES_MAX / sc->sc_vs_curr->max_packet_size;
+ if (sc->sc_nframes > UVIDEO_NFRAMES_MAX)
+ sc->sc_nframes = UVIDEO_NFRAMES_MAX;
+ DPRINTF(1, "%s: nframes=%d\n", DEVNAME(sc), sc->sc_nframes);
+
return (USBD_NORMAL_COMPLETION);
}
void
uvideo_vs_start(struct uvideo_softc *sc)
{
- struct uvideo_stream_if *si = &sc->sc_curr_strm;
int i;
DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__);
- for (i = 0; i < UVIDEO_NFRAMES; i++)
- si->size[i] = 384;
+ for (i = 0; i < sc->sc_nframes; i++)
+ sc->sc_vs_curr->size[i] = sc->sc_vs_curr->max_packet_size;
- bzero(si->buf, 384 * UVIDEO_NFRAMES);
+ bzero(sc->sc_vs_curr->buf,
+ sc->sc_vs_curr->max_packet_size * sc->sc_nframes);
usbd_setup_isoc_xfer(
- si->xfer,
- si->in_pipeh,
- si,
- si->size,
- UVIDEO_NFRAMES,
+ sc->sc_vs_curr->xfer,
+ sc->sc_vs_curr->pipeh,
+ sc->sc_vs_curr,
+ sc->sc_vs_curr->size,
+ sc->sc_nframes,
USBD_NO_COPY | USBD_SHORT_XFER_OK,
uvideo_vs_cb);
- (void)usbd_transfer(si->xfer);
+ (void)usbd_transfer(sc->sc_vs_curr->xfer);
}
void
uvideo_vs_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
- struct uvideo_stream_if *sc_curr_strm = priv;
- struct uvideo_softc *sc = sc_curr_strm->sc;
+ struct uvideo_vs_iface *vs = priv;
+ struct uvideo_softc *sc = vs->sc;
int len, i, frame_size;
uint8_t *frame;
@@ -484,9 +800,9 @@ uvideo_vs_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
if (len == 0)
goto skip;
- for (i = 0; i < UVIDEO_NFRAMES; i++) {
- frame = sc_curr_strm->buf + (i * 384);
- frame_size = sc_curr_strm->size[i];
+ for (i = 0; i < sc->sc_nframes; i++) {
+ frame = vs->buf + (i * vs->max_packet_size);
+ frame_size = vs->size[i];
if (frame_size == 0)
/* frame is empty */
@@ -499,7 +815,44 @@ skip: /* setup new transfer */
uvideo_vs_start(sc);
}
-int
+usbd_status
+uvideo_vs_negotation(struct uvideo_softc *sc)
+{
+ struct usb_video_probe_commit *pc;
+ uint8_t probe_data[34];
+ usbd_status error;
+
+ /* set probe */
+ bzero(probe_data, sizeof(probe_data));
+ pc = (struct usb_video_probe_commit *)probe_data;
+#if 0
+ pc->bFormatIndex = 1;
+ pc->bFrameIndex = 1;
+#endif
+ pc->bFormatIndex = sc->sc_desc_format_mjpeg->bFormatIndex;
+ pc->bFrameIndex = sc->sc_desc_format_mjpeg->bDefaultFrameIndex;
+ error = uvideo_vs_set_probe(sc, probe_data);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (error);
+
+ /* get probe */
+ bzero(probe_data, sizeof(probe_data));
+ error = uvideo_vs_get_probe(sc, probe_data);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (error);
+
+ /* commit */
+ error = uvideo_vs_set_commit(sc, probe_data);
+ if (error != USBD_NORMAL_COMPLETION)
+ return (error);
+
+ /* save a copy of probe commit */
+ bcopy(pc, &sc->sc_desc_probe, sizeof(sc->sc_desc_probe));
+
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
uvideo_vs_set_probe(struct uvideo_softc *sc, uint8_t *probe_data)
{
usb_device_request_t req;
@@ -512,22 +865,19 @@ uvideo_vs_set_probe(struct uvideo_softc *sc, uint8_t *probe_data)
tmp = VS_PROBE_CONTROL;
tmp = tmp << 8;
USETW(req.wValue, tmp);
+ //USETW(req.wIndex, sc->sc_vs_curr->iface);
USETW(req.wIndex, 1);
USETW(req.wLength, 26);
pc = (struct usb_video_probe_commit *)probe_data;
- pc->bFormatIndex = 1;
- pc->bFrameIndex = 1;
err = usbd_do_request(sc->sc_udev, &req, probe_data);
if (err) {
- printf("%s: could not send SET request: %s\n",
+ printf("%s: could not SET probe request: %s\n",
DEVNAME(sc), usbd_errstr(err));
- return (-1);
+ return (USBD_INVAL);
}
-
- DPRINTF(1, "%s: SET probe control request successfully\n",
- DEVNAME(sc));
+ DPRINTF(1, "%s: SET probe request successfully\n", DEVNAME(sc));
DPRINTF(1, "bmHint=0x%02x\n", UGETW(pc->bmHint));
DPRINTF(1, "bFormatIndex=0x%02x\n", pc->bFormatIndex);
@@ -543,10 +893,10 @@ uvideo_vs_set_probe(struct uvideo_softc *sc, uint8_t *probe_data)
DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n",
UGETDW(pc->dwMaxPayloadTransferSize));
- return (0);
+ return (USBD_NORMAL_COMPLETION);
}
-int
+usbd_status
uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data)
{
usb_device_request_t req;
@@ -559,6 +909,7 @@ uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data)
tmp = VS_PROBE_CONTROL;
tmp = tmp << 8;
USETW(req.wValue, tmp);
+ //USETW(req.wIndex, sc->sc_vs_curr->iface);
USETW(req.wIndex, 1);
USETW(req.wLength, 26);
@@ -566,13 +917,11 @@ uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data)
err = usbd_do_request(sc->sc_udev, &req, probe_data);
if (err) {
- printf("%s: could not send GET request: %s\n",
+ printf("%s: could not GET probe request: %s\n",
DEVNAME(sc), usbd_errstr(err));
- return (-1);
+ return (USBD_INVAL);
}
-
- DPRINTF(1, "%s: GET probe control request successfully\n",
- DEVNAME(sc));
+ DPRINTF(1, "%s: GET probe request successfully\n", DEVNAME(sc));
DPRINTF(1, "bmHint=0x%02x\n", UGETW(pc->bmHint));
DPRINTF(1, "bFormatIndex=0x%02x\n", pc->bFormatIndex);
@@ -588,11 +937,11 @@ uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data)
DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n",
UGETDW(pc->dwMaxPayloadTransferSize));
- return (0);
+ return (USBD_NORMAL_COMPLETION);
}
-int
-uvideo_vs_set_probe_commit(struct uvideo_softc *sc, uint8_t *probe_data)
+usbd_status
+uvideo_vs_set_commit(struct uvideo_softc *sc, uint8_t *probe_data)
{
usb_device_request_t req;
usbd_status err;
@@ -603,20 +952,19 @@ uvideo_vs_set_probe_commit(struct uvideo_softc *sc, uint8_t *probe_data)
tmp = VS_COMMIT_CONTROL;
tmp = tmp << 8;
USETW(req.wValue, tmp);
+ //USETW(req.wIndex, sc->sc_vs_curr->iface);
USETW(req.wIndex, 1);
USETW(req.wLength, 26);
err = usbd_do_request(sc->sc_udev, &req, probe_data);
if (err) {
- printf("%s: could not send SET commit request: %s\n",
+ printf("%s: could not SET commit request: %s\n",
DEVNAME(sc), usbd_errstr(err));
- return (-1);
+ return (USBD_INVAL);
}
+ DPRINTF(1, "%s: SET commit request successfully\n", DEVNAME(sc));
- DPRINTF(1, "%s: SET probe commit request successfully\n",
- DEVNAME(sc));
-
- return (0);
+ return (USBD_NORMAL_COMPLETION);
}
int
@@ -883,7 +1231,7 @@ uvideo_dump_desc_vcheader(struct uvideo_softc *sc,
printf("wTotalLength=%d\n", UGETW(d->wTotalLength));
printf("dwClockFrequency=%d\n", UGETDW(d->dwClockFrequency));
printf("bInCollection=0x%02x\n", d->bInCollection);
- printf("baInterfaceNr=0x%02x\n", d->baInterfaceNr);
+ //printf("baInterfaceNr=0x%02x\n", d->baInterfaceNr[0]);
}
void
@@ -952,7 +1300,7 @@ uvideo_dump_desc_endpoint(struct uvideo_softc *sc,
printf(" (UE_BULK)\n");
if (UE_GET_XFERTYPE(d->bmAttributes) == UE_INTERRUPT)
printf(" (UE_INTERRUPT)\n");
- printf("wMaxPacketsize=%d\n", UGETW(d->wMaxPacketSize));
+ printf("wMaxPacketSize=%d\n", UGETW(d->wMaxPacketSize));
printf("bInterval=0x%02x\n", d->bInterval);
}
@@ -985,7 +1333,7 @@ uvideo_dump_desc_config(struct uvideo_softc *sc,
printf("bLength=%d\n", d->bLength);
printf("bDescriptorType=0x%02x\n", d->bDescriptorType);
- printf("wTotalLength=0x%02x\n", d->wTotalLength);
+ printf("wTotalLength=%d\n", UGETW(d->wTotalLength));
printf("bNumInterface=0x%02x\n", d->bNumInterface);
printf("bConfigurationValue=0x%02x\n", d->bConfigurationValue);
printf("iConfiguration=0x%02x\n", d->iConfiguration);
@@ -1028,9 +1376,9 @@ void
uvideo_dump_desc_frame_mjpeg(struct uvideo_softc *sc,
const usb_descriptor_t *desc)
{
- struct usb_video_frame_descriptor *d;
+ struct usb_video_frame_mjpeg_desc *d;
- d = (struct usb_video_frame_descriptor *)(uint8_t *)desc;
+ d = (struct usb_video_frame_mjpeg_desc *)(uint8_t *)desc;
printf("bLength=%d\n", d->bLength);
printf("bDescriptorType=0x%02x\n", d->bDescriptorType);
@@ -1052,9 +1400,9 @@ void
uvideo_dump_desc_format_mjpeg(struct uvideo_softc *sc,
const usb_descriptor_t *desc)
{
- struct usb_video_format_mjpeg_descriptor *d;
+ struct usb_video_format_mjpeg_desc *d;
- d = (struct usb_video_format_mjpeg_descriptor *)(uint8_t *)desc;
+ d = (struct usb_video_format_mjpeg_desc *)(uint8_t *)desc;
printf("bLength=%d\n", d->bLength);
printf("bDescriptorType=0x%02x\n", d->bDescriptorType);
@@ -1069,6 +1417,33 @@ uvideo_dump_desc_format_mjpeg(struct uvideo_softc *sc,
printf("bCopyProtect=0x%02x\n", d->bCopyProtect);
}
+/*
+ * Thanks to the retarded USB Video Class specs there are different
+ * descriptors types with the same bDescriptorSubtype which makes
+ * it necessary to differ between those types by doing descriptor
+ * size dances :-(
+ */
+int
+uvideo_desc_len(int size_total, int size_fix, int size_var_element)
+{
+ int size_var;
+
+ if (size_total < size_fix)
+ return (0);
+
+ if (size_total == size_fix)
+ return (1);
+
+ if (size_total > size_fix) {
+ size_var = size_total - size_fix;
+
+ if (size_var % size_var_element == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
int
uvideo_debug_file_open(struct uvideo_softc *sc)
{
diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h
index 6855fc7218a..1a6428e6332 100644
--- a/sys/dev/usb/uvideo.h
+++ b/sys/dev/usb/uvideo.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.h,v 1.3 2008/04/10 09:22:15 mglocker Exp $ */
+/* $OpenBSD: uvideo.h,v 1.4 2008/04/16 12:19:11 mglocker Exp $ */
/*
* Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
@@ -153,7 +153,7 @@
#define COMPONENT_CONNECTOR 0x0403
/* Table 3-3: VC Interface Header Descriptor */
-struct usb_video_header_descriptor {
+struct usb_video_header_desc {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
@@ -163,20 +163,9 @@ struct usb_video_header_descriptor {
uByte bInCollection;
};
-struct usb_video_control {
- struct usb_video_header_descriptor *descr;
- uByte *baInterfaceNr;
-};
-
-struct usb_video_header_desc {
- uByte bLength;
- uByte bDescriptorType;
- uByte bDescriptorSubtype;
- uWord bcdUVC;
- uWord wTotalLength;
- uDWord dwClockFrequency; /* XXX deprecated */
- uByte bInCollection;
- uByte baInterfaceNr;
+struct usb_video_header_desc_all {
+ struct usb_video_header_desc *fix;
+ uByte *baInterfaceNr;
};
/* Table 3-4: Input Terminal Descriptor */
@@ -238,18 +227,18 @@ struct usb_video_color_matching_descr {
/* Table 4-47: Video Probe and Commit Controls */
struct usb_video_probe_commit {
- uByte bmHint[2];
+ uWord bmHint;
uByte bFormatIndex;
uByte bFrameIndex;
- uByte dwFrameInterval[4];
- uByte wKeyFrameRate[2];
- uByte wPFrameRate[2];
- uByte wCompQuality[2];
- uByte wCompWindowSize[2];
- uByte wDelay[2];
- uByte dwMaxVideoFrameSize[4];
- uByte dwMaxPayloadTransferSize[4];
- uByte wClockFrequency[4];
+ uDWord dwFrameInterval;
+ uWord wKeyFrameRate;
+ uWord wPFrameRate;
+ uWord wCompQuality;
+ uWord wCompWindowSize;
+ uWord wDelay;
+ uDWord dwMaxVideoFrameSize;
+ uDWord dwMaxPayloadTransferSize;
+ uDWord wClockFrequency;
uByte bmFramingInfo;
uByte bPreferedVersion;
uByte bMinVersion;
@@ -282,7 +271,7 @@ struct usb_video_probe_commit {
#define UVIDEO_STREAM_EOH (1 << 7)
/* Table 3-1: Motion-JPEG Video Format Descriptor */
-struct usb_video_format_mjpeg_descriptor {
+struct usb_video_format_mjpeg_desc {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
@@ -297,7 +286,7 @@ struct usb_video_format_mjpeg_descriptor {
} __packed;
/* Table 3-2: Motion-JPEG Video Frame Descriptor */
-struct usb_video_frame_descriptor {
+struct usb_video_frame_mjpeg_desc {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
@@ -316,28 +305,23 @@ struct usb_video_frame_descriptor {
/*
* Driver specific private definitions.
*/
-#define UVIDEO_NFRAMES 10 /* XXX calculate right value */
+//#define UVIDEO_NFRAMES 10 /* XXX calculate right value */
+//#define UVIDEO_NFRAMES 4 /* XXX calculate right value */
+#define UVIDEO_NFRAMES_MAX 10 /* XXX find optimal value */
+#define UVIDEO_SFRAMES_MAX 3200 /* XXX find optimal value */
-struct uvideo_stream_if {
+struct uvideo_vs_iface {
struct uvideo_softc *sc;
usbd_xfer_handle xfer;
void *buf;
- int busy;
- int numalts;
- usbd_interface_handle in_ifaceh;
- usbd_pipe_handle in_pipeh;
+ usbd_interface_handle ifaceh;
int endpoint;
- u_int16_t size[UVIDEO_NFRAMES];
-
- u_int8_t fmtgrp_cnt;
-
- usbd_interface_handle ifaceh;
- usbd_interface_handle *if_descr;
- int curr_alt;
- u_int32_t max_isoc_payload;
-
- char start_polling;
- char fid;
+ usbd_pipe_handle pipeh;
+ uint16_t size[UVIDEO_NFRAMES_MAX];
+ int numalts;
+ int curalt;
+ uint32_t max_packet_size;
+ int iface;
};
struct uvideo_sample_buffer {
@@ -380,6 +364,13 @@ struct uvideo_softc {
struct vnode *sc_vp;
struct usb_task sc_task_write;
- struct usb_video_control *sc_vc_header;
- struct uvideo_stream_if sc_curr_strm;
+ int sc_nframes;
+ struct usb_video_probe_commit sc_desc_probe;
+ struct usb_video_header_desc_all sc_desc_vc_header;
+ struct usb_video_format_mjpeg_desc *sc_desc_format_mjpeg;
+ struct usb_video_frame_mjpeg_desc *sc_desc_frame_mjpeg;
+
+#define UVIDEO_MAX_VS_NUM 8
+ struct uvideo_vs_iface *sc_vs_curr;
+ struct uvideo_vs_iface sc_vs_coll[UVIDEO_MAX_VS_NUM];
};