summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ulpt.c123
1 files changed, 122 insertions, 1 deletions
diff --git a/sys/dev/usb/ulpt.c b/sys/dev/usb/ulpt.c
index 727e5a87bae..61a62f1f3cd 100644
--- a/sys/dev/usb/ulpt.c
+++ b/sys/dev/usb/ulpt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ulpt.c,v 1.40 2011/09/17 08:36:06 miod Exp $ */
+/* $OpenBSD: ulpt.c,v 1.41 2013/01/28 17:15:31 stsp Exp $ */
/* $NetBSD: ulpt.c,v 1.57 2003/01/05 10:19:42 scw Exp $ */
/* $FreeBSD: src/sys/dev/usb/ulpt.c,v 1.24 1999/11/17 22:33:44 n_hibma Exp $ */
@@ -46,6 +46,8 @@
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -103,6 +105,8 @@ struct ulpt_softc {
int sc_refcnt;
u_char sc_dying;
+
+ struct ulpt_fwdev *sc_fwdev;
};
void ulpt_disco(void *);
@@ -112,6 +116,38 @@ int ulpt_status(struct ulpt_softc *);
void ulpt_reset(struct ulpt_softc *);
int ulpt_statusmsg(u_char, struct ulpt_softc *);
+/*
+ * Printers which need firmware uploads.
+ */
+void ulpt_load_firmware(void *);
+usbd_status ulpt_ucode_loader_hp(struct ulpt_softc *);
+struct ulpt_fwdev {
+ struct usb_devno uv_dev;
+ char *ucode_name;
+ usbd_status (*ucode_loader)(struct ulpt_softc *);
+} ulpt_fwdevs[] = {
+ {
+ { USB_VENDOR_HP, USB_PRODUCT_HP_1000 },
+ "ulpt-hp1000",
+ ulpt_ucode_loader_hp
+ },
+ {
+ { USB_VENDOR_HP, USB_PRODUCT_HP_1005 },
+ "ulpt-hp1005",
+ ulpt_ucode_loader_hp
+ },
+ {
+ { USB_VENDOR_HP, USB_PRODUCT_HP_1018 },
+ "ulpt-hp1018",
+ ulpt_ucode_loader_hp
+ },
+ {
+ { USB_VENDOR_HP, USB_PRODUCT_HP_1020 },
+ "ulpt-hp1020",
+ ulpt_ucode_loader_hp
+ },
+};
+
#if 0
void ieee1284_print_id(char *);
#endif
@@ -158,6 +194,21 @@ ulpt_match(struct device *parent, void *match, void *aux)
}
void
+ulpt_load_firmware(void *arg)
+{
+ struct ulpt_softc *sc = (struct ulpt_softc *)arg;
+ usbd_status err;
+
+ err = (sc->sc_fwdev->ucode_loader)(sc);
+ if (err != USBD_NORMAL_COMPLETION)
+ printf("%s: could not load firmware '%s'\n",
+ sc->sc_dev.dv_xname, sc->sc_fwdev->ucode_name);
+}
+
+#define ulpt_lookup(v, p) \
+ ((struct ulpt_fwdev *)usb_lookup(ulpt_fwdevs, v, p))
+
+void
ulpt_attach(struct device *parent, struct device *self, void *aux)
{
struct ulpt_softc *sc = (struct ulpt_softc *)self;
@@ -262,6 +313,15 @@ ulpt_attach(struct device *parent, struct device *self, void *aux)
sc->sc_ifaceno = id->bInterfaceNumber;
sc->sc_udev = dev;
+ /* maybe the device needs firmware */
+ sc->sc_fwdev = ulpt_lookup(uaa->vendor, uaa->product);
+ if (sc->sc_fwdev) {
+ if (rootvp == NULL)
+ mountroothook_establish(ulpt_load_firmware, sc);
+ else
+ ulpt_load_firmware(sc);
+ }
+
#if 0
/*
* This code is disabled because for some mysterious reason it causes
@@ -608,6 +668,67 @@ ulptwrite(dev_t dev, struct uio *uio, int flags)
return (error);
}
+usbd_status
+ulpt_ucode_loader_hp(struct ulpt_softc *sc)
+{
+ usbd_status error;
+ int load_error;
+ uint8_t *ucode;
+ uint32_t len;
+ size_t ucode_size;
+ const char *ucode_name = sc->sc_fwdev->ucode_name;
+ int offset = 0, remain;
+ usbd_xfer_handle xfer;
+ void *bufp;
+
+ /* open microcode file */
+ load_error = loadfirmware(ucode_name, &ucode, &ucode_size);
+ if (load_error != 0) {
+ printf("%s: failed loadfirmware of file %s (error %d)\n",
+ sc->sc_dev.dv_xname, ucode_name, load_error);
+ return (USBD_INVAL);
+ }
+
+ /* upload microcode */
+ error = usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe);
+ if (error)
+ goto free_ucode;
+ xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (xfer == NULL)
+ goto close_pipe;
+ bufp = usbd_alloc_buffer(xfer, ULPT_BSIZE);
+ if (bufp == NULL) {
+ error = USBD_NOMEM;
+ goto free_xfer;
+ }
+ remain = ucode_size;
+ while (remain > 0) {
+ len = min(remain, ULPT_BSIZE);
+ memcpy(bufp, &ucode[offset], len);
+ error = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY,
+ USBD_NO_TIMEOUT, bufp, &len, "ulptwr");
+ if (error != USBD_NORMAL_COMPLETION) {
+ printf("%s: ucode upload error=%s!\n",
+ sc->sc_dev.dv_xname, usbd_errstr(error));
+ break;
+ }
+ DPRINTF(("%s: uploaded %d bytes ucode\n",
+ sc->sc_dev.dv_xname, len));
+
+ offset += len;
+ remain -= len;
+ }
+free_xfer:
+ usbd_free_xfer(xfer);
+close_pipe:
+ usbd_close_pipe(sc->sc_out_pipe);
+ sc->sc_out_pipe = NULL;
+free_ucode:
+ free(ucode, M_DEVBUF);
+
+ return (error);
+}
+
#if 0
/* XXX This does not belong here. */
/*