Example #1
0
static int
ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
{
	struct usb_config usb_config[1];
	struct usb_device_request req;
	union {
		struct usb_fs_complete *pcomp;
		struct usb_fs_start *pstart;
		struct usb_fs_stop *pstop;
		struct usb_fs_open *popen;
		struct usb_fs_open_stream *popen_stream;
		struct usb_fs_close *pclose;
		struct usb_fs_clear_stall_sync *pstall;
		void   *addr;
	}     u;
	struct usb_endpoint *ep;
	struct usb_endpoint_descriptor *ed;
	struct usb_xfer *xfer;
	int error = 0;
	uint8_t iface_index;
	uint8_t isread;
	uint8_t ep_index;
	uint8_t pre_scale;

	u.addr = addr;

	DPRINTFN(6, "cmd=0x%08lx\n", cmd);

	switch (cmd) {
	case USB_FS_COMPLETE:
		mtx_lock(f->priv_mtx);
		error = ugen_fs_get_complete(f, &ep_index);
		mtx_unlock(f->priv_mtx);

		if (error) {
			error = EBUSY;
			break;
		}
		u.pcomp->ep_index = ep_index;
		error = ugen_fs_copy_out(f, u.pcomp->ep_index);
		break;

	case USB_FS_START:
		error = ugen_fs_copy_in(f, u.pstart->ep_index);
		if (error)
			break;
		mtx_lock(f->priv_mtx);
		xfer = f->fs_xfer[u.pstart->ep_index];
		usbd_transfer_start(xfer);
		mtx_unlock(f->priv_mtx);
		break;

	case USB_FS_STOP:
		if (u.pstop->ep_index >= f->fs_ep_max) {
			error = EINVAL;
			break;
		}
		mtx_lock(f->priv_mtx);
		xfer = f->fs_xfer[u.pstart->ep_index];
		if (usbd_transfer_pending(xfer)) {
			usbd_transfer_stop(xfer);
			/*
			 * Check if the USB transfer was stopped
			 * before it was even started. Else a cancel
			 * callback will be pending.
			 */
			if (!xfer->flags_int.transferring) {
				ugen_fs_set_complete(xfer->priv_sc,
				    USB_P2U(xfer->priv_fifo));
			}
		}
		mtx_unlock(f->priv_mtx);
		break;

	case USB_FS_OPEN:
	case USB_FS_OPEN_STREAM:
		if (u.popen->ep_index >= f->fs_ep_max) {
			error = EINVAL;
			break;
		}
		if (f->fs_xfer[u.popen->ep_index] != NULL) {
			error = EBUSY;
			break;
		}
		if (u.popen->max_bufsize > USB_FS_MAX_BUFSIZE) {
			u.popen->max_bufsize = USB_FS_MAX_BUFSIZE;
		}
		if (u.popen->max_frames & USB_FS_MAX_FRAMES_PRE_SCALE) {
			pre_scale = 1;
			u.popen->max_frames &= ~USB_FS_MAX_FRAMES_PRE_SCALE;
		} else {
			pre_scale = 0;
		}
		if (u.popen->max_frames > USB_FS_MAX_FRAMES) {
			u.popen->max_frames = USB_FS_MAX_FRAMES;
			break;
		}
		if (u.popen->max_frames == 0) {
			error = EINVAL;
			break;
		}
		ep = usbd_get_ep_by_addr(f->udev, u.popen->ep_no);
		if (ep == NULL) {
			error = EINVAL;
			break;
		}
		ed = ep->edesc;
		if (ed == NULL) {
			error = ENXIO;
			break;
		}
		iface_index = ep->iface_index;

		memset(usb_config, 0, sizeof(usb_config));

		usb_config[0].type = ed->bmAttributes & UE_XFERTYPE;
		usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR;
		usb_config[0].direction = ed->bEndpointAddress & (UE_DIR_OUT | UE_DIR_IN);
		usb_config[0].interval = USB_DEFAULT_INTERVAL;
		usb_config[0].flags.proxy_buffer = 1;
		if (pre_scale != 0)
			usb_config[0].flags.pre_scale_frames = 1;
		usb_config[0].callback = &ugen_ctrl_fs_callback;
		usb_config[0].timeout = 0;	/* no timeout */
		usb_config[0].frames = u.popen->max_frames;
		usb_config[0].bufsize = u.popen->max_bufsize;
		usb_config[0].usb_mode = USB_MODE_DUAL;	/* both modes */
		if (cmd == USB_FS_OPEN_STREAM)
			usb_config[0].stream_id = u.popen_stream->stream_id;

		if (usb_config[0].type == UE_CONTROL) {
			if (f->udev->flags.usb_mode != USB_MODE_HOST) {
				error = EINVAL;
				break;
			}
		} else {

			isread = ((usb_config[0].endpoint &
			    (UE_DIR_IN | UE_DIR_OUT)) == UE_DIR_IN);

			if (f->udev->flags.usb_mode != USB_MODE_HOST) {
				isread = !isread;
			}
			/* check permissions */
			if (isread) {
				if (!(fflags & FREAD)) {
					error = EPERM;
					break;
				}
			} else {
				if (!(fflags & FWRITE)) {
					error = EPERM;
					break;
				}
			}
		}
		error = usbd_transfer_setup(f->udev, &iface_index,
		    f->fs_xfer + u.popen->ep_index, usb_config, 1,
		    f, f->priv_mtx);
		if (error == 0) {
			/* update maximums */
			u.popen->max_packet_length =
			    f->fs_xfer[u.popen->ep_index]->max_frame_size;
			u.popen->max_bufsize =
			    f->fs_xfer[u.popen->ep_index]->max_data_length;
			/* update number of frames */
			u.popen->max_frames =
			    f->fs_xfer[u.popen->ep_index]->nframes;
			/* store index of endpoint */
			f->fs_xfer[u.popen->ep_index]->priv_fifo =
			    ((uint8_t *)0) + u.popen->ep_index;
		} else {
			error = ENOMEM;
		}
		break;

	case USB_FS_CLOSE:
		if (u.pclose->ep_index >= f->fs_ep_max) {
			error = EINVAL;
			break;
		}
		if (f->fs_xfer[u.pclose->ep_index] == NULL) {
			error = EINVAL;
			break;
		}
		usbd_transfer_unsetup(f->fs_xfer + u.pclose->ep_index, 1);
		break;

	case USB_FS_CLEAR_STALL_SYNC:
		if (u.pstall->ep_index >= f->fs_ep_max) {
			error = EINVAL;
			break;
		}
		if (f->fs_xfer[u.pstall->ep_index] == NULL) {
			error = EINVAL;
			break;
		}
		if (f->udev->flags.usb_mode != USB_MODE_HOST) {
			error = EINVAL;
			break;
		}
		mtx_lock(f->priv_mtx);
		error = usbd_transfer_pending(f->fs_xfer[u.pstall->ep_index]);
		mtx_unlock(f->priv_mtx);

		if (error) {
			return (EBUSY);
		}
		ep = f->fs_xfer[u.pstall->ep_index]->endpoint;

		/* setup a clear-stall packet */
		req.bmRequestType = UT_WRITE_ENDPOINT;
		req.bRequest = UR_CLEAR_FEATURE;
		USETW(req.wValue, UF_ENDPOINT_HALT);
		req.wIndex[0] = ep->edesc->bEndpointAddress;
		req.wIndex[1] = 0;
		USETW(req.wLength, 0);

		error = usbd_do_request(f->udev, NULL, &req, NULL);
		if (error == 0) {
			usbd_clear_data_toggle(f->udev, ep);
		} else {
			error = ENXIO;
		}
		break;

	default:
		error = ENOIOCTL;
		break;
	}

	DPRINTFN(6, "error=%d\n", error);

	return (error);
}
Example #2
0
int
urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
	struct urio_softc * sc;
	int unit = URIOUNIT(dev);
	struct urio_command *rcmd;
	int requesttype, len;
	struct iovec iov;
	struct uio uio;
	usb_device_request_t req;
	usbd_status err;
	u_int32_t req_actlen = 0;
	void *ptr = NULL;
	int error = 0;

	sc = urio_cd.cd_devs[unit];

	if (usbd_is_dying(sc->sc_udev))
		return (EIO);

	rcmd = (struct urio_command *)addr;

	switch (cmd) {
	case URIO_RECV_COMMAND:
		requesttype = rcmd->requesttype | UT_READ_VENDOR_DEVICE;
		break;

	case URIO_SEND_COMMAND:
		requesttype = rcmd->requesttype | UT_WRITE_VENDOR_DEVICE;
		break;

	default:
		return (EINVAL);
		break;
	}

	if (!(flag & FWRITE))
		return (EPERM);
	len = rcmd->length;

	DPRINTFN(1,("urio_ioctl: cmd=0x%08lx reqtype=0x%0x req=0x%0x "
		    "value=0x%0x index=0x%0x len=0x%0x\n",
		    cmd, requesttype, rcmd->request, rcmd->value,
		    rcmd->index, len));

	/* Send rio control message */
	req.bmRequestType = requesttype;
	req.bRequest = rcmd->request;
	USETW(req.wValue, rcmd->value);
	USETW(req.wIndex, rcmd->index);
	USETW(req.wLength, len);

	if (len < 0 || len > 32767)
		return (EINVAL);
	if (len != 0) {
		iov.iov_base = (caddr_t)rcmd->buffer;
		iov.iov_len = len;
		uio.uio_iov = &iov;
		uio.uio_iovcnt = 1;
		uio.uio_resid = len;
		uio.uio_offset = 0;
		uio.uio_segflg = UIO_USERSPACE;
		uio.uio_rw = req.bmRequestType & UT_READ ?
			     UIO_READ : UIO_WRITE;
		uio.uio_procp = p;
		ptr = malloc(len, M_TEMP, M_WAITOK);
		if (uio.uio_rw == UIO_WRITE) {
			error = uiomove(ptr, len, &uio);
			if (error)
				goto ret;
		}
	}

	sc->sc_refcnt++;

	err = usbd_do_request_flags(sc->sc_udev, &req, ptr, 0,
		  &req_actlen, USBD_DEFAULT_TIMEOUT);

	if (--sc->sc_refcnt < 0)
		usb_detach_wakeup(&sc->sc_dev);

	if (err) {
		error = EIO;
	} else {
		if (req_actlen != 0 && uio.uio_rw == UIO_READ)
			error = uiomove(ptr, req_actlen, &uio);
	}

ret:
	if (ptr != NULL)
		free(ptr, M_TEMP);
	return (error);
}
Example #3
0
/*------------------------------------------------------------------------*
 *	usb_pc_common_mem_cb - BUS-DMA callback function
 *------------------------------------------------------------------------*/
static void
usb_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
    int nseg, int error, uint8_t isload)
{
	struct usb_dma_parent_tag *uptag;
	struct usb_page_cache *pc;
	struct usb_page *pg;
	usb_size_t rem;
	bus_size_t off;
	uint8_t owned;

	pc = arg;
	uptag = pc->tag_parent;

	/*
	 * XXX There is sometimes recursive locking here.
	 * XXX We should try to find a better solution.
	 * XXX Until further the "owned" variable does
	 * XXX the trick.
	 */

	if (error) {
		goto done;
	}

	off = 0;
	pg = pc->page_start;
	pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
	rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
	pc->page_offset_buf = rem;
	pc->page_offset_end += rem;
#ifdef USB_DEBUG
	if (rem != (USB_P2U(pc->buffer) & (USB_PAGE_SIZE - 1))) {
		/*
		 * This check verifies that the physical address is correct:
		 */
		DPRINTFN(0, "Page offset was not preserved\n");
		error = 1;
		goto done;
	}
#endif
	while (pc->ismultiseg) {
		off += USB_PAGE_SIZE;
		if (off >= (segs->ds_len + rem)) {
			/* page crossing */
			nseg--;
			segs++;
			off = 0;
			rem = 0;
			if (nseg == 0)
				break;
		}
		pg++;
		pg->physaddr = (segs->ds_addr + off) & ~(USB_PAGE_SIZE - 1);
	}

done:
	owned = mtx_owned(uptag->mtx);
	if (!owned)
		mtx_lock(uptag->mtx);

	uptag->dma_error = (error ? 1 : 0);
	if (isload) {
		(uptag->func) (uptag);
	} else {
		cv_broadcast(uptag->cv);
	}
	if (!owned)
		mtx_unlock(uptag->mtx);
}
Example #4
0
/*
 * Stop the adapter and free any mbufs allocated to the
 * RX and TX lists.
 */
