diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2014-10-19 16:35:54 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2014-10-19 16:35:54 +0000 |
commit | 074ae0085ab485f2c97ad19fff10dadd5cd811e7 (patch) | |
tree | 0002f99d03fb1ac5023440ef3783209b7b9a9246 /sys/dev/usb/ulpt.c | |
parent | 0364a80eb0ba914a8be6eb94a0e9d1c70f14bd74 (diff) |
More gracefully handle firmware loading errors in ulpt(4).
The previous lack of error handling could trigger a kernel crash
in some situations, with ulptwrite being called while not ready.
ok deraadt phessler
Diffstat (limited to 'sys/dev/usb/ulpt.c')
-rw-r--r-- | sys/dev/usb/ulpt.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/dev/usb/ulpt.c b/sys/dev/usb/ulpt.c index 436c0f9d77f..adbf23d2453 100644 --- a/sys/dev/usb/ulpt.c +++ b/sys/dev/usb/ulpt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ulpt.c,v 1.47 2014/07/12 20:26:33 mpi Exp $ */ +/* $OpenBSD: ulpt.c,v 1.48 2014/10/19 16:35:53 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 $ */ @@ -100,6 +100,7 @@ struct ulpt_softc { #define ULPT_INIT 0x04 /* waiting to initialize for open */ u_char sc_flags; #define ULPT_NOPRIME 0x40 /* don't prime on open */ +#define ULPT_EFIRMWARE 0x80 /* error loading firmware */ u_char sc_laststatus; int sc_refcnt; @@ -193,9 +194,12 @@ ulpt_load_firmware(void *arg) usbd_status err; err = (sc->sc_fwdev->ucode_loader)(sc); - if (err != USBD_NORMAL_COMPLETION) + if (err != USBD_NORMAL_COMPLETION) { + sc->sc_flags |= ULPT_EFIRMWARE; printf("%s: could not load firmware '%s'\n", sc->sc_dev.dv_xname, sc->sc_fwdev->ucode_name); + } else + sc->sc_flags &= ~ULPT_EFIRMWARE; } #define ulpt_lookup(v, p) \ @@ -469,6 +473,13 @@ ulptopen(dev_t dev, int flag, int mode, struct proc *p) if (sc->sc_state) return (EBUSY); + /* If a previous attempt to load firmware failed, retry. */ + if (sc->sc_flags & ULPT_EFIRMWARE) { + ulpt_load_firmware(sc); + if (sc->sc_flags & ULPT_EFIRMWARE) + return (EIO); + } + sc->sc_state = ULPT_INIT; sc->sc_flags = flags; DPRINTF(("ulptopen: flags=0x%x\n", (unsigned)flags)); @@ -640,7 +651,7 @@ ulptwrite(dev_t dev, struct uio *uio, int flags) sc = ulpt_cd.cd_devs[ULPTUNIT(dev)]; - if (usbd_is_dying(sc->sc_udev)) + if (usbd_is_dying(sc->sc_udev) || (sc->sc_flags & ULPT_EFIRMWARE)) return (EIO); sc->sc_refcnt++; |