⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hc_sl811.c

📁 linux下面的SL811驱动硬件平台S3C44B0
💻 C
📖 第 1 页 / 共 5 页
字号:
			len = sizeof(sl811_rh_dev_des);
			bufp = sl811_rh_dev_des;
			OK(len);

		case USB_DT_CONFIG: 
			len = sizeof(sl811_rh_config_des);
			bufp = sl811_rh_config_des;
			OK(len);

		case USB_DT_STRING:
			len = usb_root_hub_string(wValue & 0xff, (int)(long)0,	"SL811HS", data, wLength);
			if (len > 0) {
				bufp = data;
				OK(len);
			}
		
		default:
			status = -EPIPE;
		}
		break;

	case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
		len = sizeof(sl811_rh_hub_des);
		bufp = sl811_rh_hub_des;
		OK(len);

	case RH_GET_CONFIGURATION:
		bufp[0] = 0x01;
		OK(1);

	case RH_SET_CONFIGURATION:
		OK(0);

	default:
		PDEBUG(1, "unsupported root hub command");
		status = -EPIPE;
	}

	len = min(len, buf_len);
	if (data != bufp)
		memcpy(data, bufp, len);
	urb->actual_length = len;
	urb->status = status;

	PDEBUG(5, "len = %d, status = %d", len, status);
	
	urb->hcpriv = NULL;
	urb->dev = NULL;
	if (urb->complete)
		urb->complete(urb);

	return 0;
}

/*
 * This function unlinks the URB
 */
static int sl811_rh_unlink_urb(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;

	PDEBUG(5, "enter");
	
	if (hc->rh.urb == urb) {
		hc->rh.send = 0;
		del_timer(&hc->rh.rh_int_timer);
		hc->rh.urb = NULL;
		urb->hcpriv = NULL;
		usb_dec_dev_use(urb->dev);
		urb->dev = NULL;
		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
			urb->status = -ECONNRESET;
			if (urb->complete)
				urb->complete(urb);
		} else
			urb->status = -ENOENT;
	}

	return 0;
}

/*
 * This function connect the virtual root hub to the USB stack
 */
static int sl811_connect_rh(struct sl811_hc * hc)
{
	struct usb_device *usb_dev;

	hc->rh.devnum = 0;
	usb_dev = usb_alloc_dev(NULL, hc->bus);
	if (!usb_dev)
		return -ENOMEM;

	hc->bus->root_hub = usb_dev;
	usb_connect(usb_dev);

	if (usb_new_device(usb_dev)) {
		usb_free_dev(usb_dev);
		return -ENODEV;
	}
	
	PDEBUG(5, "leave success");
	
	return 0;
}

/*
 * This function allocates private data space for the usb device
 */
static int sl811_alloc_dev_priv(struct usb_device *usb_dev)
{
	return 0;
}

/*
 * This function de-allocates private data space for the usb devic
 */
static int sl811_free_dev_priv (struct usb_device *usb_dev)
{
	return 0;
}

/*
 * This function allocates private data space for the urb
 */
static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb)
{
	struct sl811_urb_priv *urbp;
	
	urbp = kmalloc(sizeof(*urbp), GFP_KERNEL);
	if (!urbp)
		return NULL;
	
	memset(urbp, 0, sizeof(*urbp));
	
	INIT_LIST_HEAD(&urbp->td_list);
	
	urbp->urb = urb;
	urb->hcpriv = urbp;
	
	return urbp;
}

/*
 * This function free private data space for the urb
 */
static void sl811_free_urb_priv(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	struct list_head *head, *tmp;
	
	if (!urbp)
		return ;
	
	head = &urbp->td_list;
	tmp = head->next;
	
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		kfree(td);
	}
	
	kfree(urbp);
	urb->hcpriv = NULL;
	
	return ;
}

/*
 * This	function calculate the bus time need by this td.
 * Fix me! Can this use usb_calc_bus_time()?
 */