void
kue_stop(struct kue_softc *sc)
{
	usbd_status		err;
	struct ifnet		*ifp;
	int			i;

	DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));

	ifp = GET_IFP(sc);
	ifp->if_timer = 0;
	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);

	/* Stop transfers. */
	if (sc->kue_ep[KUE_ENDPT_RX] != NULL) {
		err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_RX]);
		if (err) {
			printf("%s: abort rx pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_RX]);
		if (err) {
			printf("%s: close rx pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		sc->kue_ep[KUE_ENDPT_RX] = NULL;
	}

	if (sc->kue_ep[KUE_ENDPT_TX] != NULL) {
		err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_TX]);
		if (err) {
			printf("%s: abort tx pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_TX]);
		if (err) {
			printf("%s: close tx pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		sc->kue_ep[KUE_ENDPT_TX] = NULL;
	}

	if (sc->kue_ep[KUE_ENDPT_INTR] != NULL) {
		err = usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
		if (err) {
			printf("%s: abort intr pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
		if (err) {
			printf("%s: close intr pipe failed: %s\n",
			    sc->kue_dev.dv_xname, usbd_errstr(err));
		}
		sc->kue_ep[KUE_ENDPT_INTR] = NULL;
	}

	/* Free RX resources. */
	for (i = 0; i < KUE_RX_LIST_CNT; i++) {
		if (sc->kue_cdata.kue_rx_chain[i].kue_mbuf != NULL) {
			m_freem(sc->kue_cdata.kue_rx_chain[i].kue_mbuf);
			sc->kue_cdata.kue_rx_chain[i].kue_mbuf = NULL;
		}
		if (sc->kue_cdata.kue_rx_chain[i].kue_xfer != NULL) {
			usbd_free_xfer(sc->kue_cdata.kue_rx_chain[i].kue_xfer);
			sc->kue_cdata.kue_rx_chain[i].kue_xfer = NULL;
		}
	}

	/* Free TX resources. */
	for (i = 0; i < KUE_TX_LIST_CNT; i++) {
		if (sc->kue_cdata.kue_tx_chain[i].kue_mbuf != NULL) {
			m_freem(sc->kue_cdata.kue_tx_chain[i].kue_mbuf);
			sc->kue_cdata.kue_tx_chain[i].kue_mbuf = NULL;
		}
		if (sc->kue_cdata.kue_tx_chain[i].kue_xfer != NULL) {
			usbd_free_xfer(sc->kue_cdata.kue_tx_chain[i].kue_xfer);
			sc->kue_cdata.kue_tx_chain[i].kue_xfer = NULL;
		}
	}
}
Example #5
0
/*
 * A frame has been uploaded: pass the resulting mbuf chain up to
 * the higher level protocols.
 */
void
kue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
	struct kue_chain	*c = priv;
	struct kue_softc	*sc = c->kue_sc;
	struct ifnet		*ifp = GET_IFP(sc);
	struct mbuf		*m;
	int			total_len = 0;
	int			s;

	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->kue_dev.dv_xname,
		     __func__, status));

	if (sc->kue_dying)
		return;

	if (!(ifp->if_flags & IFF_RUNNING))
		return;

	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;
		sc->kue_rx_errs++;
		if (usbd_ratecheck(&sc->kue_rx_notice)) {
			printf("%s: %u usb errors on rx: %s\n",
			    sc->kue_dev.dv_xname, sc->kue_rx_errs,
			    usbd_errstr(status));
			sc->kue_rx_errs = 0;
		}
		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_RX]);
		goto done;
	}

	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);

	DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", sc->kue_dev.dv_xname,
		     __func__, total_len,
		     UGETW(mtod(c->kue_mbuf, u_int8_t *))));

	if (total_len <= 1)
		goto done;

	m = c->kue_mbuf;
	/* copy data to mbuf */
	memcpy(mtod(m, char *), c->kue_buf, total_len);

	/* No errors; receive the packet. */
	total_len = UGETW(mtod(m, u_int8_t *));
	m_adj(m, sizeof(u_int16_t));

	if (total_len < sizeof(struct ether_header)) {
		ifp->if_ierrors++;
		goto done;
	}

	ifp->if_ipackets++;
	m->m_pkthdr.len = m->m_len = total_len;

	m->m_pkthdr.rcvif = ifp;

	s = splnet();

	/* XXX ugly */
	if (kue_newbuf(sc, c, NULL) == ENOBUFS) {
		ifp->if_ierrors++;
		goto done1;
	}

#if NBPFILTER > 0
	/*
	 * Handle BPF listeners. Let the BPF user see the packet, but
	 * don't pass it up to the ether_input() layer unless it's
	 * a broadcast packet, multicast packet, matches our ethernet
	 * address or the interface is in promiscuous mode.
	 */
	if (ifp->if_bpf)
		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif

	DPRINTFN(10,("%s: %s: deliver %d\n", sc->kue_dev.dv_xname,
		    __func__, m->m_len));
	ether_input_mbuf(ifp, m);
 done1:
	splx(s);

 done:

	/* Setup new transfer. */
	usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_RX],
	    c, c->kue_buf, KUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
	    USBD_NO_TIMEOUT, kue_rxeof);
	usbd_transfer(c->kue_xfer);

	DPRINTFN(10,("%s: %s: start rx\n", sc->kue_dev.dv_xname,
		    __func__));
}
Example #6
0
/* ARGSUSED */
static int
udsir_read(void *h, struct uio *uio, int flag)
{
	struct udsir_softc *sc = h;
	int s;
	int error;
	u_int uframelen;

	DPRINTFN(1, ("%s: sc=%p\n", __func__, sc));

	if (sc->sc_dying)
		return EIO;

#ifdef DIAGNOSTIC
	if (sc->sc_rd_buf == NULL)
		return EINVAL;
#endif

	sc->sc_refcnt++;

	if (!sc->sc_rd_readinprogress && !UDSIR_BLOCK_RX_DATA(sc))
		/* Possibly wake up polling thread */
		wakeup(&sc->sc_thread);

	do {
		s = splusb();
		while (sc->sc_ur_framelen == 0) {
			DPRINTFN(5, ("%s: calling tsleep()\n", __func__));
			error = tsleep(&sc->sc_ur_framelen, PZERO | PCATCH,
				       "usirrd", 0);
			if (sc->sc_dying)
				error = EIO;
			if (error) {
				splx(s);
				DPRINTFN(0, ("%s: tsleep() = %d\n",
					     __func__, error));
				goto ret;
			}
		}
		splx(s);

		uframelen = sc->sc_ur_framelen;
		DPRINTFN(1, ("%s: sc=%p framelen=%u, hdr=0x%02x\n",
			     __func__, sc, uframelen, sc->sc_ur_buf[0]));
		if (uframelen > uio->uio_resid)
			error = EINVAL;
		else
			error = uiomove(sc->sc_ur_buf, uframelen, uio);
		sc->sc_ur_framelen = 0;

		if (deframe_rd_ur(sc) == 0 && uframelen > 0) {
			/*
			 * Need to wait for another read to obtain a
			 * complete frame...  If we also obtained
			 * actual data, wake up the possibly sleeping
			 * thread immediately...
			 */
			wakeup(&sc->sc_thread);
		}
	} while (uframelen == 0);

	DPRINTFN(1, ("%s: return %d\n", __func__, error));

 ret:
	if (--sc->sc_refcnt < 0)
		usb_detach_wakeupold(sc->sc_dev);
	return error;
}
Example #7
0
static void
udsir_rd_cb(struct usbd_xfer *xfer, void * priv, usbd_status status)
{
	struct udsir_softc *sc = priv;
	uint32_t size;

	DPRINTFN(60, ("%s: sc=%p\n", __func__, sc));

	/* Read is no longer in progress */
	sc->sc_rd_readinprogress = 0;

	if (status == USBD_CANCELLED || sc->sc_closing)	/* this is normal */
		return;
	if (status) {
		size = 0;
		sc->sc_rd_err = 1;

		if (sc->sc_direction == udir_input ||
		    sc->sc_direction == udir_idle) {
			/*
			 * Receive error, probably need to clear error
			 * condition.
			 */
			sc->sc_direction = udir_stalled;
		}
	} else
		usbd_get_xfer_status(xfer, NULL, NULL, &size, NULL);

	sc->sc_rd_index = 0;
	sc->sc_rd_count = size;

	DPRINTFN(((size > 0 || sc->sc_rd_err != 0) ? 20 : 60),
		 ("%s: sc=%p size=%u, err=%d\n",
		  __func__, sc, size, sc->sc_rd_err));

#ifdef UDSIR_DEBUG
	if (udsirdebug >= 20 && size > 0)
		udsir_dumpdata(sc->sc_rd_buf, size, __func__);
#endif

	if (deframe_rd_ur(sc) == 0) {
		if (!deframe_isclear(&sc->sc_framestate) && size == 0 &&
		    sc->sc_rd_expectdataticks == 0) {
			/*
			 * Expected data, but didn't get it
			 * within expected time...
			 */
			DPRINTFN(5,("%s: incoming packet timeout\n",
				    __func__));
			deframe_clear(&sc->sc_framestate);
		} else if (size > 0) {
			/*
			 * If we also received actual data, reset the
			 * data read timeout and wake up the possibly
			 * sleeping thread...
			 */
			sc->sc_rd_expectdataticks = 2;
			wakeup(&sc->sc_thread);
		}
	}

	/*
	 * Check if incoming data has stopped, or that we cannot
	 * safely read any more data.  In the case of the latter we
	 * must switch to idle so that a write will not block...
	 */
	if (sc->sc_direction == udir_input &&
	    ((size == 0 && sc->sc_rd_expectdataticks == 0) ||
	     UDSIR_BLOCK_RX_DATA(sc))) {
		DPRINTFN(8, ("%s: idling on packet timeout, "
			     "complete frame, or no data\n", __func__));
		sc->sc_direction = udir_idle;

		/* Wake up for possible output */
		wakeup(&sc->sc_wr_buf);
		selnotify(&sc->sc_wr_sel, 0, 0);
	}
}
Example #8
0
static int
cdce_attach(device_t dev)
{
	struct cdce_softc *sc = device_get_softc(dev);
	struct usb_ether *ue = &sc->sc_ue;
	struct usb_attach_arg *uaa = device_get_ivars(dev);
	struct usb_interface *iface;
	const struct usb_cdc_union_descriptor *ud;
	const struct usb_interface_descriptor *id;
	const struct usb_cdc_ethernet_descriptor *ued;
	const struct usb_config *pcfg;
	int error;
	uint8_t i;
	uint8_t data_iface_no;
	char eaddr_str[5 * ETHER_ADDR_LEN];	/* approx */

	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
	sc->sc_ue.ue_udev = uaa->device;

	device_set_usb_desc(dev);

	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);

	ud = usbd_find_descriptor
	    (uaa->device, NULL, uaa->info.bIfaceIndex,
	    UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_UNION, 0 - 1);

	if ((ud == NULL) || (ud->bLength < sizeof(*ud)) ||
	    (sc->sc_flags & CDCE_FLAG_NO_UNION)) {
		DPRINTFN(1, "No union descriptor!\n");
		sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex;
		sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
		goto alloc_transfers;
	}
	data_iface_no = ud->bSlaveInterface[0];

	for (i = 0;; i++) {

		iface = usbd_get_iface(uaa->device, i);

		if (iface) {

			id = usbd_get_interface_descriptor(iface);

			if (id && (id->bInterfaceNumber == data_iface_no)) {
				sc->sc_ifaces_index[0] = i;
				sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex;
				usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
				break;
			}
		} else {
			device_printf(dev, "no data interface found\n");
			goto detach;
		}
	}

	/*
	 * <quote>
	 *
	 *  The Data Class interface of a networking device shall have
	 *  a minimum of two interface settings. The first setting
	 *  (the default interface setting) includes no endpoints and
	 *  therefore no networking traffic is exchanged whenever the
	 *  default interface setting is selected. One or more
	 *  additional interface settings are used for normal
	 *  operation, and therefore each includes a pair of endpoints
	 *  (one IN, and one OUT) to exchange network traffic. Select
	 *  an alternate interface setting to initialize the network
	 *  aspects of the device and to enable the exchange of
	 *  network traffic.
	 *
	 * </quote>
	 *
	 * Some devices, most notably cable modems, include interface
	 * settings that have no IN or OUT endpoint, therefore loop
	 * through the list of all available interface settings
	 * looking for one with both IN and OUT endpoints.
	 */

