usbd_status uhidev_write(struct uhidev_softc *sc, void *data, int len) { DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); if (sc->sc_opipe == NULL) return USBD_INVAL; #ifdef UHIDEV_DEBUG if (uhidevdebug > 50) { u_int32_t i; u_int8_t *d = data; DPRINTF(("uhidev_write: data =")); for (i = 0; i < len; i++) DPRINTF((" %02x", d[i])); DPRINTF(("\n")); } #endif return usbd_intr_transfer(sc->sc_owxfer, sc->sc_opipe, 0, USBD_NO_TIMEOUT, data, &len, "uhidevwi"); }
/* ARGSUSED */ static int udsir_write(void *h, struct uio *uio, int flag) { struct udsir_softc *sc = h; usbd_status err; uint32_t wrlen; int error, sirlength; uint8_t *wrbuf; int s; DPRINTFN(1, ("%s: sc=%p\n", __func__, sc)); if (sc->sc_dying) return EIO; #ifdef DIAGNOSTIC if (sc->sc_wr_buf == NULL) return EINVAL; #endif wrlen = uio->uio_resid; if (wrlen > sc->sc_wr_maxpsz) return EINVAL; sc->sc_refcnt++; if (!UDSIR_BLOCK_RX_DATA(sc)) { /* * If reads are not blocked, determine what action we * should potentially take... */ if (sc->sc_direction == udir_output) { /* * If the last operation was an output, wait for the * polling thread to check for incoming data. */ sc->sc_wr_stalewrite = 1; wakeup(&sc->sc_thread); } else if (!sc->sc_rd_readinprogress && (sc->sc_direction == udir_idle || sc->sc_direction == udir_input)) { /* If idle, check for input before outputting */ udsir_start_read(sc); } } s = splusb(); while (sc->sc_wr_stalewrite || (sc->sc_direction != udir_output && sc->sc_direction != udir_idle)) { DPRINTFN(5, ("%s: sc=%p stalewrite=%d direction=%d, " "calling tsleep()\n", __func__, sc, sc->sc_wr_stalewrite, sc->sc_direction)); error = tsleep(&sc->sc_wr_buf, PZERO | PCATCH, "usirwr", 0); if (sc->sc_dying) error = EIO; if (error) { splx(s); DPRINTFN(0, ("%s: tsleep() = %d\n", __func__, error)); goto ret; } } splx(s); wrbuf = sc->sc_wr_buf; sirlength = irda_sir_frame(wrbuf, MAX_UDSIR_OUTPUT_FRAME, uio, sc->sc_params.ebofs); if (sirlength < 0) error = -sirlength; else { uint32_t btlen; DPRINTFN(1, ("%s: transfer %u bytes\n", __func__, (unsigned int)wrlen)); btlen = sirlength; sc->sc_direction = udir_output; #ifdef UDSIR_DEBUG if (udsirdebug >= 20) udsir_dumpdata(wrbuf, btlen, __func__); #endif err = usbd_intr_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe, USBD_FORCE_SHORT_XFER, UDSIR_WR_TIMEOUT, wrbuf, &btlen); DPRINTFN(2, ("%s: err=%d\n", __func__, err)); if (err != USBD_NORMAL_COMPLETION) { if (err == USBD_INTERRUPTED) error = EINTR; else if (err == USBD_TIMEOUT) error = ETIMEDOUT; else error = EIO; } else error = 0; } ret: if (--sc->sc_refcnt < 0) usb_detach_wakeupold(sc->sc_dev); DPRINTFN(1, ("%s: sc=%p done\n", __func__, sc)); return error; }
int uhidev_open(struct uhidev *scd) { struct uhidev_softc *sc = scd->sc_parent; usbd_status err; int error; DPRINTF(("uhidev_open: open pipe, state=%d\n", scd->sc_state)); mutex_enter(&sc->sc_lock); if (scd->sc_state & UHIDEV_OPEN) { mutex_exit(&sc->sc_lock); return EBUSY; } scd->sc_state |= UHIDEV_OPEN; if (sc->sc_refcnt++) { mutex_exit(&sc->sc_lock); return 0; } mutex_exit(&sc->sc_lock); if (sc->sc_isize == 0) return 0; sc->sc_ibuf = kmem_alloc(sc->sc_isize, KM_SLEEP); /* Set up input interrupt pipe. */ DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, sc->sc_iep_addr)); err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr, USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf, sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); if (err != USBD_NORMAL_COMPLETION) { DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " "error=%d\n", err)); error = EIO; goto out1; } /* * Set up output interrupt pipe if an output interrupt endpoint * exists. */ if (sc->sc_oep_addr != -1) { DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr)); err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr, 0, &sc->sc_opipe); if (err != USBD_NORMAL_COMPLETION) { DPRINTF(("uhidev_open: usbd_open_pipe failed, " "error=%d\n", err)); error = EIO; goto out2; } DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe)); error = usbd_create_xfer(sc->sc_opipe, UHIDEV_OSIZE, 0, 0, &sc->sc_oxfer); if (error) { DPRINTF(("uhidev_open: couldn't allocate an xfer\n")); goto out3; } if (sc->sc_flags & UHIDEV_F_XB1) { uint8_t init_data[] = { 0x05, 0x20 }; int init_data_len = sizeof(init_data); err = usbd_intr_transfer(sc->sc_oxfer, sc->sc_opipe, 0, USBD_NO_TIMEOUT, init_data, &init_data_len); if (err != USBD_NORMAL_COMPLETION) { DPRINTF(("uhidev_open: xb1 init failed, " "error=%d\n", err)); error = EIO; goto out4; } } } return 0; out4: /* Free output xfer */ if (sc->sc_oxfer != NULL) usbd_destroy_xfer(sc->sc_oxfer); out3: /* Abort output pipe */ usbd_close_pipe(sc->sc_opipe); out2: /* Abort input pipe */ usbd_close_pipe(sc->sc_ipipe); out1: DPRINTF(("uhidev_open: failed in someway")); kmem_free(sc->sc_ibuf, sc->sc_isize); mutex_enter(&sc->sc_lock); scd->sc_state &= ~UHIDEV_OPEN; sc->sc_refcnt = 0; sc->sc_ibuf = NULL; sc->sc_ipipe = NULL; sc->sc_opipe = NULL; sc->sc_oxfer = NULL; mutex_exit(&sc->sc_lock); return error; }