tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: GSoC - USB Video Class (UVC) webcam driver



pat%polycrystal.org@localhost said:
> the IAD stuff is not yet in -current?

So I've stripped down the IAD code to something which
is harmless enough imho to go into the tree before
the 5.0 branch. It is just the additional device
attachment; there are no changes to kernel config
files necessary unless one actually wants to use
a device which uses a driver which makes use of it -
uvc would be the first candidate.

The intention is to make 5.0 a stable platform where
further uvc work can be done on, without requiring
framework changes.

I'm aware of the fact that there is no time left in soc,
but could you have a look at it and tell whether
it would work with your code?

Unless a driver attaches to "usbfif", it should issue
a message "IAD device at blabla not configured" if
a webcam is connected.

best regards
Matthias





-------------------------------------------------------------------
-------------------------------------------------------------------
Forschungszentrum Juelich GmbH
52425 Juelich

Sitz der Gesellschaft: Juelich
Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
Vorsitzende des Aufsichtsrats: MinDir'in Baerbel Brumme-Bothe
Geschaeftsfuehrung: Prof. Dr. Achim Bachem (Vorsitzender),
Dr. Ulrich Krafft (stellv. Vorsitzender), Prof. Dr. Harald Bolt,
Dr. Sebastian M. Schmidt
-------------------------------------------------------------------
-------------------------------------------------------------------
/* NetBSD */

struct usbfunction_attach_args {
        usbd_device_handle device;
        int port;
        int vendor, product, release;
        int configno;

        int type;
#define USBF_IAD 1
#define USBF_LEGACYAUDIO 2
#define USBF_INTERFACE 3
        int class, subclass, proto;
        int ifaceno;
        int nifaces;
        usbd_interface_handle *ifaces;  
};
/* $NetBSD$ */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>

#include <sys/device.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <sys/bus.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbfunction.h>

#include "locators.h"

static int usb_fifprint(void *, const char *);

typedef struct {
        uByte bLength;
        uByte bDescriptorType;
        uByte bFirstInterface;
        uByte bInterfaceCount;
        uByte bFunctionClass;
        uByte bFunctionSubClass;
        uByte bFunctionProtocol;
        uByte iFunction;
} __packed usb_interface_association_descriptor_t;

#define UDESC_INTERFACE_ASSOCIATION 11

/*
 * attach by IADs
 */
static usbd_status
usbfcn_scaniads(device_t parent, usbd_device_handle dev,
                struct usbfunction_attach_args *ufaa, int *locs)
{
        usbd_desc_iter_t di;
        const usb_descriptor_t *d;
        const usb_interface_association_descriptor_t *iad;
        int ifbusy, i;
        usbd_interface_handle *ifs;
        device_t dv;

        usb_desc_iter_init(dev, &di);
        while ((d = usb_desc_iter_next(&di))) {
                if (d->bDescriptorType != UDESC_INTERFACE_ASSOCIATION)
                        continue;
                iad = (const usb_interface_association_descriptor_t *)d;

                if (iad->bFirstInterface + iad->bInterfaceCount
                    > dev->cdesc->bNumInterface) {
                        printf("%s: invalid iad\n", device_xname(parent));
                        return USBD_INVAL;
                }

                ifbusy = 0;
                for (i = 0; i < iad->bInterfaceCount; i++) {
                        if (dev->subdevs[iad->bFirstInterface + i]) {
                                ifbusy++;
                                break;
                        }
                }
                if (ifbusy)
                        continue;

                ifs = malloc(iad->bInterfaceCount
                             * sizeof(usbd_interface_handle *),
                             M_USBDEV, M_NOWAIT);
                if (!ifs)
                        return USBD_NOMEM;
                for (i = 0; i < iad->bInterfaceCount; i++)
                        ifs[i] = &dev->ifaces[iad->bFirstInterface + i];
                ufaa->type = USBF_IAD;
                ufaa->class = iad->bFunctionClass;
                ufaa->subclass = iad->bFunctionSubClass;
                ufaa->proto = iad->bFunctionProtocol;
                ufaa->ifaces = ifs;
                ufaa->nifaces = iad->bInterfaceCount;
                ufaa->ifaceno = iad->bFirstInterface;
                locs[USBFIFCF_INTERFACE] = ufaa->ifaceno;
                dv = config_found_sm_loc(parent, "usbfif", locs, ufaa,
                                         usb_fifprint, config_stdsubmatch);
                if (dv) {
                        for (i = 0; i < iad->bInterfaceCount; i++)
                                dev->subdevs[iad->bFirstInterface + i] = dv;
                        dev->nifaces_claimed += iad->bInterfaceCount;
                }
                free(ifs, M_USBDEV);
        }
        return USBD_NORMAL_COMPLETION;
}

#if 0 /* not yet */
/*
 * handle audio devices without IADs: look for multiple audio interfaces
 * (need at least one control and one streaming interface)
 */
static usbd_status
usbfcn_scanaudio(device_t parent, usbd_device_handle dev,
        struct usbfunction_attach_args *ufaa, int *locs)
{
        int nifaces, naudioif, i, j;
        usbd_interface_handle *ifs;
        int *ifacenrs;
        device_t dv;