alloc_transfers:

	pcfg = cdce_config;	/* Default Configuration */

	for (i = 0; i != 32; i++) {

		error = usbd_set_alt_interface_index(uaa->device,
		    sc->sc_ifaces_index[0], i);
		if (error)
			break;
#if CDCE_HAVE_NCM
		if ((i == 0) && (cdce_ncm_init(sc) == 0))
			pcfg = cdce_ncm_config;
#endif
		error = usbd_transfer_setup(uaa->device,
		    sc->sc_ifaces_index, sc->sc_xfer,
		    pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx);

		if (error == 0)
			break;
	}

	if (error || (i == 32)) {
		device_printf(dev, "No valid alternate "
		    "setting found\n");
		goto detach;
	}

	ued = usbd_find_descriptor
	    (uaa->device, NULL, uaa->info.bIfaceIndex,
	    UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_ENF, 0 - 1);

	if ((ued == NULL) || (ued->bLength < sizeof(*ued))) {
		error = USB_ERR_INVAL;
	} else {
		error = usbd_req_get_string_any(uaa->device, NULL, 
		    eaddr_str, sizeof(eaddr_str), ued->iMacAddress);
	}

	if (error) {

		/* fake MAC address */

		device_printf(dev, "faking MAC address\n");
		sc->sc_ue.ue_eaddr[0] = 0x2a;
		memcpy(&sc->sc_ue.ue_eaddr[1], &ticks, sizeof(uint32_t));
		sc->sc_ue.ue_eaddr[5] = device_get_unit(dev);

	} else {

		memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr));

		for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) {

			char c = eaddr_str[i];

			if ('0' <= c && c <= '9')
				c -= '0';
			else if (c != 0)
				c -= 'A' - 10;
			else
				break;

			c &= 0xf;

			if ((i & 1) == 0)
				c <<= 4;
			sc->sc_ue.ue_eaddr[i / 2] |= c;
		}

		if (uaa->usb_mode == USB_MODE_DEVICE) {
			/*
			 * Do not use the same MAC address like the peer !
			 */
			sc->sc_ue.ue_eaddr[5] ^= 0xFF;
		}
	}

	ue->ue_sc = sc;
	ue->ue_dev = dev;
	ue->ue_udev = uaa->device;
	ue->ue_mtx = &sc->sc_mtx;
	ue->ue_methods = &cdce_ue_methods;

	error = uether_ifattach(ue);
	if (error) {
		device_printf(dev, "could not attach interface\n");
		goto detach;
	}
	return (0);			/* success */

detach:
	cdce_detach(dev);
	return (ENXIO);			/* failure */
}
Example #9
0
static void
cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct mbuf *m;
	struct mbuf *mt;
	uint32_t crc;
	uint8_t x;
	int actlen, aframes;

	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);

	DPRINTFN(1, "\n");

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
		    actlen, aframes);

		ifp->if_opackets++;

		/* free all previous TX buffers */
		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);

		/* FALLTHROUGH */
	case USB_ST_SETUP:
tr_setup:
		for (x = 0; x != CDCE_FRAMES_MAX; x++) {

			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);

			if (m == NULL)
				break;

			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
				/*
				 * Zaurus wants a 32-bit CRC appended
				 * to every frame
				 */

				crc = cdce_m_crc32(m, 0, m->m_pkthdr.len);
				crc = htole32(crc);

				if (!m_append(m, 4, (void *)&crc)) {
					m_freem(m);
					ifp->if_oerrors++;
					continue;
				}
			}
			if (m->m_len != m->m_pkthdr.len) {
				mt = m_defrag(m, M_DONTWAIT);
				if (mt == NULL) {
					m_freem(m);
					ifp->if_oerrors++;
					continue;
				}
				m = mt;
			}
			if (m->m_pkthdr.len > MCLBYTES) {
				m->m_pkthdr.len = MCLBYTES;
			}
			sc->sc_tx_buf[x] = m;
			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);

			/*
			 * If there's a BPF listener, bounce a copy of
			 * this frame to him:
			 */
			BPF_MTAP(ifp, m);
		}
		if (x != 0) {
			usbd_xfer_set_frames(xfer, x);

			usbd_transfer_submit(xfer);
		}
		break;

	default:			/* Error */
		DPRINTFN(11, "transfer error, %s\n",
		    usbd_errstr(error));

		/* free all previous TX buffers */
		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);

		/* count output errors */
		ifp->if_oerrors++;

		if (error != USB_ERR_CANCELLED) {
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			goto tr_setup;
		}
		break;
	}
}
Example #10
0
static void
cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct mbuf *m;
	int sumdata;
	int sumlen;
	int actlen;
	int aframes;
	int temp;
	int nframes;
	int x;
	int offset;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:

		usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL);

		DPRINTFN(1, "received %u bytes in %u frames\n",
		    actlen, aframes);

		if (actlen < (sizeof(sc->sc_ncm.hdr) +
		    sizeof(sc->sc_ncm.dpt))) {
			DPRINTFN(1, "frame too short\n");
			goto tr_setup;
		}
		usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr),
		    sizeof(sc->sc_ncm.hdr));

		if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') ||
		    (sc->sc_ncm.hdr.dwSignature[1] != 'C') ||
		    (sc->sc_ncm.hdr.dwSignature[2] != 'M') ||
		    (sc->sc_ncm.hdr.dwSignature[3] != 'H')) {
			DPRINTFN(1, "invalid HDR signature: "
			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
			    sc->sc_ncm.hdr.dwSignature[0],
			    sc->sc_ncm.hdr.dwSignature[1],
			    sc->sc_ncm.hdr.dwSignature[2],
			    sc->sc_ncm.hdr.dwSignature[3]);
			goto tr_stall;
		}
		temp = UGETW(sc->sc_ncm.hdr.wBlockLength);
		if (temp > sumlen) {
			DPRINTFN(1, "unsupported block length %u/%u\n",
			    temp, sumlen);
			goto tr_stall;
		}
		temp = UGETW(sc->sc_ncm.hdr.wDptIndex);
		if ((temp + sizeof(sc->sc_ncm.dpt)) > actlen) {
			DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp);
			goto tr_stall;
		}
		usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt),
		    sizeof(sc->sc_ncm.dpt));

		if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') ||
		    (sc->sc_ncm.dpt.dwSignature[1] != 'C') ||
		    (sc->sc_ncm.dpt.dwSignature[2] != 'M') ||
		    (sc->sc_ncm.dpt.dwSignature[3] != '0')) {
			DPRINTFN(1, "invalid DPT signature"
			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
			    sc->sc_ncm.dpt.dwSignature[0],
			    sc->sc_ncm.dpt.dwSignature[1],
			    sc->sc_ncm.dpt.dwSignature[2],
			    sc->sc_ncm.dpt.dwSignature[3]);
			goto tr_stall;
		}
		nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4;

		/* Subtract size of header and last zero padded entry */
		if (nframes >= (2 + 1))
			nframes -= (2 + 1);
		else
			nframes = 0;

		DPRINTFN(1, "nframes = %u\n", nframes);

		temp += sizeof(sc->sc_ncm.dpt);

		if ((temp + (4 * nframes)) > actlen)
			goto tr_stall;

		if (nframes > CDCE_NCM_SUBFRAMES_MAX) {
			DPRINTFN(1, "Truncating number of frames from %u to %u\n",
			    nframes, CDCE_NCM_SUBFRAMES_MAX);
			nframes = CDCE_NCM_SUBFRAMES_MAX;
		}
		usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes));

		sumdata = 0;

		for (x = 0; x != nframes; x++) {

			offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex);
			temp = UGETW(sc->sc_ncm.dp[x].wFrameLength);

			if ((offset == 0) ||
			    (temp < sizeof(struct ether_header)) ||
			    (temp > (MCLBYTES - ETHER_ALIGN))) {
				DPRINTFN(1, "NULL frame detected at %d\n", x);
				m = NULL;
				/* silently ignore this frame */
				continue;
			} else if ((offset + temp) > actlen) {
				DPRINTFN(1, "invalid frame "
				    "detected at %d\n", x);
				m = NULL;
				/* silently ignore this frame */
				continue;
			} else if (temp > (MHLEN - ETHER_ALIGN)) {
				m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
			} else {
				m = m_gethdr(M_DONTWAIT, MT_DATA);
			}

			DPRINTFN(16, "frame %u, offset = %u, length = %u \n",
			    x, offset, temp);

			/* check if we have a buffer */
			if (m) {
				m_adj(m, ETHER_ALIGN);

				usbd_copy_out(pc, offset, m->m_data, temp);

				/* enqueue */
				uether_rxmbuf(&sc->sc_ue, m, temp);

				sumdata += temp;
			} else {
				ifp->if_ierrors++;
			}
		}

		DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen);

	case USB_ST_SETUP:
tr_setup:
		usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max);
		usbd_xfer_set_frames(xfer, 1);
		usbd_transfer_submit(xfer);
		uether_rxflush(&sc->sc_ue);	/* must be last */
		break;

	default:			/* Error */
		DPRINTFN(1, "error = %s\n",
		    usbd_errstr(error));

		if (error != USB_ERR_CANCELLED) {
tr_stall:
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			usbd_xfer_set_frames(xfer, 0);
			usbd_transfer_submit(xfer);
		}
		break;
	}
}
Example #11
0
/*------------------------------------------------------------------------*
 *	cdce_ncm_init
 *
 * Return values:
 * 0: Success
 * Else: Failure
 *------------------------------------------------------------------------*/
