static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep,
					 struct usbhsg_request *ureq)
{
	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
	struct usb_request *req = &ureq->req;
	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
	void *buf;
	int maxp;
	int remainder, recv;
	int is_done = 0;

	/*
	 *********  assume under spin lock  *********
	 */

	maxp		= usbhs_pipe_get_maxpacket(pipe);
	buf		= req->buf    + req->actual;
	remainder	= req->length - req->actual;

	recv = usbhs_fifo_read(pipe, buf, remainder);
	/*
	 * recv < 0  : pipe busy
	 * recv >= 0 : receive data
	 *
	 * recv <= max_packet
	 */
	if (recv < 0)
		return -EBUSY;

	/* update parameters */
	req->actual += recv;

	if ((recv == remainder) ||	/* receive all data */
	    (recv < maxp))		/* short packet */
		is_done = 1;

	dev_dbg(dev, "  recv %d (%d/ %d/ %d/ %d)\n",
		usbhs_pipe_number(pipe),
		remainder, recv, is_done, req->zero);

	/* read all data ? */
	if (is_done) {
		int disable = 0;

		uep->handler->irq_mask(uep, disable);
		usbhs_fifo_disable(pipe);
		usbhsg_queue_pop(uep, ureq, 0);
	}

	return 0;
}
예제 #2
0
파일: pipe.c 프로젝트: 7799/linux
void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
{
	if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
		return;

	/*
	 * clear and disable transfer counter for IN/OUT pipe
	 */
	usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR);

	/*
	 * Only IN direction bulk pipe can use transfer count.
	 * Without using this function,
	 * received data will break if it was large data size.
	 * see PIPEnTRN/PIPEnTRE for detail
	 */
	if (usbhs_pipe_is_dir_in(pipe)) {
		int maxp = usbhs_pipe_get_maxpacket(pipe);

		usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp));
		usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */
	}
}
static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep,
				      struct usbhsg_request *ureq)
{
	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
	struct usb_request *req = &ureq->req;
	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
	void *buf;
	int remainder, send;
	int is_done = 0;
	int enable;
	int maxp;

	/*
	 *********  assume under spin lock  *********
	 */

	maxp		= usbhs_pipe_get_maxpacket(pipe);
	buf		= req->buf    + req->actual;
	remainder	= req->length - req->actual;

	send = usbhs_fifo_write(pipe, buf, remainder);

	/*
	 * send < 0 : pipe busy
	 * send = 0 : send zero packet
	 * send > 0 : send data
	 *
	 * send <= max_packet
	 */
	if (send > 0)
		req->actual += send;

	/* send all packet ? */
	if (send < remainder)
		is_done = 0;		/* there are remainder data */
	else if (send < maxp)
		is_done = 1;		/* short packet */
	else
		is_done = !req->zero;	/* send zero packet ? */

	dev_dbg(dev, "  send %d (%d/ %d/ %d/ %d)\n",
		usbhs_pipe_number(pipe),
		remainder, send, is_done, req->zero);

	/*
	 * enable interrupt and send again in irq handler
	 * if it still have remainder data which should be sent.
	 */
	enable = !is_done;
	uep->handler->irq_mask(uep, enable);

	/*
	 * usbhs_fifo_enable execute
	 *  - after callback_update,
	 *  - before queue_pop / stage_end
	 */
	usbhs_fifo_enable(pipe);

	/*
	 * all data were sent ?
	 */
	if (is_done) {
		/* it care below call in
		   "function mode" */
		if (usbhsg_is_dcp(uep))
			usbhs_dcp_control_transfer_done(pipe);

		usbhsg_queue_pop(uep, ureq, 0);
	}

	return 0;
}