From 5dc5d3a8a87c0dc9d57f2988f1976628b0cdef85 Mon Sep 17 00:00:00 2001 From: Marcus Glocker Date: Sat, 19 Apr 2008 11:24:24 +0000 Subject: Sort functions and remove obsolete bits. --- sys/dev/usb/uvideo.c | 1010 +++++++++++++++++++++++++------------------------- 1 file changed, 497 insertions(+), 513 deletions(-) (limited to 'sys/dev/usb') diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c index 4eb28399acc..3a5a4854b4a 100644 --- a/sys/dev/usb/uvideo.c +++ b/sys/dev/usb/uvideo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.c,v 1.9 2008/04/18 21:19:15 mglocker Exp $ */ +/* $OpenBSD: uvideo.c,v 1.10 2008/04/19 11:24:23 mglocker Exp $ */ /* * Copyright (c) 2008 Robert Nagy @@ -54,41 +54,42 @@ int uvideo_debug = 1; int uvideo_enable(void *); void uvideo_disable(void *); - int uvideo_open(void *, int); int uvideo_close(void *); +int uvideo_match(struct device *, void *, void *); +void uvideo_attach(struct device *, struct device *, void *); +int uvideo_detach(struct device *, int); +int uvideo_activate(struct device *, enum devact); + 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_format(struct uvideo_softc *); +int uvideo_vs_parse_desc_format_mjpeg(struct uvideo_softc *, + const usb_descriptor_t *); +int uvideo_vs_parse_desc_frame(struct uvideo_softc *); +int uvideo_vs_parse_desc_frame_mjpeg(struct uvideo_softc *, + const usb_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 *); +int uvideo_desc_len(const usb_descriptor_t *, int, int, int, int); +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 *); 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 *, struct usb_attach_arg *); void uvideo_vs_start(struct uvideo_softc *); void uvideo_vs_cb(usbd_xfer_handle, usbd_private_handle, usbd_status); -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); @@ -115,19 +116,10 @@ void uvideo_dump_desc_frame_mjpeg(struct uvideo_softc *, const usb_descriptor_t *); void uvideo_dump_desc_format_mjpeg(struct uvideo_softc *, const usb_descriptor_t *); - -int uvideo_desc_len(const usb_descriptor_t *, int, int, int, int); - +void uvideo_hexdump(void *, int); int uvideo_debug_file_open(struct uvideo_softc *); void uvideo_debug_file_write_sample(void *); -void uvideo_hexdump(void *, int); - -int uvideo_match(struct device *, void *, void *); -void uvideo_attach(struct device *, struct device *, void *); -int uvideo_detach(struct device *, int); -int uvideo_activate(struct device *, enum devact); - int uvideo_querycap(void *, struct v4l2_capability *); int uvideo_s_fmt(void *, struct v4l2_format *); int uvideo_g_fmt(void *, struct v4l2_format *); @@ -164,6 +156,64 @@ struct video_hw_if uvideo_hw_if = { NULL /* VIDIOC_DQBUF */ }; +int +uvideo_enable(void *v) +{ + struct uvideo_softc *sc = v; + + DPRINTF(1, "%s: uvideo_enable sc=%p\n", DEVNAME(sc), sc); + + if (sc->sc_dying) + return (EIO); + + if (sc->sc_enabled) + return (EBUSY); + + sc->sc_enabled = 1; + + return (0); +} + +void +uvideo_disable(void *v) +{ + struct uvideo_softc *sc = v; + + DPRINTF(1, "%s: uvideo_disable sc=%p\n", DEVNAME(sc), sc); + + if (!sc->sc_enabled) { + printf("uvideo_disable: already disabled!\n"); + return; + } + + sc->sc_enabled = 0; +} + +int +uvideo_open(void *addr, int flags) +{ + struct uvideo_softc *sc = addr; + + DPRINTF(1, "uvideo_open: sc=%p\n", sc); + + if (sc->sc_dying) + return (EIO); + + return (0); +} + +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_match(struct device * parent, void *match, void *aux) { @@ -209,16 +259,6 @@ uvideo_attach(struct device * parent, struct device * self, void *aux) if (error != USBD_NORMAL_COMPLETION) return; - /* parse video stream format descriptors */ - error = uvideo_vs_parse_format_desc(sc); - if (error != USBD_NORMAL_COMPLETION) - return; - - /* parse video stream frame descriptors */ - error = uvideo_vs_parse_frame_desc(sc); - if (error != USBD_NORMAL_COMPLETION) - return; - /* parse video stream descriptors */ error = uvideo_vs_parse_desc(sc, uaa, cdesc); if (error != USBD_NORMAL_COMPLETION) @@ -243,7 +283,6 @@ uvideo_attach(struct device * parent, struct device * self, void *aux) 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); @@ -289,65 +328,8 @@ uvideo_activate(struct device * self, enum devact act) sc->sc_dying = 1; break; } - return (rv); -} - -int -uvideo_enable(void *v) -{ - struct uvideo_softc *sc = v; - - DPRINTF(1, "%s: uvideo_enable sc=%p\n", DEVNAME(sc), sc); - - if (sc->sc_dying) - return (EIO); - - if (sc->sc_enabled) - return (EBUSY); - - - sc->sc_enabled = 1; - - return (0); -} - -void -uvideo_disable(void *v) -{ - struct uvideo_softc *sc = v; - - DPRINTF(1, "%s: uvideo_disable sc=%p\n", DEVNAME(sc), sc); - - if (!sc->sc_enabled) { - printf("uvideo_disable: already disabled!\n"); - return; - } - sc->sc_enabled = 0; -} - -int -uvideo_open(void *addr, int flags) -{ - struct uvideo_softc *sc = addr; - - DPRINTF(1, "uvideo_open: sc=%p\n", sc); - - if (sc->sc_dying) - return (EIO); - - return (0); -} - -int -uvideo_close(void *addr) -{ -#if 0 - struct uvideo_softc *sc = addr; - - DPRINTF(1, "uvideo_close: sc=%p\n", sc); -#endif - return (0); + return (rv); } int @@ -423,12 +405,25 @@ uvideo_vs_parse_desc(struct uvideo_softc *sc, struct usb_attach_arg *uaa, { usb_interface_descriptor_t *id; int i, iface, numalts; + usbd_status error; 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); + /* TODO: loop through general VS descriptors */ + + /* parse video stream format descriptors */ + error = uvideo_vs_parse_desc_format(sc); + if (error != USBD_NORMAL_COMPLETION) + return (error); + + /* parse video stream frame descriptors */ + error = uvideo_vs_parse_desc_frame(sc); + if (error != USBD_NORMAL_COMPLETION) + return (error); + /* parse interface collection */ for (i = 0; i < sc->sc_desc_vc_header.fix->bInCollection; i++) { iface = sc->sc_desc_vc_header.baInterfaceNr[i]; @@ -456,147 +451,48 @@ uvideo_vs_parse_desc(struct uvideo_softc *sc, struct usb_attach_arg *uaa, } int -uvideo_vs_parse_desc_alt(struct uvideo_softc *sc, struct usb_attach_arg *uaa, - int vs_nr, int iface, int numalts) +uvideo_vs_parse_desc_format(struct uvideo_softc *sc) { - struct uvideo_vs_iface *vs; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - int i; - usbd_status error; - - vs = &sc->sc_vs_coll[vs_nr]; - - 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[iface]); - if (id == NULL) - continue; + usbd_desc_iter_t iter; + const usb_descriptor_t *desc; - DPRINTF(1, "%s: bAlternateSetting=0x%02x, ", - DEVNAME(sc), id->bAlternateSetting); + DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); - ed = usbd_interface2endpoint_descriptor(uaa->ifaces[iface], 0); - if (ed == NULL) { - DPRINTF(1, "no endpoint descriptor\n"); + 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; } - 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; + switch (desc->bDescriptorSubtype) { + case UDESCSUB_VS_FORMAT_MJPEG: + if (desc->bLength == 11) { + uvideo_vs_parse_desc_format_mjpeg(sc, desc); + } + break; } - } - /* 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); + desc = usb_desc_iter_next(&iter); } - return (USBD_NORMAL_COMPLETION); + return (0); } int -uvideo_vs_set_alt(struct uvideo_softc *sc, struct usb_attach_arg *uaa, - int iface, int max_packet_size) +uvideo_vs_parse_desc_format_mjpeg(struct uvideo_softc *sc, + const usb_descriptor_t *desc) { - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - int i; - usbd_status error; + struct usb_video_format_mjpeg_desc *d; - 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 (USBD_INVAL); - } + d = (struct usb_video_format_mjpeg_desc *)(uint8_t *)desc; - 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); - } - } - - 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__); - - 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); - } + if (d->bNumFrameDescriptors == 0) { + printf("%s: no MJPEG frame descriptors found!\n", + DEVNAME(sc)); + return (-1); + } sc->sc_desc_format_mjpeg = d; @@ -604,7 +500,7 @@ uvideo_vs_parse_format_desc_mjpeg(struct uvideo_softc *sc, } int -uvideo_vs_parse_frame_desc(struct uvideo_softc *sc) +uvideo_vs_parse_desc_frame(struct uvideo_softc *sc) { usbd_desc_iter_t iter; const usb_descriptor_t *desc; @@ -621,7 +517,7 @@ uvideo_vs_parse_frame_desc(struct uvideo_softc *sc) switch (desc->bDescriptorSubtype) { case UDESCSUB_VS_FRAME_MJPEG: - if (uvideo_vs_parse_frame_desc_mjpeg(sc, desc) == 0) + if (uvideo_vs_parse_desc_frame_mjpeg(sc, desc) == 0) return (0); break; } @@ -635,7 +531,7 @@ uvideo_vs_parse_frame_desc(struct uvideo_softc *sc) } int -uvideo_vs_parse_frame_desc_mjpeg(struct uvideo_softc *sc, +uvideo_vs_parse_desc_frame_mjpeg(struct uvideo_softc *sc, const usb_descriptor_t *desc) { struct usb_video_frame_mjpeg_desc *d; @@ -651,171 +547,139 @@ uvideo_vs_parse_frame_desc_mjpeg(struct uvideo_softc *sc, return (0); } -usbd_status -uvideo_vs_alloc_sample(struct uvideo_softc *sc) +int +uvideo_vs_parse_desc_alt(struct uvideo_softc *sc, struct usb_attach_arg *uaa, + int vs_nr, int iface, int numalts) { - struct uvideo_sample_buffer *fb = &sc->sc_sample_buffer; - - DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); + struct uvideo_vs_iface *vs; + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed; + int i; + usbd_status error; - 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); - } + vs = &sc->sc_vs_coll[vs_nr]; - fb->fragment = 0; - fb->fid = 0; - fb->offset = 0; + 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); + } - return (USBD_NORMAL_COMPLETION); -} + id = usbd_get_interface_descriptor(uaa->ifaces[iface]); + if (id == NULL) + continue; -usbd_status -uvideo_vs_alloc(struct uvideo_softc *sc) -{ - int size; + DPRINTF(1, "%s: bAlternateSetting=0x%02x, ", + DEVNAME(sc), id->bAlternateSetting); - DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); + ed = usbd_interface2endpoint_descriptor(uaa->ifaces[iface], 0); + if (ed == NULL) { + DPRINTF(1, "no endpoint descriptor\n"); + continue; + } - sc->sc_vs_curr->sc = sc; + DPRINTF(1, "bEndpointAddress=0x%02x, ", ed->bEndpointAddress); + DPRINTF(1, "wMaxPacketSize=%d\n", UGETW(ed->wMaxPacketSize)); - 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); + 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; + } } - 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); + /* 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); } - 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, struct usb_attach_arg *uaa) +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; - DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); -#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 (error); - } - - 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_INVAL); - } - DPRINTF(1, "%s: open pipe for ", DEVNAME(sc)); - DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize=%d (%d)\n", - ed->bEndpointAddress, - 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(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); -} + 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 (USBD_INVAL); + } -void -uvideo_vs_start(struct uvideo_softc *sc) -{ - int i; + id = usbd_get_interface_descriptor(uaa->ifaces[iface]); + if (id == NULL) + continue; - DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__); + ed = usbd_interface2endpoint_descriptor(uaa->ifaces[iface], 0); + if (ed == NULL) + continue; - for (i = 0; i < sc->sc_nframes; i++) - sc->sc_vs_curr->size[i] = sc->sc_vs_curr->max_packet_size; + 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); - bzero(sc->sc_vs_curr->buf, - sc->sc_vs_curr->max_packet_size * sc->sc_nframes); + DPRINTF(1, "%s: set alternate iface to ", DEVNAME(sc)); + DPRINTF(1, "bAlternateSetting=0x%02x\n", + id->bAlternateSetting); - usbd_setup_isoc_xfer( - 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); + return (USBD_NORMAL_COMPLETION); + } + } - (void)usbd_transfer(sc->sc_vs_curr->xfer); + return (USBD_INVAL); } -void -uvideo_vs_cb(usbd_xfer_handle xfer, usbd_private_handle priv, - usbd_status status) +/* + * 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 :-( + * + * size_fix: total size of the fixed structure part + * off_num_elements: offset which tells the number of following elements + * size_element: size of a single element + * off_size_element: if size_element is 0 the element size is taken from + * this offset in the descriptor + */ +int +uvideo_desc_len(const usb_descriptor_t *desc, + int size_fix, int off_num_elements, int size_element, int off_size_element) { - struct uvideo_vs_iface *vs = priv; - struct uvideo_softc *sc = vs->sc; - int len, i, frame_size; - uint8_t *frame; - - DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__); + uint8_t *buf; + int size_elements, size_total; - if (status != USBD_NORMAL_COMPLETION) { - printf("%s: %s: %s\n", DEVNAME(sc), __func__, - usbd_errstr(status)); - return; - } - usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); + if (desc->bLength < size_fix) + return (0); - DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), len); - if (len == 0) - goto skip; + buf = (uint8_t *)desc; - for (i = 0; i < sc->sc_nframes; i++) { - frame = vs->buf + (i * vs->max_packet_size); - frame_size = vs->size[i]; + if (size_element == 0) + size_element = buf[off_size_element]; - if (frame_size == 0) - /* frame is empty */ - continue; + size_elements = buf[off_num_elements] * size_element; + size_total = size_fix + size_elements; - uvideo_vs_decode_stream_header(sc, frame, frame_size); - } + if (desc->bLength == size_total) + return (1); -skip: /* setup new transfer */ - uvideo_vs_start(sc); + return (0); } usbd_status @@ -868,8 +732,7 @@ 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.wIndex, sc->sc_vs_curr->iface); USETW(req.wLength, 26); pc = (struct usb_video_probe_commit *)probe_data; @@ -880,94 +743,251 @@ uvideo_vs_set_probe(struct uvideo_softc *sc, uint8_t *probe_data) DEVNAME(sc), usbd_errstr(err)); return (USBD_INVAL); } - DPRINTF(1, "%s: SET probe 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); + DPRINTF(1, "bFrameIndex=0x%02x\n", pc->bFrameIndex); + DPRINTF(1, "dwFrameInterval=%d (ns)\n", UGETDW(pc->dwFrameInterval)); + DPRINTF(1, "wKeyFrameRate=%d\n", UGETW(pc->wKeyFrameRate)); + DPRINTF(1, "wPFrameRate=%d\n", UGETW(pc->wPFrameRate)); + DPRINTF(1, "wCompQuality=%d\n", UGETW(pc->wCompQuality)); + DPRINTF(1, "wCompWindowSize=0x%04x\n", UGETW(pc->wCompWindowSize)); + DPRINTF(1, "wDelay=%d (ms)\n", UGETW(pc->wDelay)); + DPRINTF(1, "dwMaxVideoFrameSize=%d (bytes)\n", + UGETDW(pc->dwMaxVideoFrameSize)); + DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n", + UGETDW(pc->dwMaxPayloadTransferSize)); + + return (USBD_NORMAL_COMPLETION); +} + +usbd_status +uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data) +{ + usb_device_request_t req; + usbd_status err; + uint16_t tmp; + struct usb_video_probe_commit *pc; + + req.bmRequestType = UVIDEO_GET_IF; + req.bRequest = GET_CUR; + tmp = VS_PROBE_CONTROL; + tmp = tmp << 8; + USETW(req.wValue, tmp); + USETW(req.wIndex, sc->sc_vs_curr->iface); + USETW(req.wLength, 26); + + pc = (struct usb_video_probe_commit *)probe_data; + + err = usbd_do_request(sc->sc_udev, &req, probe_data); + if (err) { + printf("%s: could not GET probe request: %s\n", + DEVNAME(sc), usbd_errstr(err)); + return (USBD_INVAL); + } + 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); + DPRINTF(1, "bFrameIndex=0x%02x\n", pc->bFrameIndex); + DPRINTF(1, "dwFrameInterval=%d (ns)\n", UGETDW(pc->dwFrameInterval)); + DPRINTF(1, "wKeyFrameRate=%d\n", UGETW(pc->wKeyFrameRate)); + DPRINTF(1, "wPFrameRate=%d\n", UGETW(pc->wPFrameRate)); + DPRINTF(1, "wCompQuality=%d\n", UGETW(pc->wCompQuality)); + DPRINTF(1, "wCompWindowSize=0x%04x\n", UGETW(pc->wCompWindowSize)); + DPRINTF(1, "wDelay=%d (ms)\n", UGETW(pc->wDelay)); + DPRINTF(1, "dwMaxVideoFrameSize=%d (bytes)\n", + UGETDW(pc->dwMaxVideoFrameSize)); + DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n", + UGETDW(pc->dwMaxPayloadTransferSize)); + + return (USBD_NORMAL_COMPLETION); +} + +usbd_status +uvideo_vs_set_commit(struct uvideo_softc *sc, uint8_t *probe_data) +{ + usb_device_request_t req; + usbd_status err; + uint16_t tmp; + + req.bmRequestType = UVIDEO_SET_IF; + req.bRequest = SET_CUR; + tmp = VS_COMMIT_CONTROL; + tmp = tmp << 8; + USETW(req.wValue, tmp); + USETW(req.wIndex, sc->sc_vs_curr->iface); + USETW(req.wLength, 26); + + err = usbd_do_request(sc->sc_udev, &req, probe_data); + if (err) { + printf("%s: could not SET commit request: %s\n", + DEVNAME(sc), usbd_errstr(err)); + return (USBD_INVAL); + } + DPRINTF(1, "%s: SET commit request successfully\n", DEVNAME(sc)); + + return (USBD_NORMAL_COMPLETION); +} + +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) +{ + int size; + + DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); + + sc->sc_vs_curr->sc = 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); + } + + 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, struct usb_attach_arg *uaa) +{ + usb_endpoint_descriptor_t *ed; + usbd_status error; + + DPRINTF(1, "%s: %s\n", DEVNAME(sc), __func__); + + 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 (error); + } + + 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_INVAL); + } + DPRINTF(1, "%s: open pipe for ", DEVNAME(sc)); + DPRINTF(1, "bEndpointAddress=0x%02x (0x%02x), wMaxPacketSize=%d (%d)\n", + ed->bEndpointAddress, + 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(error)); + return (error); + } - DPRINTF(1, "bmHint=0x%02x\n", UGETW(pc->bmHint)); - DPRINTF(1, "bFormatIndex=0x%02x\n", pc->bFormatIndex); - DPRINTF(1, "bFrameIndex=0x%02x\n", pc->bFrameIndex); - DPRINTF(1, "dwFrameInterval=%d (ns)\n", UGETDW(pc->dwFrameInterval)); - DPRINTF(1, "wKeyFrameRate=%d\n", UGETW(pc->wKeyFrameRate)); - DPRINTF(1, "wPFrameRate=%d\n", UGETW(pc->wPFrameRate)); - DPRINTF(1, "wCompQuality=%d\n", UGETW(pc->wCompQuality)); - DPRINTF(1, "wCompWindowSize=0x%04x\n", UGETW(pc->wCompWindowSize)); - DPRINTF(1, "wDelay=%d (ms)\n", UGETW(pc->wDelay)); - DPRINTF(1, "dwMaxVideoFrameSize=%d (bytes)\n", - UGETDW(pc->dwMaxVideoFrameSize)); - DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n", - UGETDW(pc->dwMaxPayloadTransferSize)); + /* 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); } -usbd_status -uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t *probe_data) +void +uvideo_vs_start(struct uvideo_softc *sc) { - usb_device_request_t req; - usbd_status err; - uint16_t tmp; - struct usb_video_probe_commit *pc; + int i; - req.bmRequestType = UVIDEO_GET_IF; - req.bRequest = GET_CUR; - 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); + DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__); - pc = (struct usb_video_probe_commit *)probe_data; + for (i = 0; i < sc->sc_nframes; i++) + sc->sc_vs_curr->size[i] = sc->sc_vs_curr->max_packet_size; - err = usbd_do_request(sc->sc_udev, &req, probe_data); - if (err) { - printf("%s: could not GET probe request: %s\n", - DEVNAME(sc), usbd_errstr(err)); - return (USBD_INVAL); - } - DPRINTF(1, "%s: GET probe request successfully\n", DEVNAME(sc)); + bzero(sc->sc_vs_curr->buf, + sc->sc_vs_curr->max_packet_size * sc->sc_nframes); - DPRINTF(1, "bmHint=0x%02x\n", UGETW(pc->bmHint)); - DPRINTF(1, "bFormatIndex=0x%02x\n", pc->bFormatIndex); - DPRINTF(1, "bFrameIndex=0x%02x\n", pc->bFrameIndex); - DPRINTF(1, "dwFrameInterval=%d (ns)\n", UGETDW(pc->dwFrameInterval)); - DPRINTF(1, "wKeyFrameRate=%d\n", UGETW(pc->wKeyFrameRate)); - DPRINTF(1, "wPFrameRate=%d\n", UGETW(pc->wPFrameRate)); - DPRINTF(1, "wCompQuality=%d\n", UGETW(pc->wCompQuality)); - DPRINTF(1, "wCompWindowSize=0x%04x\n", UGETW(pc->wCompWindowSize)); - DPRINTF(1, "wDelay=%d (ms)\n", UGETW(pc->wDelay)); - DPRINTF(1, "dwMaxVideoFrameSize=%d (bytes)\n", - UGETDW(pc->dwMaxVideoFrameSize)); - DPRINTF(1, "dwMaxPayloadTransferSize=%d (bytes)\n", - UGETDW(pc->dwMaxPayloadTransferSize)); + usbd_setup_isoc_xfer( + 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); - return (USBD_NORMAL_COMPLETION); + (void)usbd_transfer(sc->sc_vs_curr->xfer); } -usbd_status -uvideo_vs_set_commit(struct uvideo_softc *sc, uint8_t *probe_data) +void +uvideo_vs_cb(usbd_xfer_handle xfer, usbd_private_handle priv, + usbd_status status) { - usb_device_request_t req; - usbd_status err; - uint16_t tmp; + struct uvideo_vs_iface *vs = priv; + struct uvideo_softc *sc = vs->sc; + int len, i, frame_size; + uint8_t *frame; - req.bmRequestType = UVIDEO_SET_IF; - req.bRequest = SET_CUR; - 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); + DPRINTF(2, "%s: %s\n", DEVNAME(sc), __func__); - err = usbd_do_request(sc->sc_udev, &req, probe_data); - if (err) { - printf("%s: could not SET commit request: %s\n", - DEVNAME(sc), usbd_errstr(err)); - return (USBD_INVAL); + if (status != USBD_NORMAL_COMPLETION) { + printf("%s: %s: %s\n", DEVNAME(sc), __func__, + usbd_errstr(status)); + return; + } + usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); + + DPRINTF(2, "%s: *** buffer len = %d\n", DEVNAME(sc), len); + if (len == 0) + goto skip; + + 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 */ + continue; + + uvideo_vs_decode_stream_header(sc, frame, frame_size); } - DPRINTF(1, "%s: SET commit request successfully\n", DEVNAME(sc)); - return (USBD_NORMAL_COMPLETION); +skip: /* setup new transfer */ + uvideo_vs_start(sc); } int @@ -1044,50 +1064,6 @@ uvideo_vs_decode_stream_header(struct uvideo_softc *sc, uint8_t *frame, return (0); } -int -uvideo_querycap(void *v, struct v4l2_capability * caps) -{ - struct uvideo_softc *sc = v; - - bzero(caps, sizeof(caps)); - strlcpy(caps->driver, DEVNAME(sc), - sizeof(caps->driver)); - strncpy(caps->card, "Generic USB video class device", - sizeof(caps->card)); - strncpy(caps->bus_info, "usb", sizeof(caps->bus_info)); - - caps->version = 1; - caps->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING - | V4L2_CAP_READWRITE; - - return (0); -} - -int -uvideo_s_fmt(void *v, struct v4l2_format * fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return (EINVAL); - - return (0); -} - -int -uvideo_g_fmt(void *v, struct v4l2_format * fmt) -{ - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return (EINVAL); - - return (0); -} - -int -uvideo_reqbufs(void *v, struct v4l2_requestbuffers * rb) -{ - return (0); -} - void uvideo_dump_desc_all(struct uvideo_softc *sc) { @@ -1449,40 +1425,19 @@ 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 :-( - * - * size_fix: total size of the fixed structure part - * off_num_elements: offset which tells the number of following elements - * size_element: size of a single element - * off_size_element: if size_element is 0 the element size is taken from - * this offset in the descriptor - */ -int -uvideo_desc_len(const usb_descriptor_t *desc, - int size_fix, int off_num_elements, int size_element, int off_size_element) +void +uvideo_hexdump(void *buf, int len) { - uint8_t *buf; - int size_elements, size_total; - - if (desc->bLength < size_fix) - return (0); - - buf = (uint8_t *)desc; - - if (size_element == 0) - size_element = buf[off_size_element]; - - size_elements = buf[off_num_elements] * size_element; - size_total = size_fix + size_elements; - - if (desc->bLength == size_total) - return (1); + int i; - return (0); + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("%s%5i:", i ? "\n" : "", i); + if (i % 4 == 0) + printf(" "); + printf("%02x", (int)*((u_char *)buf + i)); + } + printf("\n"); } int @@ -1532,17 +1487,46 @@ uvideo_debug_file_write_sample(void *arg) DPRINTF(1, "vn_rdwr error!\n"); } -void -uvideo_hexdump(void *buf, int len) +int +uvideo_querycap(void *v, struct v4l2_capability * caps) { - int i; + struct uvideo_softc *sc = v; - for (i = 0; i < len; i++) { - if (i % 16 == 0) - printf("%s%5i:", i ? "\n" : "", i); - if (i % 4 == 0) - printf(" "); - printf("%02x", (int)*((u_char *)buf + i)); - } - printf("\n"); + bzero(caps, sizeof(caps)); + strlcpy(caps->driver, DEVNAME(sc), + sizeof(caps->driver)); + strncpy(caps->card, "Generic USB video class device", + sizeof(caps->card)); + strncpy(caps->bus_info, "usb", sizeof(caps->bus_info)); + + caps->version = 1; + caps->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE; + + return (0); +} + +int +uvideo_s_fmt(void *v, struct v4l2_format * fmt) +{ + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return (EINVAL); + + return (0); +} + +int +uvideo_g_fmt(void *v, struct v4l2_format * fmt) +{ + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return (EINVAL); + + return (0); +} + +int +uvideo_reqbufs(void *v, struct v4l2_requestbuffers * rb) +{ + return (0); } -- cgit v1.2.3