static uint8_t
cdce_ncm_init(struct cdce_softc *sc)
{
	struct usb_ncm_parameters temp;
	struct usb_device_request req;
	struct usb_ncm_func_descriptor *ufd;
	uint8_t value[8];
	int err;

	ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL,
	    sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0 - 1,
	    UCDC_NCM_FUNC_DESC_SUBTYPE, 0 - 1);

	/* verify length of NCM functional descriptor */
	if (ufd != NULL) {
		if (ufd->bLength < sizeof(*ufd))
			ufd = NULL;
		else
			DPRINTFN(1, "Found NCM functional descriptor.\n");
	}

	req.bmRequestType = UT_READ_CLASS_INTERFACE;
	req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS;
	USETW(req.wValue, 0);
	req.wIndex[0] = sc->sc_ifaces_index[1];
	req.wIndex[1] = 0;
	USETW(req.wLength, sizeof(temp));

	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
	    &temp, 0, NULL, 1000 /* ms */);
	if (err)
		return (1);

	/* Read correct set of parameters according to device mode */

	if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize);
		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize);
		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder);
		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor);
		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment);
		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
	} else {
		sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize);
		sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize);
		sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder);
		sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor);
		sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment);
		sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams);
	}

	/* Verify maximum receive length */

	if ((sc->sc_ncm.rx_max < 32) || 
	    (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) {
		DPRINTFN(1, "Using default maximum receive length\n");
		sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN;
	}

	/* Verify maximum transmit length */

	if ((sc->sc_ncm.tx_max < 32) ||
	    (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) {
		DPRINTFN(1, "Using default maximum transmit length\n");
		sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN;
	}

	/* 
	 * Verify that the structure alignment is:
	 * - power of two
	 * - not greater than the maximum transmit length
	 * - not less than four bytes
	 */
	if ((sc->sc_ncm.tx_struct_align < 4) ||
	    (sc->sc_ncm.tx_struct_align != 
	     ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) ||
	    (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) {
		DPRINTFN(1, "Using default other alignment: 4 bytes\n");
		sc->sc_ncm.tx_struct_align = 4;
	}

	/* 
	 * Verify that the payload alignment is:
	 * - power of two
	 * - not greater than the maximum transmit length
	 * - not less than four bytes
	 */
	if ((sc->sc_ncm.tx_modulus < 4) ||
	    (sc->sc_ncm.tx_modulus !=
	     ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) ||
	    (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) {
		DPRINTFN(1, "Using default transmit modulus: 4 bytes\n");
		sc->sc_ncm.tx_modulus = 4;
	}

	/* Verify that the payload remainder */

	if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) {
		DPRINTFN(1, "Using default transmit remainder: 0 bytes\n");
		sc->sc_ncm.tx_remainder = 0;
	}

	/*
	 * Offset the TX remainder so that IP packet payload starts at
	 * the tx_modulus. This is not too clear in the specification.
	 */

	sc->sc_ncm.tx_remainder = 
	    (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) &
	    (sc->sc_ncm.tx_modulus - 1);

	/* Verify max datagrams */

	if (sc->sc_ncm.tx_nframe == 0 ||
	    sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) {
		DPRINTFN(1, "Using default max "
		    "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1);
		/* need to reserve one entry for zero padding */
		sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1);
	}

	/* Additional configuration, will fail in device side mode, which is OK. */

	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
	req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE;
	USETW(req.wValue, 0);
	req.wIndex[0] = sc->sc_ifaces_index[1];
	req.wIndex[1] = 0;

	if (ufd != NULL &&
	    (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) {
		USETW(req.wLength, 8);
		USETDW(value, sc->sc_ncm.rx_max);
		USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1));
		USETW(value + 6, 0);
	} else {
		USETW(req.wLength, 4);
		USETDW(value, sc->sc_ncm.rx_max);
 	}

	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
	    &value, 0, NULL, 1000 /* ms */);
	if (err) {
		DPRINTFN(1, "Setting input size "
		    "to %u failed.\n", sc->sc_ncm.rx_max);
	}

	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
	req.bRequest = UCDC_NCM_SET_CRC_MODE;
	USETW(req.wValue, 0);	/* no CRC */
	req.wIndex[0] = sc->sc_ifaces_index[1];
	req.wIndex[1] = 0;
	USETW(req.wLength, 0);

	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
	    NULL, 0, NULL, 1000 /* ms */);
	if (err) {
		DPRINTFN(1, "Setting CRC mode to off failed.\n");
	}

	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
	req.bRequest = UCDC_NCM_SET_NTB_FORMAT;
	USETW(req.wValue, 0);	/* NTB-16 */
	req.wIndex[0] = sc->sc_ifaces_index[1];
	req.wIndex[1] = 0;
	USETW(req.wLength, 0);

	err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req,
	    NULL, 0, NULL, 1000 /* ms */);
	if (err) {
		DPRINTFN(1, "Setting NTB format to 16-bit failed.\n");
	}

	return (0);		/* success */
}
Example #12
0
static uint8_t
cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index);
	struct mbuf *m;
	uint32_t rem;
	uint32_t offset;
	uint32_t last_offset;
	uint16_t n;
	uint8_t retval;

	usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index);

	offset = sizeof(sc->sc_ncm.hdr) +
	    sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp);

	/* Store last valid offset before alignment */
	last_offset = offset;

	/* Align offset */
	offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
	    offset, sc->sc_ncm.tx_modulus);

	/* Zero pad */
	cdce_ncm_tx_zero(pc, last_offset, offset);

	/* buffer full */
	retval = 2;

	for (n = 0; n != sc->sc_ncm.tx_nframe; n++) {

		/* check if end of transmit buffer is reached */

		if (offset >= sc->sc_ncm.tx_max)
			break;

		/* compute maximum buffer size */

		rem = sc->sc_ncm.tx_max - offset;

		IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);

		if (m == NULL) {
			/* buffer not full */
			retval = 1;
			break;
		}

		if (m->m_pkthdr.len > rem) {
			if (n == 0) {
				/* The frame won't fit in our buffer */
				DPRINTFN(1, "Frame too big to be transmitted!\n");
				m_freem(m);
				ifp->if_oerrors++;
				n--;
				continue;
			}
			/* Wait till next buffer becomes ready */
			IFQ_DRV_PREPEND(&(ifp->if_snd), m);
			break;
		}
		usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len);

		USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len);
		USETW(sc->sc_ncm.dp[n].wFrameIndex, offset);

		/* Update offset */
		offset += m->m_pkthdr.len;

		/* Store last valid offset before alignment */
		last_offset = offset;

		/* Align offset */
		offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
		    offset, sc->sc_ncm.tx_modulus);

		/* Zero pad */
		cdce_ncm_tx_zero(pc, last_offset, offset);

		/*
		 * If there's a BPF listener, bounce a copy
		 * of this frame to him:
		 */
		BPF_MTAP(ifp, m);

		/* Free mbuf */

		m_freem(m);

		/* Pre-increment interface counter */

		ifp->if_opackets++;
	}

	if (n == 0)
		return (0);

	rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4);

	USETW(sc->sc_ncm.dpt.wLength, rem);

	/* zero the rest of the data pointer entries */
	for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) {
		USETW(sc->sc_ncm.dp[n].wFrameLength, 0);
		USETW(sc->sc_ncm.dp[n].wFrameIndex, 0);
	}

	offset = last_offset;

	/* Align offset */
	offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN);

	/* Optimise, save bandwidth and force short termination */
	if (offset >= sc->sc_ncm.tx_max)
		offset = sc->sc_ncm.tx_max;
	else
		offset ++;

	/* Zero pad */
	cdce_ncm_tx_zero(pc, last_offset, offset);

	/* set frame length */
	usbd_xfer_set_frame_len(xfer, index, offset);

	/* Fill out 16-bit header */
	sc->sc_ncm.hdr.dwSignature[0] = 'N';
	sc->sc_ncm.hdr.dwSignature[1] = 'C';
	sc->sc_ncm.hdr.dwSignature[2] = 'M';
	sc->sc_ncm.hdr.dwSignature[3] = 'H';
	USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr));
	USETW(sc->sc_ncm.hdr.wBlockLength, offset);
	USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq);
	USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr));

	sc->sc_ncm.tx_seq++;

	/* Fill out 16-bit frame table header */
	sc->sc_ncm.dpt.dwSignature[0] = 'N';
	sc->sc_ncm.dpt.dwSignature[1] = 'C';
	sc->sc_ncm.dpt.dwSignature[2] = 'M';
	sc->sc_ncm.dpt.dwSignature[3] = '0';
	USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0);		/* reserved */

	usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr));
	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt),
	    sizeof(sc->sc_ncm.dpt));
	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt),
	    &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp));
	return (retval);
}
Example #13
0
static int
ugen_ioctl_post(struct usb_fifo *f, u_long cmd, void *addr, int fflags)
{
	union {
		struct usb_interface_descriptor *idesc;
		struct usb_alt_interface *ai;
		struct usb_device_descriptor *ddesc;
		struct usb_config_descriptor *cdesc;
		struct usb_device_stats *stat;
		struct usb_fs_init *pinit;
		struct usb_fs_uninit *puninit;
		uint32_t *ptime;
		void   *addr;
		int    *pint;
	}     u;
	struct usb_device_descriptor *dtemp;
	struct usb_config_descriptor *ctemp;
	struct usb_interface *iface;
	int error = 0;
	uint8_t n;

	u.addr = addr;

	DPRINTFN(6, "cmd=0x%08lx\n", cmd);

	switch (cmd) {
	case USB_DISCOVER:
		usb_needs_explore_all();
		break;

	case USB_SETDEBUG:
		if (!(fflags & FWRITE)) {
			error = EPERM;
			break;
		}
		usb_debug = *(int *)addr;
		break;

	case USB_GET_CONFIG:
		*(int *)addr = f->udev->curr_config_index;
		break;

	case USB_SET_CONFIG:
		if (!(fflags & FWRITE)) {
			error = EPERM;
			break;
		}
		error = ugen_set_config(f, *(int *)addr);
		break;

	case USB_GET_ALTINTERFACE:
		iface = usbd_get_iface(f->udev,
		    u.ai->uai_interface_index);
		if (iface && iface->idesc) {
			u.ai->uai_alt_index = iface->alt_index;
		} else {
			error = EINVAL;
		}
		break;

	case USB_SET_ALTINTERFACE:
		if (!(fflags & FWRITE)) {
			error = EPERM;
			break;
		}
		error = ugen_set_interface(f,
		    u.ai->uai_interface_index, u.ai->uai_alt_index);
		break;

	case USB_GET_DEVICE_DESC:
		dtemp = usbd_get_device_descriptor(f->udev);
		if (!dtemp) {
			error = EIO;
			break;
		}
		*u.ddesc = *dtemp;
		break;

	case USB_GET_CONFIG_DESC:
		ctemp = usbd_get_config_descriptor(f->udev);
		if (!ctemp) {
			error = EIO;
			break;
		}
		*u.cdesc = *ctemp;
		break;

	case USB_GET_FULL_DESC:
		error = ugen_get_cdesc(f, addr);
		break;

	case USB_GET_STRING_DESC:
		error = ugen_get_sdesc(f, addr);
		break;

	case USB_GET_IFACE_DRIVER:
		error = ugen_get_iface_driver(f, addr);
		break;

	case USB_REQUEST:
	case USB_DO_REQUEST:
		if (!(fflags & FWRITE)) {
			error = EPERM;
			break;
		}
		error = ugen_do_request(f, addr);
		break;

	case USB_DEVICEINFO:
	case USB_GET_DEVICEINFO:
		error = usb_gen_fill_deviceinfo(f, addr);
		break;

	case USB_DEVICESTATS:
		for (n = 0; n != 4; n++) {

			u.stat->uds_requests_fail[n] =
			    f->udev->bus->stats_err.uds_requests[n];

			u.stat->uds_requests_ok[n] =
			    f->udev->bus->stats_ok.uds_requests[n];
		}
		break;

	case USB_DEVICEENUMERATE:
		error = ugen_re_enumerate(f);
		break;

	case USB_GET_PLUGTIME:
		*u.ptime = f->udev->plugtime;
		break;

	case USB_CLAIM_INTERFACE:
	case USB_RELEASE_INTERFACE:
		/* TODO */
		break;

	case USB_IFACE_DRIVER_ACTIVE:

		n = *u.pint & 0xFF;

		iface = usbd_get_iface(f->udev, n);

		if (iface && iface->subdev)
			error = 0;
		else
			error = ENXIO;
		break;

	case USB_IFACE_DRIVER_DETACH:

		error = priv_check(curthread, PRIV_DRIVER);

		if (error)
			break;

		n = *u.pint & 0xFF;

		if (n == USB_IFACE_INDEX_ANY) {
			error = EINVAL;
			break;
		}

		/*
		 * Detach the currently attached driver.
		 */
		usb_detach_device(f->udev, n, 0);

		/*
		 * Set parent to self, this should keep attach away
		 * until the next set configuration event.
		 */
		usbd_set_parent_iface(f->udev, n, n);
		break;

	case USB_SET_POWER_MODE:
		error = ugen_set_power_mode(f, *u.pint);
		break;

	case USB_GET_POWER_MODE:
		*u.pint = ugen_get_power_mode(f);
		break;

	case USB_GET_POWER_USAGE:
		*u.pint = ugen_get_power_usage(f);
		break;

	case USB_SET_PORT_ENABLE:
		error = ugen_do_port_feature(f,
		    *u.pint, 1, UHF_PORT_ENABLE);
		break;

	case USB_SET_PORT_DISABLE:
		error = ugen_do_port_feature(f,
		    *u.pint, 0, UHF_PORT_ENABLE);
		break;

	case USB_FS_INIT:
		/* verify input parameters */
		if (u.pinit->pEndpoints == NULL) {
			error = EINVAL;
			break;
		}
		if (u.pinit->ep_index_max > 127) {
			error = EINVAL;
			break;
		}
		if (u.pinit->ep_index_max == 0) {
			error = EINVAL;
			break;
		}
		if (f->fs_xfer != NULL) {
			error = EBUSY;
			break;
		}
		if (f->dev_ep_index != 0) {
			error = EINVAL;
			break;
		}
		if (ugen_fifo_in_use(f, fflags)) {
			error = EBUSY;
			break;
		}
		error = usb_fifo_alloc_buffer(f, 1, u.pinit->ep_index_max);
		if (error) {
			break;
		}
		f->fs_xfer = malloc(sizeof(f->fs_xfer[0]) *
		    u.pinit->ep_index_max, M_USB, M_WAITOK | M_ZERO);
		if (f->fs_xfer == NULL) {
			usb_fifo_free_buffer(f);
			error = ENOMEM;
			break;
		}
		f->fs_ep_max = u.pinit->ep_index_max;
		f->fs_ep_ptr = u.pinit->pEndpoints;
		break;

	case USB_FS_UNINIT:
		if (u.puninit->dummy != 0) {
			error = EINVAL;
			break;
		}
		error = ugen_fs_uninit(f);
		break;

	default:
		mtx_lock(f->priv_mtx);
		error = ugen_iface_ioctl(f, cmd, addr, fflags);
		mtx_unlock(f->priv_mtx);
		break;
	}
	DPRINTFN(6, "error=%d\n", error);
	return (error);
}
Example #14
0
static int
ugen_set_power_mode(struct usb_fifo *f, int mode)
{
	struct usb_device *udev = f->udev;
	int err;
	uint8_t old_mode;

	if ((udev == NULL) ||
	    (udev->parent_hub == NULL)) {
		return (EINVAL);
	}
	err = priv_check(curthread, PRIV_DRIVER);
	if (err)
		return (err);

	/* get old power mode */
	old_mode = udev->power_mode;

	/* if no change, then just return */
	if (old_mode == mode)
		return (0);

	switch (mode) {
	case USB_POWER_MODE_OFF:
		/* get the device unconfigured */
		err = ugen_set_config(f, USB_UNCONFIG_INDEX);
		if (err) {
			DPRINTFN(0, "Could not unconfigure "
			    "device (ignored)\n");
		}

		/* clear port enable */
		err = usbd_req_clear_port_feature(udev->parent_hub,
		    NULL, udev->port_no, UHF_PORT_ENABLE);
		break;

	case USB_POWER_MODE_ON:
	case USB_POWER_MODE_SAVE:
		break;

	case USB_POWER_MODE_RESUME:
#if USB_HAVE_POWERD
		/* let USB-powerd handle resume */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.write_refs++;
		udev->pwr_save.last_xfer_time = ticks;
		USB_BUS_UNLOCK(udev->bus);

		/* set new power mode */
		usbd_set_power_mode(udev, USB_POWER_MODE_SAVE);

		/* wait for resume to complete */
		usb_pause_mtx(NULL, hz / 4);

		/* clear write reference */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.write_refs--;
		USB_BUS_UNLOCK(udev->bus);
#endif
		mode = USB_POWER_MODE_SAVE;
		break;

	case USB_POWER_MODE_SUSPEND:
#if USB_HAVE_POWERD
		/* let USB-powerd handle suspend */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.last_xfer_time = ticks - (256 * hz);
		USB_BUS_UNLOCK(udev->bus);
#endif
		mode = USB_POWER_MODE_SAVE;
		break;

	default:
		return (EINVAL);
	}

	if (err)
		return (ENXIO);		/* I/O failure */

	/* if we are powered off we need to re-enumerate first */
	if (old_mode == USB_POWER_MODE_OFF) {
		if (udev->flags.usb_mode == USB_MODE_HOST) {
			if (udev->re_enumerate_wait == 0)
				udev->re_enumerate_wait = 1;
		}
		/* set power mode will wake up the explore thread */
	}

	/* set new power mode */
	usbd_set_power_mode(udev, mode);

	return (0);			/* success */
}
Example #15
0
static int
udsir_detach(device_t self, int flags)
{
	struct udsir_softc *sc = device_private(self);
	int s;
	int rv = 0;

	DPRINTFN(0, ("udsir_detach: sc=%p flags=%d\n", sc, flags));

	sc->sc_closing = sc->sc_dying = 1;

	wakeup(&sc->sc_thread);

	while (sc->sc_thread != NULL)
		tsleep(&sc->sc_closing, PWAIT, "usircl", 0);

	/* Abort all pipes.  Causes processes waiting for transfer to wake. */
	if (sc->sc_rd_pipe != NULL) {
		usbd_abort_pipe(sc->sc_rd_pipe);
	}
	if (sc->sc_wr_pipe != NULL) {
		usbd_abort_pipe(sc->sc_wr_pipe);
	}
	if (sc->sc_rd_xfer != NULL) {
		usbd_destroy_xfer(sc->sc_rd_xfer);
		sc->sc_rd_xfer = NULL;
		sc->sc_rd_buf = NULL;
	}
	if (sc->sc_wr_xfer != NULL) {
		usbd_destroy_xfer(sc->sc_wr_xfer);
		sc->sc_wr_xfer = NULL;
		sc->sc_wr_buf = NULL;
	}
	/* Close pipes. */
	if (sc->sc_rd_pipe != NULL) {
		usbd_close_pipe(sc->sc_rd_pipe);
		sc->sc_rd_pipe = NULL;
	}
	if (sc->sc_wr_pipe != NULL) {
		usbd_close_pipe(sc->sc_wr_pipe);
		sc->sc_wr_pipe = NULL;
	}
	wakeup(&sc->sc_ur_framelen);
	wakeup(&sc->sc_wr_buf);

	s = splusb();
	if (--sc->sc_refcnt >= 0) {
		/* Wait for processes to go away. */
		usb_detach_waitold(sc->sc_dev);
	}
	splx(s);

	if (sc->sc_child != NULL)
		rv = config_detach(sc->sc_child, flags);

	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);

	seldestroy(&sc->sc_rd_sel);
	seldestroy(&sc->sc_wr_sel);

	return rv;
}
Example #16
0
int
uftdi_param(void *vsc, int portno, struct termios *t)
{
	struct uftdi_softc *sc = vsc;
	usb_device_request_t req;
	usbd_status err;
	int rate, data, flow;

	DPRINTF(("uftdi_param: sc=%p\n", sc));

	if (usbd_is_dying(sc->sc_udev))
		return (EIO);

	switch (sc->sc_type) {
	case UFTDI_TYPE_SIO:
		switch (t->c_ospeed) {
		case 300: rate = ftdi_sio_b300; break;
		case 600: rate = ftdi_sio_b600; break;
		case 1200: rate = ftdi_sio_b1200; break;
		case 2400: rate = ftdi_sio_b2400; break;
		case 4800: rate = ftdi_sio_b4800; break;
		case 9600: rate = ftdi_sio_b9600; break;
		case 19200: rate = ftdi_sio_b19200; break;
		case 38400: rate = ftdi_sio_b38400; break;
		case 57600: rate = ftdi_sio_b57600; break;
		case 115200: rate = ftdi_sio_b115200; break;
		default:
			return (EINVAL);
		}
		break;

	case UFTDI_TYPE_8U232AM:
		if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1)
			return (EINVAL);
		break;
	case UFTDI_TYPE_2232H:
		if (uftdi_2232h_getrate(t->c_ospeed, &rate) == -1)
			 return (EINVAL);
		break;
	}
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_BAUD_RATE;
	USETW(req.wValue, rate);
	USETW(req.wIndex, ((rate >> 8) & 0xFF00) | portno);
	USETW(req.wLength, 0);
	DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
		    "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
		    UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	if (ISSET(t->c_cflag, CSTOPB))
		data = FTDI_SIO_SET_DATA_STOP_BITS_2;
	else
		data = FTDI_SIO_SET_DATA_STOP_BITS_1;
	if (ISSET(t->c_cflag, PARENB)) {
		if (ISSET(t->c_cflag, PARODD))
			data |= FTDI_SIO_SET_DATA_PARITY_ODD;
		else
			data |= FTDI_SIO_SET_DATA_PARITY_EVEN;
	} else
		data |= FTDI_SIO_SET_DATA_PARITY_NONE;
	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		data |= FTDI_SIO_SET_DATA_BITS(5);
		break;
	case CS6:
		data |= FTDI_SIO_SET_DATA_BITS(6);
		break;
	case CS7:
		data |= FTDI_SIO_SET_DATA_BITS(7);
		break;
	case CS8:
		data |= FTDI_SIO_SET_DATA_BITS(8);
		break;
	}
	sc->last_lcr = data;

	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_DATA;
	USETW(req.wValue, data);
	USETW(req.wIndex, portno);
	USETW(req.wLength, 0);
	DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
		    "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
		    UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	if (ISSET(t->c_cflag, CRTSCTS)) {
		flow = FTDI_SIO_RTS_CTS_HS;
		USETW(req.wValue, 0);
	} else if (ISSET(t->c_iflag, IXON|IXOFF)) {
		flow = FTDI_SIO_XON_XOFF_HS;
		USETW2(req.wValue, t->c_cc[VSTOP], t->c_cc[VSTART]);
	} else {
		flow = FTDI_SIO_DISABLE_FLOW_CTRL;
		USETW(req.wValue, 0);
	}
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
	USETW2(req.wIndex, flow, portno);
	USETW(req.wLength, 0);
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	return (0);
}
Example #17
0
/* ARGSUSED */
static int
udsir_open(void *h, int flag, int mode, struct lwp *l)
{
	struct udsir_softc *sc = h;
	int error;
	usbd_status err;

	DPRINTFN(0, ("%s: sc=%p\n", __func__, sc));

	err = usbd_open_pipe(sc->sc_iface, sc->sc_rd_addr, 0, &sc->sc_rd_pipe);
	if (err != USBD_NORMAL_COMPLETION) {
		error = EIO;
		goto bad1;
	}
	err = usbd_open_pipe(sc->sc_iface, sc->sc_wr_addr, 0, &sc->sc_wr_pipe);
	if (err != USBD_NORMAL_COMPLETION) {
		error = EIO;
		goto bad2;
	}
	error = usbd_create_xfer(sc->sc_rd_pipe, sc->sc_rd_maxpsz,
	    USBD_SHORT_XFER_OK, 0, &sc->sc_rd_xfer);
	if (error)
		 goto bad3;

	error = usbd_create_xfer(sc->sc_wr_pipe, IRDA_MAX_FRAME_SIZE,
	    USBD_FORCE_SHORT_XFER, 0, &sc->sc_wr_xfer);
	if (error)
		goto bad4;

	sc->sc_rd_buf = usbd_get_buffer(sc->sc_rd_xfer);
	sc->sc_wr_buf = usbd_get_buffer(sc->sc_wr_xfer);

	sc->sc_ur_buf = kmem_alloc(IRDA_MAX_FRAME_SIZE, KM_SLEEP);
	if (sc->sc_ur_buf == NULL) {
		error = ENOMEM;
		goto bad5;
	}

	sc->sc_rd_index = sc->sc_rd_count = 0;
	sc->sc_closing = 0;
	sc->sc_rd_readinprogress = 0;
	sc->sc_rd_expectdataticks = 0;
	sc->sc_ur_framelen = 0;
	sc->sc_rd_err = 0;
	sc->sc_wr_stalewrite = 0;
	sc->sc_direction = udir_idle;
	sc->sc_params.speed = 0;
	sc->sc_params.ebofs = 0;
	sc->sc_params.maxsize = min(sc->sc_rd_maxpsz, sc->sc_wr_maxpsz);

	deframe_init(&sc->sc_framestate, sc->sc_ur_buf, IRDA_MAX_FRAME_SIZE);

	/* Increment reference for thread */
	sc->sc_refcnt++;

	error = kthread_create(PRI_NONE, 0, NULL, udsir_thread, sc,
	    &sc->sc_thread, "%s", device_xname(sc->sc_dev));
	if (error) {
		sc->sc_refcnt--;
		goto bad5;
	}

	return 0;

 bad5:
	usbd_destroy_xfer(sc->sc_wr_xfer);
	sc->sc_wr_xfer = NULL;
 bad4:
	usbd_destroy_xfer(sc->sc_rd_xfer);
	sc->sc_rd_xfer = NULL;
 bad3:
	usbd_close_pipe(sc->sc_wr_pipe);
	sc->sc_wr_pipe = NULL;
 bad2:
	usbd_close_pipe(sc->sc_rd_pipe);
	sc->sc_rd_pipe = NULL;
 bad1:
	return error;
}
Example #18
0
void
uftdi_attach(struct device *parent, struct device *self, void *aux)
{
	struct uftdi_softc *sc = (struct uftdi_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct usbd_device *dev = uaa->device;
	struct usbd_interface *iface;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	char *devname = sc->sc_dev.dv_xname;
	int i;
	usbd_status err;
	struct ucom_attach_args uca;

	DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc));

	sc->sc_udev = dev;

	if (uaa->iface == NULL) {
		/* Move the device into the configured state. */
		err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1);
		if (err) {
			printf("%s: failed to set configuration, err=%s\n",
			    sc->sc_dev.dv_xname, usbd_errstr(err));
			goto bad;
		}

		err = usbd_device2interface_handle(dev, UFTDI_IFACE_INDEX, &iface);
		if (err) {
			printf("%s: failed to get interface, err=%s\n",
			    sc->sc_dev.dv_xname, usbd_errstr(err));
			goto bad;
		}
	} else
		iface = uaa->iface;

	id = usbd_get_interface_descriptor(iface);

	sc->sc_iface = iface;

	if (uaa->release < 0x0200) {
		sc->sc_type = UFTDI_TYPE_SIO;
		sc->sc_hdrlen = 1;
	} else if (uaa->release == 0x0700  || uaa->release == 0x0800) {
		sc->sc_type = UFTDI_TYPE_2232H;
		sc->sc_hdrlen = 0;
	} else {
		sc->sc_type = UFTDI_TYPE_8U232AM;
		sc->sc_hdrlen = 0;
	}

	uca.bulkin = uca.bulkout = -1;
	for (i = 0; i < id->bNumEndpoints; i++) {
		int addr, dir, attr;
		ed = usbd_interface2endpoint_descriptor(iface, i);
		if (ed == NULL) {
			printf("%s: could not read endpoint descriptor\n",
			    devname);
			goto bad;
		}

		addr = ed->bEndpointAddress;
		dir = UE_GET_DIR(ed->bEndpointAddress);
		attr = ed->bmAttributes & UE_XFERTYPE;
		if (dir == UE_DIR_IN && attr == UE_BULK) {
			uca.bulkin = addr;
			uca.ibufsize = (UGETW(ed->wMaxPacketSize) > 0) ?
			    UGETW(ed->wMaxPacketSize) : UFTDIIBUFSIZE;
		} else if (dir == UE_DIR_OUT && attr == UE_BULK) {
			uca.bulkout = addr;
			uca.obufsize = (UGETW(ed->wMaxPacketSize) > 0) ?
			    UGETW(ed->wMaxPacketSize) : UFTDIOBUFSIZE;
			uca.obufsize-= sc->sc_hdrlen;
		} else {
			printf("%s: unexpected endpoint\n", devname);
			goto bad;
		}
	}
	if (uca.bulkin == -1) {
		printf("%s: Could not find data bulk in\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}
	if (uca.bulkout == -1) {
		printf("%s: Could not find data bulk out\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}

	if (uaa->iface == NULL)
		uca.portno = FTDI_PIT_SIOA;
	else
		uca.portno = FTDI_PIT_SIOA + id->bInterfaceNumber;
	/* bulkin, bulkout set above */
	uca.ibufsizepad = uca.ibufsize;
	uca.opkthdrlen = sc->sc_hdrlen;
	uca.device = dev;
	uca.iface = iface;
	uca.methods = &uftdi_methods;
	uca.arg = sc;
	uca.info = NULL;

	DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);

	return;

bad:
	DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
	usbd_deactivate(sc->sc_udev);
}
Example #19
0
/* 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;
}
Example #20
0
void
hidms_input(struct hidms *ms, uint8_t *data, u_int len)
{
	int dx, dy, dz, dw;
	u_int32_t buttons = 0;
	int flags;
	int i, s;

	DPRINTFN(5,("hidms_input: len=%d\n", len));

	/*
	 * The Microsoft Wireless Intellimouse 2.0 sends one extra leading
	 * byte of data compared to most USB mice.  This byte frequently
	 * switches from 0x01 (usual state) to 0x02.  It may be used to
	 * report non-standard events (such as battery life).  However,
	 * at the same time, it generates a left click event on the
	 * button byte, where there shouldn't be any.  We simply discard
	 * the packet in this case.
	 *
	 * This problem affects the MS Wireless Notebook Optical Mouse, too.
	 * However, the leading byte for this mouse is normally 0x11, and
	 * the phantom mouse click occurs when it's 0x14.
	 */
	if (ms->sc_flags & HIDMS_LEADINGBYTE) {
		if (*data++ == 0x02)
			return;
		/* len--; */
	} else if (ms->sc_flags & HIDMS_SPUR_BUT_UP) {
		if (*data == 0x14 || *data == 0x15)
			return;
	}

	flags = WSMOUSE_INPUT_DELTA;
	if (ms->sc_flags & HIDMS_ABSX)
		flags |= WSMOUSE_INPUT_ABSOLUTE_X;
	if (ms->sc_flags & HIDMS_ABSY)
		flags |= WSMOUSE_INPUT_ABSOLUTE_Y;

	dx =  hid_get_data(data, len, &ms->sc_loc_x);
	dy = -hid_get_data(data, len, &ms->sc_loc_y);
	dz =  hid_get_data(data, len, &ms->sc_loc_z);
	dw =  hid_get_data(data, len, &ms->sc_loc_w);

	if (ms->sc_flags & HIDMS_ABSY)
		dy = -dy;
	if (ms->sc_flags & HIDMS_REVZ)
		dz = -dz;
	if (ms->sc_flags & HIDMS_REVW)
		dw = -dw;

	if (ms->sc_tsscale.swapxy && !ms->sc_rawmode) {
		int tmp = dx;
		dx = dy;
		dy = tmp;
	}

	if (!ms->sc_rawmode &&
	    (ms->sc_tsscale.maxx - ms->sc_tsscale.minx) != 0 &&
	    (ms->sc_tsscale.maxy - ms->sc_tsscale.miny) != 0) {
		/* Scale down to the screen resolution. */
		dx = ((dx - ms->sc_tsscale.minx) * ms->sc_tsscale.resx) /
		    (ms->sc_tsscale.maxx - ms->sc_tsscale.minx);
		dy = ((dy - ms->sc_tsscale.miny) * ms->sc_tsscale.resy) /
		    (ms->sc_tsscale.maxy - ms->sc_tsscale.miny);
	}

	for (i = 0; i < ms->sc_num_buttons; i++)
		if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
			buttons |= (1 << HIDMS_BUT(i));

	if (dx != 0 || dy != 0 || dz != 0 || dw != 0 ||
	    buttons != ms->sc_buttons) {
		DPRINTFN(10, ("hidms_input: x:%d y:%d z:%d w:%d buttons:0x%x\n",
			dx, dy, dz, dw, buttons));
		ms->sc_buttons = buttons;
		if (ms->sc_wsmousedev != NULL) {
			s = spltty();
			wsmouse_input(ms->sc_wsmousedev, buttons,
			    dx, dy, dz, dw, flags);
			splx(s);
		}
	}
}
Example #21
0
int
kue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
	struct kue_softc	*sc = ifp->if_softc;
	struct ifaddr 		*ifa = (struct ifaddr *)data;
	int			s, error = 0;

	DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));

	if (sc->kue_dying)
		return (EIO);

