void umodem_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct umodem_softc *sc = priv; u_char mstatus; if (usbd_is_dying(sc->sc_udev)) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_notify_pipe); return; } if (sc->sc_notify_buf.bmRequestType != UCDC_NOTIFICATION) { DPRINTF(("%s: unknown message type (%02x) on notify pipe\n", sc->sc_dev.dv_xname, sc->sc_notify_buf.bmRequestType)); return; } switch (sc->sc_notify_buf.bNotification) { case UCDC_N_SERIAL_STATE: /* * Set the serial state in ucom driver based on * the bits from the notify message */ if (UGETW(sc->sc_notify_buf.wLength) != 2) { printf("%s: Invalid notification length! (%d)\n", sc->sc_dev.dv_xname, UGETW(sc->sc_notify_buf.wLength)); break; } DPRINTF(("%s: notify bytes = %02x%02x\n", sc->sc_dev.dv_xname, sc->sc_notify_buf.data[0], sc->sc_notify_buf.data[1])); /* Currently, lsr is always zero. */ sc->sc_lsr = sc->sc_msr = 0; mstatus = sc->sc_notify_buf.data[0]; if (ISSET(mstatus, UCDC_N_SERIAL_RI)) sc->sc_msr |= UMSR_RI; if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) sc->sc_msr |= UMSR_DSR; if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) sc->sc_msr |= UMSR_DCD; ucom_status_change((struct ucom_softc *)sc->sc_subdev); break; default: DPRINTF(("%s: unknown notify message: %02x\n", sc->sc_dev.dv_xname, sc->sc_notify_buf.bNotification)); break; } }
void umct_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct umct_softc *sc = priv; u_char *buf = sc->sc_intr_buf; u_char mstatus; if (sc->sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } DPRINTF(("%s: umct status = MSR:%02x, LSR:%02x\n", sc->sc_dev.dv_xname, buf[0],buf[1])); sc->sc_lsr = sc->sc_msr = 0; mstatus = buf[0]; if (ISSET(mstatus, MSR_DSR)) sc->sc_msr |= UMSR_DSR; if (ISSET(mstatus, MSR_DCD)) sc->sc_msr |= UMSR_DCD; ucom_status_change((struct ucom_softc *)sc->sc_subdev); }
void uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct uplcom_softc *sc = priv; u_char *buf = sc->sc_intr_buf; u_char pstatus; if (sc->sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } DPRINTF(("%s: uplcom status = %02x\n", USBDEVNAME(sc->sc_dev), buf[8])); sc->sc_lsr = sc->sc_msr = 0; pstatus = buf[8]; if (ISSET(pstatus, RSAQ_STATUS_DSR)) sc->sc_msr |= UMSR_DSR; if (ISSET(pstatus, RSAQ_STATUS_DCD)) sc->sc_msr |= UMSR_DCD; ucom_status_change(device_private(sc->sc_subdev)); }
Static void uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count) { struct uftdi_softc *sc = vsc; u_char msr, lsr; DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc, portno, *count)); msr = FTDI_GET_MSR(*ptr); lsr = FTDI_GET_LSR(*ptr); #ifdef UFTDI_DEBUG if (*count != 2) DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]=" "0x%02x\n", sc, portno, *count, (*ptr)[2])); #endif if (sc->sc_msr != msr || (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) { DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) " "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr, lsr, sc->sc_lsr)); sc->sc_msr = msr; sc->sc_lsr = lsr; ucom_status_change(device_private(sc->sc_subdev[portno-1])); } /* Adjust buffer pointer to skip status prefix */ *ptr += 2; }
void ubsa_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct ubsa_softc *sc = priv; u_char *buf; int i; buf = sc->sc_intr_buf; if (sc->sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: ubsa_intr: abnormal status: %s\n", device_xname(sc->sc_dev), usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } /* incidentally, Belkin adapter status bits match UART 16550 bits */ sc->sc_lsr = buf[2]; sc->sc_msr = buf[3]; DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n", device_xname(sc->sc_dev), sc->sc_lsr, sc->sc_msr)); for (i = 0; i < sc->sc_numif; i++) { ucom_status_change(device_private(sc->sc_subdevs[i])); } }
void uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count) { struct uftdi_softc *sc = vsc; u_char msr, lsr; DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc, portno, *count)); msr = FTDI_GET_MSR(*ptr); lsr = FTDI_GET_LSR(*ptr); #ifdef UFTDI_DEBUG if (*count != 2) DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]=" "0x%02x\n", sc, portno, *count, (*ptr)[2])); #endif if (sc->sc_msr != msr || (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) { DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) " "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr, lsr, sc->sc_lsr)); sc->sc_msr = msr; sc->sc_lsr = lsr; ucom_status_change((struct ucom_softc *)sc->sc_subdev); } /* Pick up status and adjust data part. */ *ptr += 2; *count -= 2; }
/* Handle delayed events. */ static void ubsa_notify(void *arg) { struct ubsa_softc *sc; sc = arg; ucom_status_change(&sc->sc_ucom); }
static int ucom_open(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); int error; mtx_assert(sc->sc_mtx, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_GONE) { return (ENXIO); } if (sc->sc_flag & UCOM_FLAG_HL_READY) { /* already opened */ return (0); } DPRINTF("tp = %p\n", tp); if (sc->sc_callback->ucom_pre_open) { /* * give the lower layer a chance to disallow TTY open, for * example if the device is not present: */ error = (sc->sc_callback->ucom_pre_open) (sc); if (error) { return (error); } } sc->sc_flag |= UCOM_FLAG_HL_READY; /* Disable transfers */ sc->sc_flag &= ~UCOM_FLAG_GP_DATA; sc->sc_lsr = 0; sc->sc_msr = 0; sc->sc_mcr = 0; /* reset programmed line state */ sc->sc_pls_curr = 0; sc->sc_pls_set = 0; sc->sc_pls_clr = 0; ucom_queue_command(sc, ucom_cfg_open, NULL, &sc->sc_open_task[0].hdr, &sc->sc_open_task[1].hdr); /* Queue transfer enable command last */ ucom_queue_command(sc, ucom_cfg_start_transfers, NULL, &sc->sc_start_task[0].hdr, &sc->sc_start_task[1].hdr); ucom_modem(tp, SER_DTR | SER_RTS, 0); ucom_break(sc, 0); ucom_status_change(sc); return (0); }
static void uticom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct uticom_softc *sc = priv; u_char *buf = sc->sc_intr_buf; if (usbd_is_dying(sc->sc_udev)) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { DPRINTF(("%s: uticom_intr: int status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); return; } DPRINTF(("%s: uticom_intr: abnormal status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } if (!xfer->actlen) return; DPRINTF(("%s: xfer_length = %d\n", sc->sc_dev.dv_xname, xfer->actlen)); sc->sc_lsr = sc->sc_msr = 0; if (buf[0] == 0) { /* msr registers */ if (buf[1] & UTICOM_MCR_CTS) sc->sc_msr |= UMSR_CTS; if (buf[1] & UTICOM_MCR_DSR) sc->sc_msr |= UMSR_DSR; if (buf[1] & UTICOM_MCR_CD) sc->sc_msr |= UMSR_DCD; if (buf[1] & UTICOM_MCR_RI) sc->sc_msr |= UMSR_RI; } else { /* lsr registers */ if (buf[0] & UTICOM_LCR_OVR) sc->sc_lsr |= ULSR_OE; if (buf[0] & UTICOM_LCR_PTE) sc->sc_lsr |= ULSR_PE; if (buf[0] & UTICOM_LCR_FRE) sc->sc_lsr |= ULSR_FE; if (buf[0] & UTICOM_LCR_BRK) sc->sc_lsr |= ULSR_BI; } // if (uticomstickdsr) // sc->sc_msr |= UMSR_DSR; ucom_status_change((struct ucom_softc *)sc->sc_subdev); }
Static void umct_notify(void *arg) { struct umct_softc *sc; sc = (struct umct_softc *)arg; if (sc->sc_ucom.sc_dying == 0) ucom_status_change(&sc->sc_ucom); }
static void uplcom_notify(void *arg, int count) { struct uplcom_softc *sc; sc = (struct uplcom_softc *)arg; if (sc->sc_ucom.sc_dying) return; ucom_status_change(&sc->sc_ucom); }
static void uhso_bs_intr_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhso_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; int actlen; struct usb_cdc_notification cdc; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (actlen < UCDC_NOTIFICATION_LENGTH) { UHSO_DPRINTF(0, "UCDC notification too short: %d\n", actlen); goto tr_setup; } else if (actlen > (int)sizeof(struct usb_cdc_notification)) { UHSO_DPRINTF(0, "UCDC notification too large: %d\n", actlen); actlen = sizeof(struct usb_cdc_notification); } pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, &cdc, actlen); if (UGETW(cdc.wIndex) != sc->sc_iface_no) { UHSO_DPRINTF(0, "Interface mismatch, got %d expected %d\n", UGETW(cdc.wIndex), sc->sc_iface_no); goto tr_setup; } if (cdc.bmRequestType == UCDC_NOTIFICATION && cdc.bNotification == UCDC_N_SERIAL_STATE) { UHSO_DPRINTF(2, "notify = 0x%02x\n", cdc.data[0]); sc->sc_msr = 0; sc->sc_lsr = 0; if (cdc.data[0] & UCDC_N_SERIAL_RI) sc->sc_msr |= SER_RI; if (cdc.data[0] & UCDC_N_SERIAL_DSR) sc->sc_msr |= SER_DSR; if (cdc.data[0] & UCDC_N_SERIAL_DCD) sc->sc_msr |= SER_DCD; ucom_status_change(&sc->sc_ucom[0]); } case USB_ST_SETUP: tr_setup: default: if (error == USB_ERR_CANCELLED) break; usbd_xfer_set_stall(xfer); goto tr_setup; } }
void ubsa_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct ubsa_softc *sc = priv; u_char *buf; struct usb_cdc_notification *cdcbuf; buf = sc->sc_intr_buf; cdcbuf = (struct usb_cdc_notification *)sc->sc_intr_buf; if (usbd_is_dying(sc->sc_udev)) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: ubsa_intr: abnormal status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } #if 1 /* test */ if (cdcbuf->bmRequestType == UCDC_NOTIFICATION) { printf("%s: this device is using CDC notify message in" " intr pipe.\n" "Please send your dmesg to <*****@*****.**>, thanks.\n", sc->sc_dev.dv_xname); printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", sc->sc_dev.dv_xname, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); /* check the buffer data */ if (cdcbuf->bNotification == UCDC_N_SERIAL_STATE) printf("%s:notify serial state, len=%d, data=0x%02x\n", sc->sc_dev.dv_xname, UGETW(cdcbuf->wLength), cdcbuf->data[0]); } #endif /* incidentally, Belkin adapter status bits match UART 16550 bits */ sc->sc_lsr = buf[2]; sc->sc_msr = buf[3]; DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n", sc->sc_dev.dv_xname, sc->sc_lsr, sc->sc_msr)); ucom_status_change((struct ucom_softc *)sc->sc_subdev); }
static void ugensa_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct ugensa_softc *sc = priv; usb_cdc_notification_t *buf; u_char mstatus; buf = (usb_cdc_notification_t *)sc->sc_intr_buf; if (sc->sc_ucom.sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; device_printf(sc->sc_ucom.sc_dev, "ugensa_intr: abnormal status: %s\n", usbd_errstr(status)); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } if (buf->bmRequestType != UCDC_NOTIFICATION) { DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n", sc->sc_dev.dv_xname, buf->bmRequestType)); return; } if (buf->bNotification == UCDC_N_SERIAL_STATE) { /* invalid message length, discard it */ if (UGETW(buf->wLength) != 2) return; /* XXX: sc_lsr is always 0 */ sc->sc_lsr = sc->sc_msr = 0; mstatus = buf->data[0]; if (ISSET(mstatus, UCDC_N_SERIAL_RI)) sc->sc_msr |= UMSR_RI; if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) sc->sc_msr |= UMSR_DSR; if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) sc->sc_msr |= UMSR_DCD; } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) { DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n", sc->sc_dev.dv_xname, buf->bNotification)); return; } ucom_status_change(&sc->sc_ucom); }
Static void uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct uvscom_softc *sc = priv; u_char *buf = sc->sc_intr_buf; u_char pstatus; if (sc->sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; printf("%s: uvscom_intr: abnormal status: %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(status)); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } DPRINTFN(2, ("%s: uvscom status = %02x %02x\n", USBDEVNAME(sc->sc_dev), buf[0], buf[1])); sc->sc_lsr = sc->sc_msr = 0; sc->sc_usr = buf[1]; pstatus = buf[0]; if (ISSET(pstatus, UVSCOM_TXRDY)) SET(sc->sc_lsr, ULSR_TXRDY); if (ISSET(pstatus, UVSCOM_RXRDY)) SET(sc->sc_lsr, ULSR_RXRDY); pstatus = buf[1]; if (ISSET(pstatus, UVSCOM_CTS)) SET(sc->sc_msr, UMSR_CTS); if (ISSET(pstatus, UVSCOM_DSR)) SET(sc->sc_msr, UMSR_DSR); if (ISSET(pstatus, UVSCOM_DCD)) SET(sc->sc_msr, UMSR_DCD); ucom_status_change((struct ucom_softc *) sc->sc_subdev); }
static void u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct u3g_softc *sc = (struct u3g_softc *)priv; u_char *buf; if (sc->sc_dying) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } buf = sc->sc_intr_buff; if (buf[0] == 0xa1 && buf[1] == 0x20) { u_char msr; msr = sc->sc_msr & ~(UMSR_DCD | UMSR_DSR | UMSR_RI); if (buf[8] & U3G_INPIN_DCD) msr |= UMSR_DCD; if (buf[8] & U3G_INPIN_DSR) msr |= UMSR_DSR; if (buf[8] & U3G_INPIN_RI) msr |= UMSR_RI; if (msr != sc->sc_msr) { sc->sc_msr = msr; if (sc->sc_open) ucom_status_change(device_private(sc->sc_ucom)); } } }
int ucomopen(dev_t dev, int flag, int mode, struct proc *p) { int unit = UCOMUNIT(dev); usbd_status err; struct ucom_softc *sc; struct tty *tp; struct termios t; int s; int error; if (unit >= ucom_cd.cd_ndevs) return (ENXIO); sc = ucom_cd.cd_devs[unit]; if (sc == NULL) return (ENXIO); if (sc->sc_dying) return (EIO); if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0) return (ENXIO); /* open the pipes if this is the first open */ ucom_lock(sc); if (sc->sc_open++ == 0) { s = splusb(); DPRINTF(("ucomopen: open pipes in=%d out=%d\n", sc->sc_bulkin_no, sc->sc_bulkout_no)); DPRINTF(("ucomopen: hid %p pipes in=%p out=%p\n", sc->sc_uhidev, sc->sc_ipipe, sc->sc_opipe)); if (sc->sc_bulkin_no != -1) { /* Open the bulk pipes */ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0, &sc->sc_bulkin_pipe); if (err) { DPRINTF(("%s: open bulk out error (addr %d), err=%s\n", sc->sc_dev.dv_xname, sc->sc_bulkin_no, usbd_errstr(err))); error = EIO; goto fail_0; } err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no, USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); if (err) { DPRINTF(("%s: open bulk in error (addr %d), err=%s\n", sc->sc_dev.dv_xname, sc->sc_bulkout_no, usbd_errstr(err))); error = EIO; goto fail_1; } /* Allocate a request and an input buffer and start reading. */ sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev); if (sc->sc_ixfer == NULL) { error = ENOMEM; goto fail_2; } sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer, sc->sc_ibufsizepad); if (sc->sc_ibuf == NULL) { error = ENOMEM; goto fail_2; } sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); if (sc->sc_oxfer == NULL) { error = ENOMEM; goto fail_3; } } else { /* * input/output pipes and xfers already allocated * as is the input buffer. */ sc->sc_ipipe = sc->sc_uhidev->sc_ipipe; sc->sc_ixfer = sc->sc_uhidev->sc_ixfer; sc->sc_opipe = sc->sc_uhidev->sc_opipe; sc->sc_oxfer = sc->sc_uhidev->sc_oxfer; } sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer, sc->sc_obufsize + sc->sc_opkthdrlen); if (sc->sc_obuf == NULL) { error = ENOMEM; goto fail_4; } if (sc->sc_methods->ucom_open != NULL) { error = sc->sc_methods->ucom_open(sc->sc_parent, sc->sc_portno); if (error) { ucom_cleanup(sc); splx(s); ucom_unlock(sc); return (error); } } ucom_status_change(sc); ucomstartread(sc); splx(s); } ucom_unlock(sc); s = spltty(); tp = sc->sc_tty; splx(s); DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp)); tp->t_dev = dev; if (!ISSET(tp->t_state, TS_ISOPEN)) { SET(tp->t_state, TS_WOPEN); ttychars(tp); /* * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ t.c_ispeed = 0; t.c_ospeed = TTYDEF_SPEED; t.c_cflag = TTYDEF_CFLAG; if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) SET(t.c_cflag, CRTSCTS); if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) SET(t.c_cflag, MDMBUF); /* Make sure ucomparam() will do something. */ tp->t_ospeed = 0; (void) ucomparam(tp, &t); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; s = spltty(); ttsetwater(tp); /* * Turn on DTR. We must always do this, even if carrier is not * present, because otherwise we'd have to use TIOCSDTR * immediately after setting CLOCAL, which applications do not * expect. We always assert DTR while the device is open * unless explicitly requested to deassert it. */ ucom_dtr(sc, 1); /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/ ucom_hwiflow(sc); if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || UCOMCUA(dev) || ISSET(sc->sc_msr, UMSR_DCD) || ISSET(tp->t_cflag, MDMBUF)) SET(tp->t_state, TS_CARR_ON); else CLR(tp->t_state, TS_CARR_ON); } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) { error = EBUSY; goto bad; } else s = spltty(); if (UCOMCUA(dev)) { if (ISSET(tp->t_state, TS_ISOPEN)) { /* Someone is already dialed in */ error = EBUSY; goto bad1; } sc->sc_cua = 1; } else { /* tty (not cua) device, wait for carrier */ if (ISSET(flag, O_NONBLOCK)) { if (sc->sc_cua) { error = EBUSY; goto bad1; } } else { while (sc->sc_cua || (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) { SET(tp->t_state, TS_WOPEN); error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0); /* * If TS_WOPEN has been reset, that means the * cua device has been closed. We don't want * to fail in that case, so just go around * again. */ if (error && ISSET(tp->t_state, TS_WOPEN)) { CLR(tp->t_state, TS_WOPEN); goto bad1; } } } } splx(s); error = ttyopen(UCOMUNIT(dev), tp); if (error) goto bad; error = (*LINESW(tp, l_open))(dev, tp); if (error) goto bad; return (0); fail_4: if (sc->sc_uhidev == NULL) usbd_free_xfer(sc->sc_oxfer); sc->sc_oxfer = NULL; fail_3: usbd_free_xfer(sc->sc_ixfer); sc->sc_ixfer = NULL; fail_2: usbd_close_pipe(sc->sc_bulkout_pipe); sc->sc_bulkout_pipe = NULL; fail_1: usbd_close_pipe(sc->sc_bulkin_pipe); sc->sc_bulkin_pipe = NULL; fail_0: splx(s); ucom_unlock(sc); return (error); bad1: splx(s); bad: ucom_lock(sc); ucom_cleanup(sc); ucom_unlock(sc); return (error); }
int ucomopen(dev_t dev, int flag, int mode, struct lwp *l) { int unit = UCOMUNIT(dev); usbd_status err; struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit); struct ucom_buffer *ub; struct tty *tp; int s, i; int error; if (sc == NULL) return (ENXIO); if (sc->sc_dying) return (EIO); if (!device_is_active(sc->sc_dev)) return (ENXIO); tp = sc->sc_tty; DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp)); if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) return (EBUSY); s = spltty(); /* * Do the following iff this is a first open. */ while (sc->sc_opening) tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0); if (sc->sc_dying) { splx(s); return (EIO); } sc->sc_opening = 1; if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { struct termios t; tp->t_dev = dev; if (sc->sc_methods->ucom_open != NULL) { error = sc->sc_methods->ucom_open(sc->sc_parent, sc->sc_portno); if (error) { ucom_cleanup(sc); sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); return (error); } } ucom_status_change(sc); /* * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ t.c_ispeed = 0; t.c_ospeed = TTYDEF_SPEED; t.c_cflag = TTYDEF_CFLAG; if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) SET(t.c_cflag, CRTSCTS); if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) SET(t.c_cflag, MDMBUF); /* Make sure ucomparam() will do something. */ tp->t_ospeed = 0; (void) ucomparam(tp, &t); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; ttychars(tp); ttsetwater(tp); /* * Turn on DTR. We must always do this, even if carrier is not * present, because otherwise we'd have to use TIOCSDTR * immediately after setting CLOCAL, which applications do not * expect. We always assert DTR while the device is open * unless explicitly requested to deassert it. Ditto RTS. */ ucom_dtr(sc, 1); ucom_rts(sc, 1); DPRINTF(("ucomopen: open pipes in=%d out=%d\n", sc->sc_bulkin_no, sc->sc_bulkout_no)); /* Open the bulk pipes */ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe); if (err) { DPRINTF(("%s: open bulk in error (addr %d), err=%s\n", USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no, usbd_errstr(err))); error = EIO; goto fail_0; } err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no, USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); if (err) { DPRINTF(("%s: open bulk out error (addr %d), err=%s\n", USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no, usbd_errstr(err))); error = EIO; goto fail_1; } sc->sc_rx_unblock = 0; sc->sc_rx_stopped = 0; sc->sc_tx_stopped = 0; memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff)); memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff)); SIMPLEQ_INIT(&sc->sc_ibuff_empty); SIMPLEQ_INIT(&sc->sc_ibuff_full); SIMPLEQ_INIT(&sc->sc_obuff_free); SIMPLEQ_INIT(&sc->sc_obuff_full); /* Allocate input buffers */ for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) { ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev); if (ub->ub_xfer == NULL) { error = ENOMEM; goto fail_2; } ub->ub_data = usbd_alloc_buffer(ub->ub_xfer, sc->sc_ibufsizepad); if (ub->ub_data == NULL) { error = ENOMEM; goto fail_2; } if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) { error = EIO; goto fail_2; } } for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS]; ub++) { ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev); if (ub->ub_xfer == NULL) { error = ENOMEM; goto fail_2; } ub->ub_data = usbd_alloc_buffer(ub->ub_xfer, sc->sc_obufsize); if (ub->ub_data == NULL) { error = ENOMEM; goto fail_2; } SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link); } } sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); if (error) goto bad; error = (*tp->t_linesw->l_open)(dev, tp); if (error) goto bad; return (0); fail_2: usbd_abort_pipe(sc->sc_bulkin_pipe); for (i = 0; i < UCOM_IN_BUFFS; i++) { if (sc->sc_ibuff[i].ub_xfer != NULL) { usbd_free_xfer(sc->sc_ibuff[i].ub_xfer); sc->sc_ibuff[i].ub_xfer = NULL; sc->sc_ibuff[i].ub_data = NULL; } } usbd_abort_pipe(sc->sc_bulkout_pipe); for (i = 0; i < UCOM_OUT_BUFFS; i++) { if (sc->sc_obuff[i].ub_xfer != NULL) { usbd_free_xfer(sc->sc_obuff[i].ub_xfer); sc->sc_obuff[i].ub_xfer = NULL; sc->sc_obuff[i].ub_data = NULL; } } usbd_close_pipe(sc->sc_bulkout_pipe); sc->sc_bulkout_pipe = NULL; fail_1: usbd_close_pipe(sc->sc_bulkin_pipe); sc->sc_bulkin_pipe = NULL; fail_0: sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); return (error); bad: s = spltty(); CLR(tp->t_state, TS_BUSY); if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { /* * We failed to open the device, and nobody else had it opened. * Clean up the state as appropriate. */ ucom_cleanup(sc); } splx(s); return (error); }
void umsm_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct umsm_softc *sc = priv; struct usb_cdc_notification *buf; u_char mstatus; buf = (struct usb_cdc_notification *)sc->sc_intr_buf; if (usbd_is_dying(sc->sc_udev)) return; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) return; DPRINTF(("%s: umsm_intr: abnormal status: %s\n", sc->sc_dev.dv_xname, usbd_errstr(status))); usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); return; } if (buf->bmRequestType != UCDC_NOTIFICATION) { #if 1 /* test */ printf("%s: this device is not using CDC notify message in intr pipe.\n" "Please send your dmesg to <*****@*****.**>, thanks.\n", sc->sc_dev.dv_xname); printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", sc->sc_dev.dv_xname, sc->sc_intr_buf[0], sc->sc_intr_buf[1], sc->sc_intr_buf[2], sc->sc_intr_buf[3], sc->sc_intr_buf[4], sc->sc_intr_buf[5], sc->sc_intr_buf[6]); #else DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n", sc->sc_dev.dv_xname, buf->bmRequestType)); #endif return; } if (buf->bNotification == UCDC_N_SERIAL_STATE) { /* invalid message length, discard it */ if (UGETW(buf->wLength) != 2) return; /* XXX: sc_lsr is always 0 */ sc->sc_lsr = sc->sc_msr = 0; mstatus = buf->data[0]; if (ISSET(mstatus, UCDC_N_SERIAL_RI)) sc->sc_msr |= UMSR_RI; if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) sc->sc_msr |= UMSR_DSR; if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) sc->sc_msr |= UMSR_DCD; } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) { DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n", sc->sc_dev.dv_xname, buf->bNotification)); return; } ucom_status_change((struct ucom_softc *)sc->sc_subdev); }