static int uftdi_send_data(uftdi_state_t *uf, mblk_t *data) { usb_bulk_req_t *br; int len = MBLKL(data); int rval; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_send_data: %d 0x%x 0x%x 0x%x", len, data->b_rptr[0], (len > 1) ? data->b_rptr[1] : 0, (len > 2) ? data->b_rptr[2] : 0); ASSERT(!mutex_owned(&uf->uf_lock)); br = usb_alloc_bulk_req(uf->uf_dip, 0, USB_FLAGS_SLEEP); br->bulk_data = data; br->bulk_len = len; br->bulk_timeout = UFTDI_BULKOUT_TIMEOUT; br->bulk_cb = uftdi_bulkout_cb; br->bulk_exc_cb = uftdi_bulkout_cb; br->bulk_client_private = (usb_opaque_t)uf; br->bulk_attributes = USB_ATTRS_AUTOCLEARING; rval = usb_pipe_bulk_xfer(uf->uf_bulkout_ph, br, 0); if (rval != USB_SUCCESS) { USB_DPRINTF_L2(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_send_data: xfer failed %d", rval); br->bulk_data = NULL; usb_free_bulk_req(br); } return (rval); }
/*ARGSUSED*/ static void uftdi_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) { uftdi_state_t *uf = (uftdi_state_t *)req->bulk_client_private; int data_len; mblk_t *data = req->bulk_data; data_len = data ? MBLKL(data) : 0; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_bulkout_cb: cr=%d len=%d", req->bulk_completion_reason, data_len); if (uf->uf_port_state == UFTDI_PORT_OPEN && req->bulk_completion_reason && data_len > 0) { uftdi_put_head(&uf->uf_tx_mp, data); req->bulk_data = NULL; } usb_free_bulk_req(req); /* notify GSD */ if (uf->uf_cb.cb_tx) uf->uf_cb.cb_tx(uf->uf_cb.cb_arg); /* send more */ mutex_enter(&uf->uf_lock); uf->uf_bulkout_state = UFTDI_PIPE_IDLE; if (uf->uf_tx_mp == NULL) cv_broadcast(&uf->uf_tx_cv); else uftdi_tx_start(uf, NULL); mutex_exit(&uf->uf_lock); }
/* * start receiving data */ static int uftdi_rx_start(uftdi_state_t *uf) { usb_bulk_req_t *br; int rval; USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_rx_start"); ASSERT(mutex_owned(&uf->uf_lock)); uf->uf_bulkin_state = UFTDI_PIPE_BUSY; mutex_exit(&uf->uf_lock); br = usb_alloc_bulk_req(uf->uf_dip, uf->uf_xfer_sz, USB_FLAGS_SLEEP); br->bulk_len = uf->uf_xfer_sz; br->bulk_timeout = UFTDI_BULKIN_TIMEOUT; br->bulk_cb = uftdi_bulkin_cb; br->bulk_exc_cb = uftdi_bulkin_cb; br->bulk_client_private = (usb_opaque_t)uf; br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK; rval = usb_pipe_bulk_xfer(uf->uf_bulkin_ph, br, 0); if (rval != USB_SUCCESS) { USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_rx_start: xfer failed %d", rval); usb_free_bulk_req(br); } mutex_enter(&uf->uf_lock); if (rval != USB_SUCCESS) uf->uf_bulkin_state = UFTDI_PIPE_IDLE; return (rval); }
void usba10_usb_free_bulk_req(usb_bulk_req_t *reqp) { usb_free_bulk_req(reqp); }
/*ARGSUSED*/ static void uftdi_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) { uftdi_state_t *uf = (uftdi_state_t *)req->bulk_client_private; mblk_t *data; int data_len; data = req->bulk_data; data_len = data ? MBLKL(data) : 0; /* * The first two bytes of data are status register bytes * that arrive with every packet from the device. Process * them here before handing the rest of the data on. * * When active, the device will send us these bytes at least * every 40 milliseconds, even if there's no received data. */ if (req->bulk_completion_reason == USB_CR_OK && data_len >= 2) { uint8_t msr = FTDI_GET_MSR(data->b_rptr); uint8_t lsr = FTDI_GET_LSR(data->b_rptr); int new_rx_err; data->b_rptr += 2; mutex_enter(&uf->uf_lock); if (uf->uf_msr != msr) { /* * modem status register changed */ USB_DPRINTF_L3(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_bulkin_cb: new msr: 0x%02x -> 0x%02x", uf->uf_msr, msr); uf->uf_msr = msr; if (uf->uf_port_state == UFTDI_PORT_OPEN && uf->uf_cb.cb_status) { mutex_exit(&uf->uf_lock); uf->uf_cb.cb_status(uf->uf_cb.cb_arg); mutex_enter(&uf->uf_lock); } } if ((uf->uf_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) { /* * line status register *receive* bits changed * * (The THRE and TEMT (transmit) status bits are * masked out above.) */ USB_DPRINTF_L3(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_bulkin_cb: new lsr: 0x%02x -> 0x%02x", uf->uf_lsr, lsr); new_rx_err = B_TRUE; } else new_rx_err = B_FALSE; uf->uf_lsr = lsr; /* THRE and TEMT captured here */ if ((lsr & FTDI_LSR_MASK) != 0 && (MBLKL(data) > 0 || new_rx_err) && uf->uf_port_state == UFTDI_PORT_OPEN) { /* * The current line status register value indicates * that there's been some sort of unusual condition * on the receive side. We either received a break, * or got some badly formed characters from the * serial port - framing errors, overrun, parity etc. * So there's either some new data to post, or a * new error (break) to post, or both. * * Invoke uftdi_rxerr_put() to place the inbound * characters as M_BREAK messages on the receive * mblk chain, decorated with error flag(s) for * upper-level modules (e.g. ldterm) to process. */ mutex_exit(&uf->uf_lock); uftdi_rxerr_put(&uf->uf_rx_mp, data, lsr); ASSERT(MBLKL(data) == 0); /* * Since we've converted all the received * characters into M_BREAK messages, we * invoke the rx callback to shove the mblks * up the STREAM. */ if (uf->uf_cb.cb_rx) uf->uf_cb.cb_rx(uf->uf_cb.cb_arg); mutex_enter(&uf->uf_lock); } mutex_exit(&uf->uf_lock); data_len = MBLKL(data); } USB_DPRINTF_L4(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_bulkin_cb: " "cr=%d len=%d", req->bulk_completion_reason, data_len); /* save data and notify GSD */ if (data_len > 0 && uf->uf_port_state == UFTDI_PORT_OPEN && req->bulk_completion_reason == USB_CR_OK) { req->bulk_data = NULL; uftdi_put_tail(&uf->uf_rx_mp, data); if (uf->uf_cb.cb_rx) uf->uf_cb.cb_rx(uf->uf_cb.cb_arg); } usb_free_bulk_req(req); /* receive more */ mutex_enter(&uf->uf_lock); uf->uf_bulkin_state = UFTDI_PIPE_IDLE; if (uf->uf_port_state == UFTDI_PORT_OPEN && uf->uf_dev_state == USB_DEV_ONLINE) { if (uftdi_rx_start(uf) != USB_SUCCESS) { USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh, "uftdi_bulkin_cb: restart rx fail"); } } mutex_exit(&uf->uf_lock); }