#ifdef DIAGNOSTIC
	if (!curproc) {
		printf("%s: no proc!!\n", sc->kue_dev.dv_xname);
		return EIO;
	}
#endif

	s = splnet();

	switch(command) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		kue_init(sc);

		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			arp_ifinit(&sc->arpcom, ifa);
			break;
#endif /* INET */
		}
		break;

	case SIOCSIFFLAGS:
		if (ifp->if_flags & IFF_UP) {
			if (ifp->if_flags & IFF_RUNNING &&
			    ifp->if_flags & IFF_PROMISC &&
			    !(sc->kue_if_flags & IFF_PROMISC)) {
				sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
				kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
				    sc->kue_rxfilt);
			} else if (ifp->if_flags & IFF_RUNNING &&
			    !(ifp->if_flags & IFF_PROMISC) &&
			    sc->kue_if_flags & IFF_PROMISC) {
				sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
				kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
				    sc->kue_rxfilt);
			} else if (!(ifp->if_flags & IFF_RUNNING))
				kue_init(sc);
		} else {
			if (ifp->if_flags & IFF_RUNNING)
				kue_stop(sc);
		}
		sc->kue_if_flags = ifp->if_flags;
		error = 0;
		break;

	default:
		error = ether_ioctl(ifp, &sc->arpcom, command, data);
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			kue_setmulti(sc);
		error = 0;
	}

	splx(s);
	return (error);
}
Example #22
0
void
ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
{
	int mod, omod;
	u_int16_t ibuf[MAXKEYS];	/* chars events */
	int s;
	int nkeys, i, j;
	int key;
#define ADDKEY(c) ibuf[nkeys++] = (c)

#ifdef UKBD_DEBUG
	/*
	 * Keep a trace of the last events.  Using printf changes the
	 * timing, so this can be useful sometimes.
	 */
	if (ukbdtrace) {
		struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
		p->unit = sc->sc_hdev.sc_dev.dv_unit;
		microtime(&p->tv);
		p->ud = *ud;
		if (++ukbdtraceindex >= UKBDTRACESIZE)
			ukbdtraceindex = 0;
	}
	if (ukbddebug > 5) {
		struct timeval tv;
		microtime(&tv);
		DPRINTF((" at %lu.%06lu  mod=0x%02x key0=0x%02x key1=0x%02x "
			 "key2=0x%02x key3=0x%02x\n",
			 tv.tv_sec, tv.tv_usec,
			 ud->modifiers, ud->keycode[0], ud->keycode[1],
			 ud->keycode[2], ud->keycode[3]));
	}
#endif

	if (ud->keycode[0] == KEY_ERROR) {
		DPRINTF(("ukbd_intr: KEY_ERROR\n"));
		return;		/* ignore  */
	}
	nkeys = 0;
	mod = ud->modifiers;
	omod = sc->sc_odata.modifiers;
	if (mod != omod)
		for (i = 0; i < sc->sc_nmod; i++)
			if (( mod & sc->sc_mods[i].mask) !=
			    (omod & sc->sc_mods[i].mask))
				ADDKEY(sc->sc_mods[i].key |
				       (mod & sc->sc_mods[i].mask
					  ? PRESS : RELEASE));
	if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
		/* Check for released keys. */
		for (i = 0; i < sc->sc_nkeycode; i++) {
			key = sc->sc_odata.keycode[i];
			if (key == 0)
				continue;
			for (j = 0; j < sc->sc_nkeycode; j++)
				if (key == ud->keycode[j])
					goto rfound;
			DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key));
			ADDKEY(key | RELEASE);
		rfound:
			;
		}

		/* Check for pressed keys. */
		for (i = 0; i < sc->sc_nkeycode; i++) {
			key = ud->keycode[i];
			if (key == 0)
				continue;
			for (j = 0; j < sc->sc_nkeycode; j++)
				if (key == sc->sc_odata.keycode[j])
					goto pfound;
			DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key));
			ADDKEY(key | PRESS);
		pfound:
			;
		}
	}
	sc->sc_odata = *ud;

	if (nkeys == 0)
		return;

	if (sc->sc_polling) {
		DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0]));
		memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
		sc->sc_npollchar = nkeys;
		return;
	}
