summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormglocker <mglocker@openbsd.org>2008-12-08 18:33:24 +0000
committermglocker <mglocker@openbsd.org>2008-12-08 18:33:24 +0000
commit781a5db6ffd0ea41beeed3cc1b27c29b904be963 (patch)
treea1b942c3d2c3e2d8c56b85f3a69cb35fcb076d28
parentDo not short circuit pseudo commands when we get a match since, depending (diff)
downloadwireguard-openbsd-781a5db6ffd0ea41beeed3cc1b27c29b904be963.tar.xz
wireguard-openbsd-781a5db6ffd0ea41beeed3cc1b27c29b904be963.zip
Add ability to load firmware for devices which require it.
Tested by deraadt@ and myself.
-rw-r--r--sys/dev/usb/uvideo.c155
-rw-r--r--sys/dev/usb/uvideo.h6
2 files changed, 159 insertions, 2 deletions
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index ed3189bb676..3f79cf0cffa 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.100 2008/12/06 20:06:39 mglocker Exp $ */
+/* $OpenBSD: uvideo.c,v 1.101 2008/12/08 18:33:24 mglocker Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -64,6 +64,7 @@ int uvideo_open(void *, int, int *, uint8_t *, void (*)(void *),
int uvideo_close(void *);
int uvideo_match(struct device *, void *, void *);
void uvideo_attach(struct device *, struct device *, void *);
+void uvideo_attach_hook(void *);
int uvideo_detach(struct device *, int);
int uvideo_activate(struct device *, enum devact);
@@ -190,6 +191,13 @@ caddr_t uvideo_mappage(void *, off_t, int);
int uvideo_get_bufsize(void *);
int uvideo_start_read(void *);
+/*
+ * Firmware
+ */
+int uvideo_ucode_match(struct uvideo_softc *,
+ struct usb_attach_arg *);
+usbd_status uvideo_ucode_loader_ricoh(struct uvideo_softc *);
+
struct cfdriver uvideo_cd = {
NULL, "uvideo", DV_DULL
};
@@ -228,6 +236,21 @@ struct video_hw_if uvideo_hw_if = {
uvideo_start_read /* start stream for read */
};
+struct uvideo_ucode {
+ int vendor;
+ int product;
+ char ucode_name[64];
+ usbd_status (*ucode_loader)(struct uvideo_softc *);
+} uvideo_ucode_devs[] = {
+ {
+ USB_VENDOR_RICOH,
+ USB_PRODUCT_RICOH_VGPVCC7,
+ "r5u87x-05ca-183a.fw",
+ uvideo_ucode_loader_ricoh
+ },
+ { 0, 0, "", NULL }
+};
+
/*
* Some devices do not report themselfs as UVC compatible although
* they are. They report UICLASS_VENDOR in the bInterfaceClass
@@ -373,6 +396,27 @@ uvideo_attach(struct device *parent, struct device *self, void *aux)
if (error != USBD_NORMAL_COMPLETION)
return;
+ /* if the device needs ucode do mountroothook */
+ sc->sc_flags |= uvideo_ucode_match(sc, uaa);
+
+ if (sc->sc_flags & UVIDEO_FLAGS_NEED_UCODE && rootvp == NULL)
+ mountroothook_establish(uvideo_attach_hook, sc);
+ else
+ uvideo_attach_hook(sc);
+}
+
+void
+uvideo_attach_hook(void *arg)
+{
+ struct uvideo_softc *sc = arg;
+ usbd_status error;
+
+ if (sc->sc_flags & UVIDEO_FLAGS_NEED_UCODE) {
+ error = (sc->sc_ucode->ucode_loader)(sc);
+ if (error != USBD_NORMAL_COMPLETION)
+ return;
+ }
+
/* set default video stream interface */
error = usbd_set_interface(sc->sc_vs_cur->ifaceh, 0);
if (error != USBD_NORMAL_COMPLETION)
@@ -2968,3 +3012,112 @@ uvideo_start_read(void *v)
return (0);
}
+
+int
+uvideo_ucode_match(struct uvideo_softc *sc, struct usb_attach_arg *uaa)
+{
+ usb_device_descriptor_t *dd;
+ int i;
+
+ dd = usbd_get_device_descriptor(uaa->device);
+
+ for (i = 0; uvideo_ucode_devs[i].vendor != 0; i++) {
+ if (UGETW(dd->idVendor) == uvideo_ucode_devs[i].vendor &&
+ UGETW(dd->idProduct) == uvideo_ucode_devs[i].product) {
+ sc->sc_ucode = &uvideo_ucode_devs[i];
+ return (UVIDEO_FLAGS_NEED_UCODE);
+ }
+ }
+
+ return (0);
+}
+
+usbd_status
+uvideo_ucode_loader_ricoh(struct uvideo_softc *sc)
+{
+ usb_device_request_t req;
+ usbd_status error;
+ uint8_t *ucode;
+ size_t ucode_size;
+ uint8_t buf;
+ uint16_t len, addr;
+ int offset, remain;
+
+ /* get device microcode status */
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = 0xa4;
+ USETW(req.wIndex, 0);
+ USETW(req.wValue, 0);
+ USETW(req.wLength, 1);
+ buf = 0;
+ error = usbd_do_request(sc->sc_udev, &req, &buf);
+ if (error != USBD_NORMAL_COMPLETION) {
+ printf("%s: ucode status error=%s!\n",
+ DEVNAME(sc), usbd_errstr(error));
+ return (USBD_INVAL);
+ }
+ if (buf) {
+ DPRINTF(1, "%s: microcode already loaded\n", DEVNAME(sc));
+ return (USBD_NORMAL_COMPLETION);
+ } else {
+ DPRINTF(1, "%s: microcode not loaded\n", DEVNAME(sc));
+ }
+
+ /* open ucode file */
+ error = loadfirmware(sc->sc_ucode->ucode_name, &ucode, &ucode_size);
+ if (error != 0) {
+ printf("%s: loadfirmware error=%d!\n", DEVNAME(sc), error);
+ return (USBD_INVAL);
+ }
+
+ /* upload microcode */
+ offset = 0;
+ remain = ucode_size;
+ while (remain > 0) {
+ if (remain < 3) {
+ printf("%s: ucode file incomplete!\n", DEVNAME(sc));
+ return (USBD_INVAL);
+ }
+
+ len = ucode[offset];
+ addr = ucode[offset + 1] | (ucode[offset + 2] << 8);
+ offset += 3;
+ remain -= 3;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = 0xa0;
+ USETW(req.wIndex, 0);
+ USETW(req.wValue, addr);
+ USETW(req.wLength, len);
+ error = usbd_do_request(sc->sc_udev, &req, &ucode[offset]);
+ if (error != USBD_NORMAL_COMPLETION) {
+ printf("%s: ucode upload error=%s!\n",
+ DEVNAME(sc), usbd_errstr(error));
+ free(ucode, M_DEVBUF);
+ return (USBD_INVAL);
+ }
+ DPRINTF(1, "%s: uploaded %d bytes ucode to addr 0x%x\n",
+ DEVNAME(sc), len, addr);
+
+ offset += len;
+ remain -= len;
+ }
+ free(ucode, M_DEVBUF);
+
+ /* activate microcode */
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = 0xa1;
+ USETW(req.wIndex, 0);
+ USETW(req.wValue, 0);
+ USETW(req.wLength, 1);
+ buf = 0;
+ error = usbd_do_request(sc->sc_udev, &req, &buf);
+ if (error != USBD_NORMAL_COMPLETION) {
+ printf("%s: ucode activate error=%s!\n",
+ DEVNAME(sc), usbd_errstr(error));
+ return (USBD_INVAL);
+ }
+ DPRINTF(1, "%s: ucode activated\n", DEVNAME(sc));
+
+ return (USBD_NORMAL_COMPLETION);
+}
diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h
index d8fc68cd0e2..8e422eda018 100644
--- a/sys/dev/usb/uvideo.h
+++ b/sys/dev/usb/uvideo.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.h,v 1.39 2008/12/05 10:44:52 mglocker Exp $ */
+/* $OpenBSD: uvideo.h,v 1.40 2008/12/08 18:33:24 mglocker Exp $ */
/*
* Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
@@ -558,6 +558,8 @@ struct uvideo_softc {
struct device *sc_videodev;
+#define UVIDEO_FLAGS_NEED_UCODE 0x1
+ int sc_flags;
int sc_enabled;
int sc_dying;
int sc_max_fbuf_size;
@@ -599,4 +601,6 @@ struct uvideo_softc {
int *sc_uplayer_fsize;
uint8_t *sc_uplayer_fbuffer;
void (*sc_uplayer_intr)(void *);
+
+ struct uvideo_ucode *sc_ucode;
};