        nifaces = dev->cdesc->bNumInterface;
        naudioif = 0;
        for (i = 0; i < nifaces; i++) {
                if (dev->subdevs[i])
                        continue; /* interface already claimed */
                if (dev->ifaces[i].idesc->bInterfaceClass == UICLASS_AUDIO)
                        naudioif++;
        }
        if (naudioif < 2)
                return USBD_NORMAL_COMPLETION;

        ifs = malloc(naudioif * sizeof(usbd_interface_handle *),
                     M_USBDEV, M_NOWAIT);
        if (!ifs)
                return USBD_NOMEM;
        ifacenrs = malloc(naudioif * sizeof(int), M_USBDEV, M_NOWAIT);
        if (!ifacenrs) {
                free(ifs, M_USBDEV);
                return USBD_NOMEM;
        }
        j = 0;
        for (i = 0; i < nifaces; i++) {
                if (dev->subdevs[i])
                        continue; /* interface already claimed */
                if (dev->ifaces[i].idesc->bInterfaceClass == UICLASS_AUDIO) {
                        ifs[j] = &dev->ifaces[i];
                        ifacenrs[j] = i;
                        j++;
                        if (j == naudioif)
                                break;
                }
        }
        if (j != naudioif) {
                printf("udev_scanaudio: lost interface\n");
                free(ifs, M_USBDEV);
                return USBD_INVAL;
        }

        ufaa->type = USBF_LEGACYAUDIO;
        ufaa->class = UICLASS_AUDIO;
        ufaa->subclass = 0;
        ufaa->proto = 0;
        ufaa->ifaces = ifs;
        ufaa->nifaces = naudioif;
        ufaa->ifaceno = ifacenrs[0];
        locs[USBFIFCF_INTERFACE] = ufaa->ifaceno;
        dv = config_found_sm_loc(parent, "usbfif", locs, ufaa,
                                 usb_fifprint, config_stdsubmatch);
        if (dv) {
                for (i = 0; i < naudioif; i++)
                        dev->subdevs[ifacenrs[i]] = dv;
                dev->nifaces_claimed += naudioif;
        }
        free(ifs, M_USBDEV);
        free(ifacenrs, M_USBDEV);
        return USBD_NORMAL_COMPLETION;
}

static usbd_status
usbfcn_scaninterfaces(device_t parent, usbd_device_handle dev,
                      struct usbfunction_attach_args *ufaa, int *locs)
{
        int i;
        usbd_interface_handle ifs;
        device_t dv;

        for (i = 0; i < dev->cdesc->bNumInterface; i++) {
                if (dev->subdevs[i])
                        continue; /* interface already claimed */
                ifs = &dev->ifaces[i];
                ufaa->type = USBF_INTERFACE;
                ufaa->class = dev->ifaces[i].idesc->bInterfaceClass;
                ufaa->subclass = dev->ifaces[i].idesc->bInterfaceSubClass;
                ufaa->proto = dev->ifaces[i].idesc->bInterfaceProtocol;
                ufaa->ifaces = &ifs;
                ufaa->nifaces = 1;
                /* ifaceno should be i, else we have a strange device */
                ufaa->ifaceno = dev->ifaces[i].idesc->bInterfaceNumber;
                locs[USBFIFCF_INTERFACE] = ufaa->ifaceno;
                dv = config_found_sm_loc(parent, "usbfif", locs, ufaa,
                                         usb_fifprint, config_stdsubmatch);
                if (dv) {
                        dev->subdevs[i] = dv;
                        dev->nifaces_claimed++;
                }
        }
        return USBD_NORMAL_COMPLETION;
}
#endif /* not yet */

static int
usb_fifprint(void *aux, const char *pnp)
{
        struct usbfunction_attach_args *uaa = aux;

        if (pnp) {
                if (uaa->type == USBF_IAD)
                        aprint_normal("IAD device (class=%d) at %s",
                                      uaa->class, pnp);
#if 0 /* not yet */
                else if (uaa->type == USBF_LEGACYAUDIO)
                        aprint_normal("legacy audio device at %s", pnp);
#endif
                else
                        return (QUIET);
        }
        aprint_normal(" interface %d", uaa->ifaceno);
        return (UNCONF);
}