#ifdef WSDISPLAY_COMPAT_RAWKBD
	if (sc->sc_rawkbd) {
		u_char cbuf[MAXKEYS * 2];
		int c;
		int npress;

		for (npress = i = j = 0; i < nkeys; i++) {
			key = ibuf[i];
			c = ukbd_trtab[key & CODEMASK];
			if (c == NN)
				continue;
			if (c & 0x80)
				cbuf[j++] = 0xe0;
			cbuf[j] = c & 0x7f;
			if (key & RELEASE)
				cbuf[j] |= 0x80;
			else {
				/* remember pressed keys for autorepeat */
				if (c & 0x80)
					sc->sc_rep[npress++] = 0xe0;
				sc->sc_rep[npress++] = c & 0x7f;
			}
			DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n",
				    c & 0x80 ? "0xe0 " : "",
				    cbuf[j]));
			j++;
		}
		s = spltty();
		wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
		splx(s);
		if (npress != 0) {
			sc->sc_nrep = npress;
			timeout_add(&sc->sc_rawrepeat_ch,
			    hz * REP_DELAY1 / 1000);
		} else
			timeout_del(&sc->sc_rawrepeat_ch);
		return;
	}
#endif

	s = spltty();
	for (i = 0; i < nkeys; i++) {
		key = ibuf[i];
		wskbd_input(sc->sc_wskbddev,
		    key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
		    key&CODEMASK);
	}
	splx(s);
}
Example #23
0
int
kue_load_fw(struct kue_softc *sc)
{
	usb_device_descriptor_t dd;
	usbd_status		err;
	struct kue_firmware	*fw;
	u_char			*buf;
	size_t			buflen;

	DPRINTFN(1,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));

	/*
	 * First, check if we even need to load the firmware.
	 * If the device was still attached when the system was
	 * rebooted, it may already have firmware loaded in it.
	 * If this is the case, we don't need to do it again.
	 * And in fact, if we try to load it again, we'll hang,
	 * so we have to avoid this condition if we don't want
	 * to look stupid.
	 *
	 * We can test this quickly by checking the bcdRevision
	 * code. The NIC will return a different revision code if
	 * it's probed while the firmware is still loaded and
	 * running.
	 */
	if (usbd_get_device_desc(sc->kue_udev, &dd))
		return (EIO);
	if (UGETW(dd.bcdDevice) >= KUE_WARM_REV) {
		printf("%s: warm boot, no firmware download\n",
		       sc->kue_dev.dv_xname);
		return (0);
	}

	err = loadfirmware("kue", &buf, &buflen);
	if (err) {
		printf("%s: failed loadfirmware of file %s: errno %d\n",
		    sc->kue_dev.dv_xname, "kue", err);
		return (err);
	}
	fw = (struct kue_firmware *)buf;

	printf("%s: cold boot, downloading firmware\n",
	       sc->kue_dev.dv_xname);

	/* Load code segment */
	DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[0], ntohl(fw->codeseglen));
	if (err) {
		printf("%s: failed to load code segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}

	/* Load fixup segment */
	DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[ntohl(fw->codeseglen)], ntohl(fw->fixseglen));
	if (err) {
		printf("%s: failed to load fixup segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}

	/* Send trigger command. */
	DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[ntohl(fw->codeseglen) + ntohl(fw->fixseglen)],
	    ntohl(fw->trigseglen));
	if (err) {
		printf("%s: failed to load trigger segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}
	free(buf, M_DEVBUF);

	usbd_delay_ms(sc->kue_udev, 10);

	/*
	 * Reload device descriptor.
	 * Why? The chip without the firmware loaded returns
	 * one revision code. The chip with the firmware
	 * loaded and running returns a *different* revision
	 * code. This confuses the quirk mechanism, which is
	 * dependent on the revision data.
	 */
	(void)usbd_reload_device_desc(sc->kue_udev);

	DPRINTFN(1,("%s: %s: done\n", sc->kue_dev.dv_xname, __func__));

	/* Reset the adapter. */
	kue_reset(sc);

	return (0);
}
Example #24
0
static void
usie_if_rx_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct usie_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m0;
	struct mbuf *m = NULL;
	struct usie_desc *rxd;
	uint32_t actlen;
	uint16_t err;
	uint16_t pkt;
	uint16_t ipl;
	uint16_t len;
	uint16_t diff;
	uint8_t pad;
	uint8_t ipv;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(15, "rx done, actlen=%u\n", actlen);

		if (actlen < sizeof(struct usie_hip)) {
			DPRINTF("data too short %u\n", actlen);
			goto tr_setup;
		}
		m = sc->sc_rxm;
		sc->sc_rxm = NULL;

		/* fall though */
	case USB_ST_SETUP:
tr_setup:

		if (sc->sc_rxm == NULL) {
			sc->sc_rxm = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR,
			    MJUMPAGESIZE /* could be bigger than MCLBYTES */ );
		}
		if (sc->sc_rxm == NULL) {
			DPRINTF("could not allocate Rx mbuf\n");
			ifp->if_ierrors++;
			usbd_xfer_set_stall(xfer);
			usbd_xfer_set_frames(xfer, 0);
		} else {
			/*
			 * Directly loading a mbuf cluster into DMA to
			 * save some data copying. This works because
			 * there is only one cluster.
			 */
			usbd_xfer_set_frame_data(xfer, 0,
			    mtod(sc->sc_rxm, caddr_t), MIN(MJUMPAGESIZE, USIE_RXSZ_MAX));
			usbd_xfer_set_frames(xfer, 1);
		}
		usbd_transfer_submit(xfer);
		break;

	default:			/* Error */
		DPRINTF("USB transfer error, %s\n", usbd_errstr(error));

		if (error != USB_ERR_CANCELLED) {
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			ifp->if_ierrors++;
			goto tr_setup;
		}
		if (sc->sc_rxm != NULL) {
			m_freem(sc->sc_rxm);
			sc->sc_rxm = NULL;
		}
		break;
	}

	if (m == NULL)
		return;

	mtx_unlock(&sc->sc_mtx);

	m->m_pkthdr.len = m->m_len = actlen;

	err = pkt = 0;

	/* HW can aggregate multiple frames in a single USB xfer */
	for (;;) {
		rxd = mtod(m, struct usie_desc *);

		len = be16toh(rxd->hip.len) & USIE_HIP_IP_LEN_MASK;
		pad = (rxd->hip.id & USIE_HIP_PAD) ? 1 : 0;
		ipl = (len - pad - ETHER_HDR_LEN);
		if (ipl >= len) {
			DPRINTF("Corrupt frame\n");
			m_freem(m);
			break;
		}
		diff = sizeof(struct usie_desc) + ipl + pad;

		if (((rxd->hip.id & USIE_HIP_MASK) != USIE_HIP_IP) ||
		    (be16toh(rxd->desc_type) & USIE_TYPE_MASK) != USIE_IP_RX) {
			DPRINTF("received wrong type of packet\n");
			m->m_data += diff;
			m->m_pkthdr.len = (m->m_len -= diff);
			err++;
			if (m->m_pkthdr.len > 0)
				continue;
			m_freem(m);
			break;
		}
		switch (be16toh(rxd->ethhdr.ether_type)) {
		case ETHERTYPE_IP:
			ipv = NETISR_IP;
			break;
#ifdef INET6
		case ETHERTYPE_IPV6:
			ipv = NETISR_IPV6;
			break;
#endif
		default:
			DPRINTF("unsupported ether type\n");
			err++;
			break;
		}

		/* the last packet */
		if (m->m_pkthdr.len <= diff) {
			m->m_data += (sizeof(struct usie_desc) + pad);
			m->m_pkthdr.len = m->m_len = ipl;
			m->m_pkthdr.rcvif = ifp;
			BPF_MTAP(sc->sc_ifp, m);
			netisr_dispatch(ipv, m);
			break;
		}
		/* copy aggregated frames to another mbuf */
		m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
		if (__predict_false(m0 == NULL)) {
			DPRINTF("could not allocate mbuf\n");
			err++;
			m_freem(m);
			break;
		}
		m_copydata(m, sizeof(struct usie_desc) + pad, ipl, mtod(m0, caddr_t));
		m0->m_pkthdr.rcvif = ifp;
		m0->m_pkthdr.len = m0->m_len = ipl;

		BPF_MTAP(sc->sc_ifp, m0);
		netisr_dispatch(ipv, m0);

		m->m_data += diff;
		m->m_pkthdr.len = (m->m_len -= diff);
	}

	mtx_lock(&sc->sc_mtx);

	ifp->if_ierrors += err;
	ifp->if_ipackets += pkt;
}
Example #25
0
void
kue_init(void *xsc)
{
	struct kue_softc	*sc = xsc;
	struct ifnet		*ifp = GET_IFP(sc);
	int			s;
	u_char			*eaddr;

	DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));

	if (ifp->if_flags & IFF_RUNNING)
		return;

	s = splnet();

	eaddr = sc->arpcom.ac_enaddr;
	/* Set MAC address */
	kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN);

	sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST;

	 /* If we want promiscuous mode, set the allframes bit. */
	if (ifp->if_flags & IFF_PROMISC)
		sc->kue_rxfilt |= KUE_RXFILT_PROMISC;

	kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);

	/* I'm not sure how to tune these. */
