Пример #1
0
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;
    }
}
Пример #2
0
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);
}
Пример #3
0
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));
}
Пример #4
0
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;
}
Пример #5
0
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]));
	}
}
Пример #6
0
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;
}
Пример #7
0
/* Handle delayed events. */
static void
ubsa_notify(void *arg)
{
	struct ubsa_softc *sc;

	sc = arg;
	ucom_status_change(&sc->sc_ucom);
}
Пример #8
0
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);
}
Пример #9
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);
}
Пример #10
0
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);
}
Пример #11
0
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);
}
Пример #12
0
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;
	}
}
Пример #13
0
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);
}
Пример #14
0
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);
}
Пример #15
0
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);
}
Пример #16
0
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));
		}
	}
}
Пример #17
0
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);
}
Пример #18
0
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);
}
Пример #19
0
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);
}