usbd_status
usb_attachfunctions(device_t parent, usbd_device_handle dev, int port)
{
        usbd_status res;
        usb_device_descriptor_t *dd;
        struct usbfunction_attach_args ufaa;
        int locs[USBFIFCF_NLOCS];

        dd = &dev->ddesc;

        ufaa.device = dev;
        ufaa.port = port;
        ufaa.vendor = UGETW(dd->idVendor);
        ufaa.product = UGETW(dd->idProduct);
        ufaa.release = UGETW(dd->bcdDevice);
        ufaa.configno = dev->cdesc->bConfigurationValue;
        locs[USBFIFCF_PORT] = ufaa.port;
        locs[USBFIFCF_VENDOR] = ufaa.vendor;
        locs[USBFIFCF_PRODUCT] = ufaa.product;
        locs[USBFIFCF_RELEASE] = ufaa.release;
        locs[USBFIFCF_CONFIGURATION] = ufaa.configno;

        if ((dd->bDeviceClass == UDCLASS_MISC) &&
            (dd->bDeviceSubClass == UDSUBCLASS_COMMON) &&
            (dd->bDeviceProtocol == UDPROTO_IAD) &&
            (dev->cdesc->iConfiguration == 0)) {
                res = usbfcn_scaniads(parent, dev, &ufaa, locs);
                if (res)
                        return res;
        }       
#if 0 /* not yet */
        res = usbfcn_scanaudio(parent, dev, &ufaa, locs);
        if (res)
                return res;

        res = usbfcn_scaninterfaces(parent, dev, &ufaa, locs);
        if (res)
                return res;
#endif
        return USBD_NORMAL_COMPLETION;
}
#
# old_revision [05483fc8817ab109a28dae727d55611ef093c9cf]
#
# patch "sys/dev/usb/files.usb"
#  from [f8965efae43fae946f88304cc9ab9bf6331cb4ae]
#    to [e9b86c319bb1e13ab65518db14c12285c4b001bc]
# 
# patch "sys/dev/usb/usb.h"
#  from [4a00b4b553426a4992979e04792911044710560b]
#    to [944759b51fefe5d2fcacbd462a3dd999a0edbefc]
# 
# patch "sys/dev/usb/usb_subr.c"
#  from [63bcf87e6307cfe6a160d758cbad25c5beca0e5a]
#    to [1c50f60faf4aab5a6e0691593dac531e3ec57d6b]
# 
# patch "sys/dev/usb/usbdivar.h"
#  from [60305dd33cce54cd0c77c04055bb1c430aa6c144]
#    to [47ddf7be41c53c0b7df50a75de711a7831058646]
#
============================================================
--- sys/dev/usb/files.usb       f8965efae43fae946f88304cc9ab9bf6331cb4ae
+++ sys/dev/usb/files.usb       e9b86c319bb1e13ab65518db14c12285c4b001bc
@@ -11,6 +11,8 @@ define        usbifif { [port = -1], [configura
                   [vendor = -1], [product = -1], [release = -1] }
 define usbifif { [port = -1], [configuration = -1], [interface = -1],
                  [vendor = -1], [product = -1], [release = -1] }
+define usbfif { [port = -1], [configuration = -1], [interface = -1],
+                [vendor = -1], [product = -1], [release = -1] }
 
 device usb: usbroothubif
 attach usb at usbus
@@ -20,9 +22,10 @@ file dev/usb/usb_quirks.c            usb
 file   dev/usb/usb_mem.c               usb
 file   dev/usb/usb_subr.c              usb
 file   dev/usb/usb_quirks.c            usb
+file   dev/usb/usb_functions.c         usb
 
 # Hub driver
-device uhub: usbdevif, usbifif
+device uhub: usbdevif, usbifif, usbfif
 attach uhub at usbroothubif with uroothub
 attach uhub at usbdevif
 file   dev/usb/uhub.c                  usb
============================================================
--- sys/dev/usb/usb.h   4a00b4b553426a4992979e04792911044710560b
+++ sys/dev/usb/usb.h   944759b51fefe5d2fcacbd462a3dd999a0edbefc
@@ -388,6 +388,9 @@ typedef struct {
 #define UDCLASS_WIRELESS       0xe0
 #define  UDSUBCLASS_RF         0x01
 #define   UDPROTO_BLUETOOTH    0x01
+#define UDCLASS_MISC           0xef
+#define  UDSUBCLASS_COMMON     0x02
+#define   UDPROTO_IAD          0x01
 #define UDCLASS_VENDOR         0xff
 
 /* Interface class codes */
============================================================
--- sys/dev/usb/usb_subr.c      63bcf87e6307cfe6a160d758cbad25c5beca0e5a
+++ sys/dev/usb/usb_subr.c      1c50f60faf4aab5a6e0691593dac531e3ec57d6b
@@ -932,6 +932,8 @@ usbd_probe_and_attach(device_ptr_t paren
                        return (USBD_NOMEM);
                dev->subdevlen = nifaces;
 
+               usb_attachfunctions(parent, dev, port);
+
                err = usbd_attachinterfaces(parent, dev, port);
 
                if (!dev->nifaces_claimed) {
============================================================
--- sys/dev/usb/usbdivar.h      60305dd33cce54cd0c77c04055bb1c430aa6c144
+++ sys/dev/usb/usbdivar.h      47ddf7be41c53c0b7df50a75de711a7831058646
@@ -246,6 +246,8 @@ void                usb_disconnect_port(struct usbd_po
 void           usb_transfer_complete(usbd_xfer_handle);
 void           usb_disconnect_port(struct usbd_port *, device_ptr_t);
 
+usbd_status usb_attachfunctions(device_t, usbd_device_handle, int);
+
 /* Routines from usb.c */
 void           usb_needs_explore(usbd_device_handle);
 void           usb_needs_reattach(usbd_device_handle);


Home | Main Index | Thread Index | Old Index