#if 0
	/*
	 * Leave this one alone for now; setting it
	 * wrong causes lockups on some machines/controllers.
	 */
	kue_setword(sc, KUE_CMD_SET_SOFS, 1);
#endif
	kue_setword(sc, KUE_CMD_SET_URB_SIZE, 64);

	/* Init TX ring. */
	if (kue_tx_list_init(sc) == ENOBUFS) {
		printf("%s: tx list init failed\n", sc->kue_dev.dv_xname);
		splx(s);
		return;
	}

	/* Init RX ring. */
	if (kue_rx_list_init(sc) == ENOBUFS) {
		printf("%s: rx list init failed\n", sc->kue_dev.dv_xname);
		splx(s);
		return;
	}

	/* Load the multicast filter. */
	kue_setmulti(sc);

	if (sc->kue_ep[KUE_ENDPT_RX] == NULL) {
		if (kue_open_pipes(sc)) {
			splx(s);
			return;
		}
	}

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	splx(s);
}
Example #26
0
static void
usie_if_tx_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct usie_softc *sc = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc;
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m;
	uint16_t size;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(11, "transfer complete\n");
		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
		ifp->if_opackets++;

		/* fall though */
	case USB_ST_SETUP:
tr_setup:

		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
			break;

		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
		if (m == NULL)
			break;

		if (m->m_pkthdr.len > (MCLBYTES - ETHER_HDR_LEN +
		    ETHER_CRC_LEN - sizeof(sc->sc_txd))) {
			DPRINTF("packet len is too big: %d\n",
			    m->m_pkthdr.len);
			break;
		}
		pc = usbd_xfer_get_frame(xfer, 0);

		sc->sc_txd.hip.len = htobe16(m->m_pkthdr.len +
		    ETHER_HDR_LEN + ETHER_CRC_LEN);
		size = sizeof(sc->sc_txd);

		usbd_copy_in(pc, 0, &sc->sc_txd, size);
		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len +
		    size + ETHER_CRC_LEN);

		BPF_MTAP(ifp, m);

		m_freem(m);

		usbd_transfer_submit(xfer);
		break;

	default:			/* Error */
		DPRINTF("USB transfer error, %s\n",
		    usbd_errstr(error));
		ifp->if_oerrors++;

		if (error != USB_ERR_CANCELLED) {
			usbd_xfer_set_stall(xfer);
			ifp->if_ierrors++;
			goto tr_setup;
		}
		break;
	}
}
Example #27
0
static int
ukbd_interrupt(keyboard_t *kbd, void *arg)
{
	usbd_status status = (usbd_status)arg;
	ukbd_state_t *state;
	struct ukbd_data *ud;
	struct timeval tv;
	u_long now;
	int mod, omod;
	int key, c;
	int i, j;

	DPRINTFN(5, ("ukbd_intr: status=%d\n", status));
	if (status == USBD_CANCELLED)
		return 0;

	state = (ukbd_state_t *)kbd->kb_data;
	ud = &state->ks_ndata;

	if (status != USBD_NORMAL_COMPLETION) {
		DPRINTF(("ukbd_intr: status=%d\n", status));
		if (status == USBD_STALLED)
		    usbd_clear_endpoint_stall_async(state->ks_intrpipe);
		return 0;
	}

	if (ud->keycode[0] == KEY_ERROR) {
		return 0;		/* ignore  */
	}

	getmicrouptime(&tv);
	now = (u_long)tv.tv_sec*1000 + (u_long)tv.tv_usec/1000;

#define ADDKEY1(c) 		\
	if (state->ks_inputs < INPUTBUFSIZE) {				\
		state->ks_input[state->ks_inputtail] = (c);		\
		++state->ks_inputs;					\
		state->ks_inputtail = (state->ks_inputtail + 1)%INPUTBUFSIZE; \
	}

	mod = ud->modifiers;
	omod = state->ks_odata.modifiers;
	if (mod != omod) {
		for (i = 0; i < NMOD; i++)
			if (( mod & ukbd_mods[i].mask) !=
			    (omod & ukbd_mods[i].mask))
				ADDKEY1(ukbd_mods[i].key |
				       (mod & ukbd_mods[i].mask
					  ? KEY_PRESS : KEY_RELEASE));
	}

	/* Check for released keys. */
	for (i = 0; i < NKEYCODE; i++) {
		key = state->ks_odata.keycode[i];
		if (key == 0)
			continue;
		for (j = 0; j < NKEYCODE; j++) {
			if (ud->keycode[j] == 0)
				continue;
			if (key == ud->keycode[j])
				goto rfound;
		}
		ADDKEY1(key | KEY_RELEASE);
	rfound:
		;
	}

	/* Check for pressed keys. */
	for (i = 0; i < NKEYCODE; i++) {
		key = ud->keycode[i];
		if (key == 0)
			continue;
		state->ks_ntime[i] = now + kbd->kb_delay1;
		for (j = 0; j < NKEYCODE; j++) {
			if (state->ks_odata.keycode[j] == 0)
				continue;
			if (key == state->ks_odata.keycode[j]) {
				state->ks_ntime[i] = state->ks_otime[j];
				if (state->ks_otime[j] > now)
					goto pfound;
				state->ks_ntime[i] = now + kbd->kb_delay2;
				break;
			}
		}
		ADDKEY1(key | KEY_PRESS);
		/*
		 * If any other key is presently down, force its repeat to be
		 * well in the future (100s).  This makes the last key to be
		 * pressed do the autorepeat.
		 */
		for (j = 0; j < NKEYCODE; j++) {
			if (j != i)
				state->ks_ntime[j] = now + 100 * 1000;
		}
	pfound:
		;
	}

	state->ks_odata = *ud;
	bcopy(state->ks_ntime, state->ks_otime, sizeof(state->ks_ntime));
	if (state->ks_inputs <= 0) {
		return 0;
	}

#ifdef USB_DEBUG
	for (i = state->ks_inputhead, j = 0; j < state->ks_inputs; ++j,
		i = (i + 1)%INPUTBUFSIZE) {
		c = state->ks_input[i];
		DPRINTF(("0x%x (%d) %s\n", c, c,
			(c & KEY_RELEASE) ? "released":"pressed"));
	}
	if (ud->modifiers)
		DPRINTF(("mod:0x%04x ", ud->modifiers));
        for (i = 0; i < NKEYCODE; i++) {
		if (ud->keycode[i])
			DPRINTF(("%d ", ud->keycode[i]));
	}
	DPRINTF(("\n"));
#endif /* USB_DEBUG */

	if (state->ks_polling) {
		return 0;
	}

	if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
		/* let the callback function to process the input */
		(*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
					    kbd->kb_callback.kc_arg);
	} else {
		/* read and discard the input; no one is waiting for it */
		do {
			c = ukbd_read_char(kbd, FALSE);
		} while (c != NOKEY);
	}

	return 0;
}
Example #28
0
static void
udsir_attach(device_t parent, device_t self, void *aux)
{
	struct udsir_softc *sc = device_private(self);
	struct usbif_attach_arg *uiaa = aux;
	struct usbd_device *dev = uiaa->uiaa_device;
	struct usbd_interface *iface = uiaa->uiaa_iface;
	char *devinfop;
	usb_endpoint_descriptor_t *ed;
	uint8_t epcount;
	int i;
	struct ir_attach_args ia;

	DPRINTFN(10, ("udsir_attach: sc=%p\n", sc));

	sc->sc_dev = self;

	aprint_naive("\n");
	aprint_normal("\n");

	devinfop = usbd_devinfo_alloc(dev, 0);
	aprint_normal_dev(self, "%s\n", devinfop);
	usbd_devinfo_free(devinfop);

	sc->sc_udev = dev;
	sc->sc_iface = iface;

	epcount = 0;
	(void)usbd_endpoint_count(iface, &epcount);

	sc->sc_rd_addr = -1;
	sc->sc_wr_addr = -1;
	for (i = 0; i < epcount; i++) {
		ed = usbd_interface2endpoint_descriptor(iface, i);
		if (ed == NULL) {
			aprint_error_dev(self, "couldn't get ep %d\n", i);
			return;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_rd_addr = ed->bEndpointAddress;
			sc->sc_rd_maxpsz = UGETW(ed->wMaxPacketSize);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_wr_addr = ed->bEndpointAddress;
			sc->sc_wr_maxpsz = UGETW(ed->wMaxPacketSize);
		}
	}
	if (sc->sc_rd_addr == -1 || sc->sc_wr_addr == -1) {
		aprint_error_dev(self, "missing endpoint\n");
		return;
	}

	DPRINTFN(10, ("udsir_attach: %p\n", sc->sc_udev));

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);

	ia.ia_type = IR_TYPE_IRFRAME;
	ia.ia_methods = &udsir_methods;
	ia.ia_handle = sc;

	sc->sc_child = config_found(self, &ia, ir_print);
	selinit(&sc->sc_rd_sel);
	selinit(&sc->sc_wr_sel);

	return;
}
Example #29
0
void
wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */,
	int x, int y, int z, int w, u_int flags)
{
	struct wsmouse_softc *sc = device_private(wsmousedev);
	struct wseventvar *evar;
	int mb, ub, d, nevents;
	/* one for each dimension (4) + a bit for each button */
	struct wscons_event events[4 + sizeof(d) * 8];

        /*
         * Discard input if not open.
         */
	evar = sc->sc_base.me_evp;
	if (evar == NULL)
		return;

#ifdef DIAGNOSTIC
	if (evar->q == NULL) {
		printf("wsmouse_input: evar->q=NULL\n");
		return;
	}
#endif

#if NWSMUX > 0
	DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n",
		    device_xname(sc->sc_base.me_dv),
		    sc->sc_base.me_parent, evar));
