r8a66597-hcd.c

来自「linux 内核源代码」· C语言 代码 · 共 2,241 行 · 第 1/4 页

C
2,241
字号
	if (info->pipenum == 0)		return;	r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));	r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));	r8a66597_write(r8a66597, info->pipenum, PIPESEL);	if (!info->dir_in)		val |= R8A66597_DIR;	if (info->type == R8A66597_BULK && info->dir_in)		val |= R8A66597_DBLB | R8A66597_SHTNAK;	val |= info->type | info->epnum;	r8a66597_write(r8a66597, val, PIPECFG);	r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum),		       PIPEBUF);	r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket,		       PIPEMAXP);	if (info->interval)		info->interval--;	r8a66597_write(r8a66597, info->interval, PIPEPERI);}/* this function must be called with interrupt disabled */static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td){	struct r8a66597_pipe_info *info;	struct urb *urb = td->urb;	if (td->pipenum > 0) {		info = &td->pipe->info;		cfifo_change(r8a66597, 0);		pipe_buffer_setting(r8a66597, info);		if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),				   usb_pipeout(urb->pipe)) &&		    !usb_pipecontrol(urb->pipe)) {			r8a66597_pipe_toggle(r8a66597, td->pipe, 0);			pipe_toggle_set(r8a66597, td->pipe, urb, 0);			clear_all_buffer(r8a66597, td->pipe);			usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),				      usb_pipeout(urb->pipe), 1);		}		pipe_toggle_restore(r8a66597, td->pipe, urb);	}}/* this function must be called with interrupt disabled */static u16 get_empty_pipenum(struct r8a66597 *r8a66597,			     struct usb_endpoint_descriptor *ep){	u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;	memset(array, 0, sizeof(array));	switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {	case USB_ENDPOINT_XFER_BULK:		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)			array[i++] = 4;		else {			array[i++] = 3;			array[i++] = 5;		}		break;	case USB_ENDPOINT_XFER_INT:		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {			array[i++] = 6;			array[i++] = 7;			array[i++] = 8;		} else			array[i++] = 9;		break;	case USB_ENDPOINT_XFER_ISOC:		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)			array[i++] = 2;		else			array[i++] = 1;		break;	default:		err("Illegal type");		return 0;	}	i = 1;	min = array[0];	while (array[i] != 0) {		if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]])			min = array[i];		i++;	}	return min;}static u16 get_r8a66597_type(__u8 type){	u16 r8a66597_type;	switch (type) {	case USB_ENDPOINT_XFER_BULK:		r8a66597_type = R8A66597_BULK;		break;	case USB_ENDPOINT_XFER_INT:		r8a66597_type = R8A66597_INT;		break;	case USB_ENDPOINT_XFER_ISOC:		r8a66597_type = R8A66597_ISO;		break;	default:		err("Illegal type");		r8a66597_type = 0x0000;		break;	}	return r8a66597_type;}static u16 get_bufnum(u16 pipenum){	u16 bufnum = 0;	if (pipenum == 0)		bufnum = 0;	else if (check_bulk_or_isoc(pipenum))		bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2;	else if (check_interrupt(pipenum))		bufnum = 4 + (pipenum - 6);	else		err("Illegal pipenum (%d)", pipenum);	return bufnum;}static u16 get_buf_bsize(u16 pipenum){	u16 buf_bsize = 0;	if (pipenum == 0)		buf_bsize = 3;	else if (check_bulk_or_isoc(pipenum))		buf_bsize = R8A66597_BUF_BSIZE - 1;	else if (check_interrupt(pipenum))		buf_bsize = 0;	else		err("Illegal pipenum (%d)", pipenum);	return buf_bsize;}/* this function must be called with interrupt disabled */static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,				     struct r8a66597_device *dev,				     struct r8a66597_pipe *pipe,				     struct urb *urb){	int i;	struct r8a66597_pipe_info *info = &pipe->info;	if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {		for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {			if ((r8a66597->dma_map & (1 << i)) != 0)				continue;			info("address %d, EndpointAddress 0x%02x use DMA FIFO",			     usb_pipedevice(urb->pipe),			     info->dir_in ? USB_ENDPOINT_DIR_MASK + info->epnum					    : info->epnum);			r8a66597->dma_map |= 1 << i;			dev->dma_map |= 1 << i;			set_pipe_reg_addr(pipe, i);			cfifo_change(r8a66597, 0);			r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,				      MBW | CURPIPE, pipe->fifosel);			r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,					  pipe->info.pipenum);			r8a66597_bset(r8a66597, BCLR, pipe->fifoctr);			break;		}	}}/* this function must be called with interrupt disabled */static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,				 struct usb_host_endpoint *hep,				 struct r8a66597_pipe_info *info){	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);	struct r8a66597_pipe *pipe = hep->hcpriv;	dbg("enable_pipe:");	pipe->info = *info;	set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);	r8a66597->pipe_cnt[pipe->info.pipenum]++;	dev->pipe_cnt[pipe->info.pipenum]++;	enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);}/* this function must be called with interrupt disabled */static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address){	struct r8a66597_td *td, *next;	struct urb *urb;	struct list_head *list = &r8a66597->pipe_queue[pipenum];	if (list_empty(list))		return;	list_for_each_entry_safe(td, next, list, queue) {		if (!td)			continue;		if (td->address != address)			continue;		urb = td->urb;		list_del(&td->queue);		kfree(td);		if (urb) {			usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),					urb);			spin_unlock(&r8a66597->lock);			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,					-ENODEV);			spin_lock(&r8a66597->lock);		}		break;	}}/* this function must be called with interrupt disabled */static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,				      struct r8a66597_device *dev){	int check_ep0 = 0;	u16 pipenum;	if (!dev)		return;	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {		if (!dev->pipe_cnt[pipenum])			continue;		if (!check_ep0) {			check_ep0 = 1;			force_dequeue(r8a66597, 0, dev->address);		}		r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum];		dev->pipe_cnt[pipenum] = 0;		force_dequeue(r8a66597, pipenum, dev->address);	}	dbg("disable_pipe");	r8a66597->dma_map &= ~(dev->dma_map);	dev->dma_map = 0;}/* this function must be called with interrupt disabled */static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,			   struct usb_host_endpoint *hep,			   struct usb_endpoint_descriptor *ep){	struct r8a66597_pipe_info info;	info.pipenum = get_empty_pipenum(r8a66597, ep);	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);	info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);	info.type = get_r8a66597_type(ep->bmAttributes				      & USB_ENDPOINT_XFERTYPE_MASK);	info.bufnum = get_bufnum(info.pipenum);	info.buf_bsize = get_buf_bsize(info.pipenum);	info.interval = ep->bInterval;	if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)		info.dir_in = 1;	else		info.dir_in = 0;	enable_r8a66597_pipe(r8a66597, urb, hep, &info);}static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb){	struct r8a66597_device *dev;	dev = get_urb_to_r8a66597_dev(r8a66597, urb);	dev->state = USB_STATE_CONFIGURED;}static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb,			    u16 pipenum){	if (pipenum == 0 && usb_pipeout(urb->pipe))		enable_irq_empty(r8a66597, pipenum);	else		enable_irq_ready(r8a66597, pipenum);	if (!usb_pipeisoc(urb->pipe))		enable_irq_nrdy(r8a66597, pipenum);}static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum){	disable_irq_ready(r8a66597, pipenum);	disable_irq_nrdy(r8a66597, pipenum);}/* this function must be called with interrupt disabled */static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port){	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)					 | (1 << USB_PORT_FEAT_C_CONNECTION);	r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));	r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));}/* this function must be called with interrupt disabled */static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port){	u16 speed = get_rh_usb_speed(r8a66597, port);	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];	if (speed == HSMODE)		rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED);	else if (speed == LSMODE)		rh->port |= (1 << USB_PORT_FEAT_LOWSPEED);	rh->port &= ~(1 << USB_PORT_FEAT_RESET);	rh->port |= 1 << USB_PORT_FEAT_ENABLE;}/* this function must be called with interrupt disabled */static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port){	struct r8a66597_device *dev = r8a66597->root_hub[port].dev;	r8a66597->root_hub[port].port &= ~(1 << USB_PORT_FEAT_CONNECTION);	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_C_CONNECTION);	disable_r8a66597_pipe_all(r8a66597, dev);	free_usb_address(r8a66597, dev);	r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));}/* this function must be called with interrupt disabled */static void prepare_setup_packet(struct r8a66597 *r8a66597,				 struct r8a66597_td *td){	int i;	u16 *p = (u16 *)td->urb->setup_packet;	unsigned long setup_addr = USBREQ;	r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,		       DCPMAXP);	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);	for (i = 0; i < 4; i++) {		r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);		setup_addr += 2;	}	r8a66597_write(r8a66597, SUREQ, DCPCTR);}/* this function must be called with interrupt disabled */static void prepare_packet_read(struct r8a66597 *r8a66597,				struct r8a66597_td *td){	struct urb *urb = td->urb;	if (usb_pipecontrol(urb->pipe)) {		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);		if (urb->actual_length == 0) {			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);			r8a66597_write(r8a66597, BCLR, CFIFOCTR);		}		pipe_irq_disable(r8a66597, td->pipenum);		pipe_start(r8a66597, td->pipe);		pipe_irq_enable(r8a66597, urb, td->pipenum);	} else {		if (urb->actual_length == 0) {			pipe_irq_disable(r8a66597, td->pipenum);			pipe_setting(r8a66597, td);			pipe_stop(r8a66597, td->pipe);			r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);			if (td->pipe->pipetre) {				r8a66597_write(r8a66597, TRCLR,						td->pipe->pipetre);				r8a66597_write(r8a66597,						(urb->transfer_buffer_length						+ td->maxpacket - 1)						/ td->maxpacket,						td->pipe->pipetrn);				r8a66597_bset(r8a66597, TRENB,						td->pipe->pipetre);			}			pipe_start(r8a66597, td->pipe);			pipe_irq_enable(r8a66597, urb, td->pipenum);		}	}}/* this function must be called with interrupt disabled */static void prepare_packet_write(struct r8a66597 *r8a66597,				 struct r8a66597_td *td){	u16 tmp;	struct urb *urb = td->urb;	if (usb_pipecontrol(urb->pipe)) {		pipe_stop(r8a66597, td->pipe);		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);		if (urb->actual_length == 0) {			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);			r8a66597_write(r8a66597, BCLR, CFIFOCTR);		}	} else {		if (urb->actual_length == 0)			pipe_setting(r8a66597, td);		if (td->pipe->pipetre)			r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);	}	r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);	fifo_change_from_pipe(r8a66597, td->pipe);	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);	if (unlikely((tmp & FRDY) == 0))		pipe_irq_enable(r8a66597, urb, td->pipenum);	else		packet_write(r8a66597, td->pipenum);	pipe_start(r8a66597, td->pipe);}/* this function must be called with interrupt disabled */static void prepare_status_packet(struct r8a66597 *r8a66597,				  struct r8a66597_td *td){	struct urb *urb = td->urb;	r8a66597_pipe_toggle(r8a66597, td->pipe, 1);	pipe_stop(r8a66597, td->pipe);	if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);		r8a66597_write(r8a66597, BCLR, CFIFOCTR);		r8a66597_write(r8a66597, BVAL, CFIFOCTR);		enable_irq_empty(r8a66597, 0);	} else {		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);		r8a66597_write(r8a66597, BCLR, CFIFOCTR);		enable_irq_ready(r8a66597, 0);	}	enable_irq_nrdy(r8a66597, 0);	pipe_start(r8a66597, td->pipe);}static int is_set_address(unsigned char *setup_packet){	if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&			setup_packet[1] == USB_REQ_SET_ADDRESS)		return 1;	else		return 0;}/* this function must be called with interrupt disabled */static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td){	BUG_ON(!td);	switch (td->type) {	case USB_PID_SETUP:		if (is_set_address(td->urb->setup_packet)) {			td->set_address = 1;			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,								     td->urb);			if (td->urb->setup_packet[2] == 0)				return -EPIPE;		}		prepare_setup_packet(r8a66597, td);		break;	case USB_PID_IN:		prepare_packet_read(r8a66597, td);		break;	case USB_PID_OUT:		prepare_packet_write(r8a66597, td);		break;	case USB_PID_ACK:		prepare_status_packet(r8a66597, td);		break;	default:		err("invalid type.");		break;	}	return 0;}static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb){	if (usb_pipeisoc(urb->pipe)) {		if (urb->number_of_packets == td->iso_cnt)			return 1;	}	/* control or bulk or interrupt */	if ((urb->transfer_buffer_length <= urb->actual_length) ||	    (td->short_packet) || (td->zero_packet))		return 1;	return 0;}/* this function must be called with interrupt disabled */static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td){	unsigned long time;	BUG_ON(!td);	if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) &&	    !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) {		r8a66597->timeout_map |= 1 << td->pipenum;		switch (usb_pipetype(td->urb->pipe)) {		case PIPE_INTERRUPT:		case PIPE_ISOCHRONOUS:			time = 30;			break;		default:			time = 300;			break;		}		mod_timer(&r8a66597->td_timer[td->pipenum],			  jiffies + msecs_to_jiffies(time));	}}/* this function must be called with interrupt disabled */static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,		u16 pipenum, struct urb *urb, int status)__releases(r8a66597->lock) __acquires(r8a66597->lock)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?