static void sl811_calc_td_time(struct sl811_td *td)
{
#if 1
	int time;
	int len = td->len;
	struct sl811_hc *hc = td->urb->dev->bus->hcpriv; 

	if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
		time = 8*8*len + 1024;
	else {
		if (td->ctrl & SL811_USB_CTRL_PREAMBLE)
			time = 8*8*len + 2048;
		else
			time = 8*len + 256;
	}

	time += 2*10 * len;

	td->bustime = time;
	
#else

	unsigned long tmp;
	int time;
	int low_speed = usb_pipeslow(td->urb->pipe);
	int input_dir = usb_pipein(td->urb->pipe);
	int bytecount = td->len;
	int isoc = usb_pipeisoc(td->urb->pipe); 

	if (low_speed) {	/* no isoc. here */
		if (input_dir) {
			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
			time =  (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
		} else {
			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
			time =  (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
		}
	} else if (!isoc){	/* for full-speed: */
		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
		time = (9107L + BW_HOST_DELAY + tmp);
	} else {		/* for isoc: */
		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
		time =  (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
	}
	
	td->bustime = time / 84;

#endif		 
}

/*
 * This	function calculate the remainder bus time in current frame.
 */
static inline int sl811_calc_bus_remainder(struct sl811_hc *hc)
{
	return (sl811_read(hc, SL811_SOFCNTDIV) * 64);
}

/*
 * This function allocates td for the urb
 */
static struct sl811_td* sl811_alloc_td(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	
	td = kmalloc(sizeof (*td), GFP_KERNEL);
	if (!td)
		return NULL;
	
	memset(td, 0, sizeof(*td));
	
	INIT_LIST_HEAD(&td->td_list);
	
	td->urb = urb;
	list_add_tail(&td->td_list, &urbp->td_list);
	
	return td;
}

/*
 * Fill the td.
 */
static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf)
{
	td->ctrl = ctrl;
	td->addr = addr;
	td->len = len;
	td->pidep = pidep;
	td->dev = dev;
	td->buf = buf;
	td->left = len;
	td->errcnt = 3;
}

/*
 * Fill the td.
 */
static inline void sl811_reset_td(struct sl811_td *td)
{
	td->status = 0;
	td->left = td->len;
	td->done = 0;
	td->errcnt = 3;
	td->nakcnt = 0;
	td->td_status = 0;
}

static void sl811_print_td(int level, struct sl811_td *td)
{
	 PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n 
		dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n 
		buf = %p, bustime = %d, td_status = %d\n", 
		td, td->ctrl, td->addr, td->len, td->pidep,
		td->dev, td->status, td->left, td->errcnt, td->done,
		td->buf, td->bustime, td->td_status);
}

/*
 * Isochronous transfers
 */
static int sl811_submit_isochronous(struct urb *urb)
{
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	int i;
	
	PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp);
	
	/* Can't have low speed bulk transfers */
	if (usb_pipeslow(urb->pipe)) {
		PDEBUG(1, "error, urb = %p, low speed device", urb);
		return -EINVAL;
	}
	
	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
		
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_ISO;
	
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].actual_length = 0;
		urb->iso_frame_desc[i].status = -EXDEV;
			
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		sl811_fill_td(td, ctrl, SL811_DATA_START, 
			urb->iso_frame_desc[i].length,
			pidep, dev,
			urb->transfer_buffer + urb->iso_frame_desc[i].offset);
		sl811_calc_td_time(td);
		if (urbp->cur_td == NULL)
			urbp->cur_td = urbp->first_td = td;	
	}
	
	urbp->last_td = td;	
	
	PDEBUG(4, "leave success");

/*	
// for debug
	{
		struct list_head *head, *tmp;
		struct sl811_td *td;
		int i = 0;
		head = &urbp->td_list;
		tmp = head->next;
	
		if (list_empty(&urbp->td_list)) {
			PDEBUG(1, "bug!!! td list is empty!");
			return -ENODEV;
		}
		
		while (tmp != head) {
			++i;
			td = list_entry(tmp, struct sl811_td, td_list);
			PDEBUG(2, "td = %p, i = %d", td, i);
			tmp = tmp->next;
		}
	}
*/	
	return 0;
}

/*
 * Reset isochronous transfers
 */
static void sl811_reset_isochronous(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	struct list_head *head, *tmp;
	int i;

	PDEBUG(4, "enter, urb = %p", urb);
	
	for (i = 0; i < urb->number_of_packets; i++) {
		urb->iso_frame_desc[i].actual_length = 0;
		urb->iso_frame_desc[i].status = -EXDEV;
	}

	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		sl811_reset_td(td);
	}
	
	urbp->cur_td = urbp->first_td;
	
	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
	urb->error_count = 0;
}

/*
 * Result the iso urb.
 */
static void sl811_result_isochronous(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	int status = 0;
	struct sl811_td *td;
	int i;

	PDEBUG(4, "enter, urb = %p", urb);
		
	urb->actual_length = 0;

	i = 0;
	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		
		if (!td->done) {
			if (urbp->unlink)
				urb->status = -ENOENT;
			else {
				PDEBUG(1, "we should not get here!");
				urb->status = -EXDEV;
			}
			return ;	
		}
		if (td->td_status) {
			status = td->td_status;
			urb->error_count++;
			PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status);
		}

		urb->iso_frame_desc[i].actual_length = td->len - td->left;
		urb->actual_length += td->len - td->left;
		urb->iso_frame_desc[i].status = td->td_status;
		++i;
		if (td->left)
			PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left);
	}

	urb->status = status;
/*
// for debug
	PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status);		
*/
	PDEBUG(4, "leave success");
}

/*
 * Interrupt transfers
 */
static int sl811_submit_interrupt(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	if (len > maxsze) {
		PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze);
		return -EINVAL;
	}
	if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
		ctrl |= SL811_USB_CTRL_PREAMBLE;
	
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
	if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
		ctrl |= SL811_USB_CTRL_TOGGLE_1;
	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));	
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;
		
	sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data);
	sl811_calc_td_time(td);
	urbp->cur_td = urbp->first_td = urbp->last_td = td;
	urbp->interval = 0;
	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Reset interrupt transfers
 */
static void sl811_reset_interrupt(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = urbp->cur_td;
	
	PDEBUG(4, "enter, interval = %d", urb->interval);
	
	td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
	if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
		td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));	
	
	sl811_reset_td(td);

	urbp->interval = urb->interval;
	
	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
}

/*
 * Result the interrupt urb.
 */
static void sl811_result_interrupt(struct urb *urb)
{
	struct list_head *tmp;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	int toggle;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	urb->actual_length = 0;

	tmp = &urbp->td_list;
	tmp = tmp->next;
	td = list_entry(tmp, struct sl811_td, td_list);

	// success.
	if (td->done && td->td_status == 0) {
		urb->actual_length += td->len - td->left;
		urb->status = 0;
		return ;
	}
	// tranfer is done but fail, reset the toggle.

⌨️ 快捷键说明

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