#endif

	sc->sc_mb = btns;
	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
		sc->sc_dx += x;
	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
		sc->sc_dy += y;
	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z))
		sc->sc_dz += z;
	if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W))
		sc->sc_dw += w;

	/*
	 * We have at least one event (mouse button, delta-X, or
	 * delta-Y; possibly all three, and possibly three separate
	 * button events).  Deliver these events until we are out
	 * of changes or out of room.  As events get delivered,
	 * mark them `unchanged'.
	 */
	ub = sc->sc_ub;
	nevents = 0;

	if (flags & WSMOUSE_INPUT_ABSOLUTE_X) {
		if (sc->sc_x != x) {
			events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_X;
			events[nevents].value = x;
			nevents++;
		}
	} else {
		if (sc->sc_dx) {
			events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_X;
			events[nevents].value = sc->sc_dx;
			nevents++;
		}
	}
	if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) {
		if (sc->sc_y != y) {
			events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y;
			events[nevents].value = y;
			nevents++;
		}
	} else {
		if (sc->sc_dy) {
			events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Y;
			events[nevents].value = sc->sc_dy;
			nevents++;
		}
	}
	if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) {
		if (sc->sc_z != z) {
			events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z;
			events[nevents].value = z;
			nevents++;
		}
	} else {
		if (sc->sc_dz) {
			events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_Z;
			events[nevents].value = sc->sc_dz;
			nevents++;
		}
	}
	if (flags & WSMOUSE_INPUT_ABSOLUTE_W) {
		if (sc->sc_w != w) {
			events[nevents].type = WSCONS_EVENT_MOUSE_ABSOLUTE_W;
			events[nevents].value = w;
			nevents++;
		}
	} else {
		if (sc->sc_dw) {
			events[nevents].type = WSCONS_EVENT_MOUSE_DELTA_W;
			events[nevents].value = sc->sc_dw;
			nevents++;
		}
	}

	mb = sc->sc_mb;
	while ((d = mb ^ ub) != 0) {
		int btnno;

		/*
		 * Cancel button repeating if button status changed.
		 */
		if (sc->sc_repeat_button != -1) {
			KASSERT(sc->sc_repeat_button >= 0);
			KASSERT(sc->sc_repeat.wr_buttons &
                            (1 << sc->sc_repeat_button));
			ub &= ~(1 << sc->sc_repeat_button);
			sc->sc_repeat_button = -1;
			callout_stop(&sc->sc_repeat_callout);
		}

		/*
		 * Mouse button change.  Find the first change and drop
		 * it into the event queue.
		 */
		btnno = ffs(d) - 1;
		KASSERT(btnno >= 0);

		if (nevents >= sizeof(events) / sizeof(events[0])) {
			aprint_error_dev(sc->sc_base.me_dv,
			    "Event queue full (button status mb=0x%x"
			    " ub=0x%x)\n", mb, ub);
			break;
		}

		events[nevents].type =
		    (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
		events[nevents].value = btnno;
		nevents++;

		ub ^= (1 << btnno);

		/*
		 * Program button repeating if configured for this button.
		 */
		if ((mb & d) && (sc->sc_repeat.wr_buttons & (1 << btnno)) &&
		    sc->sc_repeat.wr_delay_first > 0) {
			sc->sc_repeat_button = btnno;
			sc->sc_repeat_delay = sc->sc_repeat.wr_delay_first;
			callout_schedule(&sc->sc_repeat_callout,
			    mstohz(sc->sc_repeat_delay));
		}
	}

	if (nevents == 0 || wsevent_inject(evar, events, nevents) == 0) {
		/* All events were correctly injected into the queue.
		 * Synchronize the mouse's status with what the user
		 * has received. */
		sc->sc_x = x; sc->sc_dx = 0;
		sc->sc_y = y; sc->sc_dy = 0;
		sc->sc_z = z; sc->sc_dz = 0;
		sc->sc_w = w; sc->sc_dw = 0;
		sc->sc_ub = ub;
#if NWSMUX > 0
		DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n",
			    device_xname(sc->sc_base.me_dv), evar));
#endif
	}
}
Example #30
0
int
wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
{
	struct wi_usb_chain	*c;
	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
	struct wi_wridreq	*prid;
	int			total_len, rnd_len;
	int			err;
	struct wi_ltv_gen	p2ltv;
	u_int16_t		val = 0;
	int			i;

	DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
	    (ltv->wi_len-1)*2 ));

	/* Do we need to deal with these here, as in _io version?
	 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
	 * RID_TX_RATE munging
	 * RID_ENCRYPTION
	 * WI_RID_TX_CRYPT_KEY
	 * WI_RID_DEFLT_CRYPT_KEYS
	 */
	if (ltv->wi_type == WI_RID_PORTTYPE &&
	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
		p2ltv.wi_type = WI_RID_PORTTYPE;
		p2ltv.wi_len = 2;
		p2ltv.wi_val = wsc->wi_ibss_port;
		ltv = &p2ltv;
	} else if (wsc->sc_firmware_type != WI_LUCENT) {
		int v;

		switch (ltv->wi_type) {
		case WI_RID_TX_RATE:
			p2ltv.wi_type = WI_RID_TX_RATE;
			p2ltv.wi_len = 2;
			switch (letoh16(ltv->wi_val)) {
			case 1: v = 1; break;
			case 2: v = 2; break;
			case 3:	v = 15; break;
			case 5: v = 4; break;
			case 6: v = 3; break;
			case 7: v = 7; break;
			case 11: v = 8; break;
			default: return EINVAL;
			}
			p2ltv.wi_val = htole16(v);
			ltv = &p2ltv;
			break;
		case WI_RID_ENCRYPTION:
			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
			p2ltv.wi_len = 2;
			if (ltv->wi_val & htole16(0x01)) {
				val = PRIVACY_INVOKED;
				/*
				 * If using shared key WEP we must set the
				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
				 * need this bit set even when not using
				 * shared key. We can't just test for
				 * IEEE80211_AUTH_SHARED since Symbol cards
				 * have 2 shared key modes.
				 */
				if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
				    wsc->sc_firmware_type == WI_SYMBOL)
					val |= EXCLUDE_UNENCRYPTED;

				switch (wsc->wi_crypto_algorithm) {
				case WI_CRYPTO_FIRMWARE_WEP:
					/*
					 * TX encryption is broken in
					 * Host AP mode.
					 */
					if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
						val |= HOST_ENCRYPT;
					break;
				case WI_CRYPTO_SOFTWARE_WEP:
					val |= HOST_ENCRYPT|HOST_DECRYPT;
					break;
				}
				p2ltv.wi_val = htole16(val);
			} else
				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
			ltv = &p2ltv;
			break;
		case WI_RID_TX_CRYPT_KEY:
			if (ltv->wi_val > WI_NLTV_KEYS)
				return (EINVAL);
			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
			p2ltv.wi_len = 2;
			p2ltv.wi_val = ltv->wi_val;
			ltv = &p2ltv;
			break;
		case WI_RID_DEFLT_CRYPT_KEYS: {
				int error;
				int keylen;
				struct wi_ltv_str ws;
				struct wi_ltv_keys *wk;

				wk = (struct wi_ltv_keys *)ltv;
				keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
				keylen = letoh16(keylen);

				for (i = 0; i < 4; i++) {
					bzero(&ws, sizeof(ws));
					ws.wi_len = (keylen > 5) ? 8 : 4;
					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
					bcopy(&wk->wi_keys[i].wi_keydat,
					    ws.wi_str, keylen);
					error = wi_write_record_usb(wsc,
					    (struct wi_ltv_gen *)&ws);
					if (error)
						return (error);
				}
			}
			return (0);
		}
	}

	wi_usb_tx_lock(sc);

	c = &sc->wi_usb_tx_chain[0];

	prid = c->wi_usb_buf;

	total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
	    sizeof(prid->rid) + (ltv->wi_len-1)*2;
	rnd_len = ROUNDUP64(total_len);
	if (rnd_len > WI_USB_BUFSZ) {
		printf("write_record buf size err %x %x\n", 
		    rnd_len, WI_USB_BUFSZ);
		wi_usb_tx_unlock(sc);
		return EIO;
	}

	prid->type = htole16(WI_USB_WRIDREQ);
	prid->frmlen = htole16(ltv->wi_len);
	prid->rid  = htole16(ltv->wi_type);
	if (ltv->wi_len > 1)
		bcopy(&ltv->wi_val, &prid->data[0], (ltv->wi_len-1)*2);

	bzero(((char*)prid)+total_len, rnd_len - total_len);

	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
	    WI_USB_TX_TIMEOUT, wi_usb_txeof);

	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);

	if (err == 0)
		err = sc->ridresperr;

	sc->ridresperr = 0;

	wi_usb_tx_unlock(sc);

	DPRINTFN(5,("%s: %s: exit err=%x\n",
	    sc->wi_usb_dev.dv_xname, __func__, err));
	return err;
}