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

📄 dwc_otg_hcd.c

📁 host usb 主设备程序 支持sd卡 mouse keyboard 的最单单的驱动程序 gcc编译
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (hcd == NULL) {		retval = -ENOMEM;		goto error1;	}	hcd->regs = otg_dev->base;	hcd->self.otg_port = 1;	/* Initialize the DWC OTG HCD. */	dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);	dwc_otg_hcd->core_if = otg_dev->core_if;	otg_dev->hcd = dwc_otg_hcd;	/* Register the HCD CIL Callbacks */	dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, &hcd_cil_callbacks, hcd);	/* Initialize the non-periodic schedule. */	INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive);	INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active);	/* Initialize the periodic schedule. */	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);	/*	 * Create a host channel descriptor for each host channel implemented	 * in the controller. Initialize the channel descriptor array.	 */	INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list);	num_channels = dwc_otg_hcd->core_if->core_params->host_channels;	for (i = 0; i < num_channels; i++) {		channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL);		if (channel == NULL) {			retval = -ENOMEM;			printk("%s: host channel allocation failed\n", __func__);			goto error2;		}		memset(channel, 0, sizeof(dwc_hc_t));		channel->hc_num = i;		dwc_otg_hcd->hc_ptr_array[i] = channel;#ifdef DEBUG		init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]);#endif		dbg_otg("HCD Added channel #%d, hc=%p\n", i, channel);	}	/* Initialize the Connection timeout timer. */	init_timer(&dwc_otg_hcd->conn_timer);	/* Initialize reset tasklet. */	reset_tasklet.data = (unsigned long) dwc_otg_hcd;	dwc_otg_hcd->reset_tasklet = &reset_tasklet;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)	/* Set device flags indicating whether the HCD supports DMA. */	if (otg_dev->core_if->dma_enable) {		DWC_PRINT("Using DMA mode\n");		pdev->dev.dma_mask = (void *) ~0;		pdev->dev.coherent_dma_mask = ~0;		if (otg_dev->core_if->dma_desc_enable) {			DWC_PRINT("Device using Descriptor DMA mode\n");		} else {			DWC_PRINT("Device using Buffer DMA mode\n");		}	} else {		DWC_PRINT("Using Slave mode\n");		pdev->dev.dma_mask = (void *) 0;		pdev->dev.coherent_dma_mask = 0;	}#endif	/*	 * Finish generic HCD initialization and start the HCD. This function	 * allocates the DMA buffer pool, registers the USB bus, requests the	 * IRQ line, and calls dwc_otg_hcd_start method.	 * 2nd contact point of USB Core by scsuh.	 */	retval = usb_add_hcd(hcd, IRQ_OTG, SA_SHIRQ);	if (retval < 0) {		goto error2;	}	/*	 * Allocate space for storing data on status transactions. Normally no	 * data is sent, but this space acts as a bit bucket. This must be	 * done after usb_add_hcd since that function allocates the DMA buffer	 * pool.	 */	if (otg_dev->core_if->dma_enable) {		dwc_otg_hcd->status_buf =			dma_alloc_coherent(&pdev->dev, DWC_OTG_HCD_STATUS_BUF_SIZE,					   &dwc_otg_hcd->status_buf_dma, GFP_KERNEL | GFP_DMA);	} else {		dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE, GFP_KERNEL);	}	if (dwc_otg_hcd->status_buf == NULL) {		retval = -ENOMEM;		DWC_ERROR("%s: status_buf allocation failed\n", __func__);		goto error3;	}	dbg_otg("DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n",		    pdev->dev.bus_id, hcd->self.busnum);	return 0;	/* Error conditions */      error3:	usb_remove_hcd(hcd);      error2:	dwc_otg_hcd_free(hcd);	usb_put_hcd(hcd);      error1:	return retval;}/** * Removes the HCD. * Frees memory and resources associated with the HCD and deregisters the bus. */void dwc_otg_hcd_remove(struct platform_device *_lmdev){	dwc_otg_device_t *otg_dev = platform_get_drvdata(_lmdev);	dwc_otg_hcd_t *dwc_otg_hcd;	struct usb_hcd *hcd;	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");	if (!otg_dev) {		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);		return;	}	dwc_otg_hcd = otg_dev->hcd;	if (!dwc_otg_hcd) {		DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);		return;	}	hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);	if (!hcd) {		DWC_DEBUGPL(DBG_ANY, "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n", __func__);		return;	}	/* Turn off all interrupts */	dwc_write_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0);	dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1, 0);	usb_remove_hcd(hcd);	dwc_otg_hcd_free(hcd);	usb_put_hcd(hcd);	return;}/* ========================================================================= *  Linux HC Driver Functions * ========================================================================= *//** * Initializes dynamic portions of the DWC_otg HCD state. */static void hcd_reinit(dwc_otg_hcd_t * _hcd){	struct list_head *item;	int num_channels;	int i;	dwc_hc_t *channel;	_hcd->flags.d32 = 0;	_hcd->non_periodic_qh_ptr = &_hcd->non_periodic_sched_active;	_hcd->non_periodic_channels = 0;	_hcd->periodic_channels = 0;	/*	 * Put all channels in the free channel list and clean up channel	 * states.	 */	item = _hcd->free_hc_list.next;	while (item != &_hcd->free_hc_list) {		list_del(item);		item = _hcd->free_hc_list.next;	}	num_channels = _hcd->core_if->core_params->host_channels;	for (i = 0; i < num_channels; i++) {		channel = _hcd->hc_ptr_array[i];		list_add_tail(&channel->hc_list_entry, &_hcd->free_hc_list);		dwc_otg_hc_cleanup(_hcd->core_if, channel);	}	/* Initialize the DWC core for host mode operation. */	dwc_otg_core_host_init(_hcd->core_if);}/** Initializes the DWC_otg controller and its root hub and prepares it for host * mode operation. Activates the root port. Returns 0 on success and a negative * error code on failure. */int dwc_otg_hcd_start(struct usb_hcd *_hcd){	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);	dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;	struct usb_bus *bus;	dbg_otg("\n\n\nDWC OTG HCD START\n\n\n\n");	bus = hcd_to_bus(_hcd);	/* Initialize the bus state.  If the core is in Device Mode	 * HALT the USB bus and return. */	if (dwc_otg_is_device_mode(core_if)) {		_hcd->state = HC_STATE_RUNNING;		return 0;	}	_hcd->state = HC_STATE_RUNNING;	/* Initialize and connect root hub if one is not already attached */	if (bus->root_hub) {		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");		/* Inform the HUB driver to resume. */		usb_hcd_resume_root_hub(_hcd);	} else {		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Does Not Have Root Hub\n");	}	hcd_reinit(dwc_otg_hcd);	return 0;}static void qh_list_free(dwc_otg_hcd_t * _hcd, struct list_head *_qh_list){	struct list_head *item;	dwc_otg_qh_t *qh;	if (_qh_list->next == NULL) {		/* The list hasn't been initialized yet. */		return;	}	/* Ensure there are no QTDs or URBs left. */	kill_urbs_in_qh_list(_hcd, _qh_list);	for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) {		qh = list_entry(item, dwc_otg_qh_t, qh_list_entry);		dwc_otg_hcd_qh_remove_and_free(_hcd, qh);	}}/** * Halts the DWC_otg host mode operations in a clean manner. USB transfers are * stopped. */void dwc_otg_hcd_stop(struct usb_hcd *_hcd){	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);	hprt0_data_t hprt0 = {.d32 = 0 };	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");	/* Turn off all host-specific interrupts. */	dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);	/*	 * The root hub should be disconnected before this function is called.	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)	 * and the QH lists (via ..._hcd_endpoint_disable).	 */	/* Turn off the vbus power */	DWC_PRINT("PortPower off\n");	hprt0.b.prtpwr = 0;	dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32);	return;}/** Returns the current frame number. */int dwc_otg_hcd_get_frame_number(struct usb_hcd *_hcd){#if 0	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);	hfnum_data_t hfnum;	hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum);#ifdef DEBUG_SOF	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", hfnum.b.frnum);#endif	return hfnum.b.frnum;#else	return (readl(S3C_UDC_OTG_HFNUM) & 0x0000ffff);#endif}/** * Frees secondary storage associated with the dwc_otg_hcd structure contained * in the struct usb_hcd field. */void dwc_otg_hcd_free(struct usb_hcd *_hcd){	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);	int i;	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");	del_timers(dwc_otg_hcd);	/* Free memory for QH/QTD lists */	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);	/* Free memory for the host channels. */	for (i = 0; i < MAX_EPS_CHANNELS; i++) {		dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];		if (hc != NULL) {			DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", i, hc);			kfree(hc);		}	}	if (dwc_otg_hcd->core_if->dma_enable) {		if (dwc_otg_hcd->status_buf_dma) {			dma_free_coherent(_hcd->self.controller,					  DWC_OTG_HCD_STATUS_BUF_SIZE,					  dwc_otg_hcd->status_buf, dwc_otg_hcd->status_buf_dma);		}	} else if (dwc_otg_hcd->status_buf != NULL) {		kfree(dwc_otg_hcd->status_buf);	}	return;}#ifdef DEBUGstatic void dump_urb_info(struct urb *_urb, char *_fn_name){	DWC_PRINT("%s, urb %p\n", _fn_name, _urb);	DWC_PRINT("  Device address: %d\n", usb_pipedevice(_urb->pipe));	DWC_PRINT("  Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe),		  (usb_pipein(_urb->pipe) ? "IN" : "OUT"));	DWC_PRINT("  Endpoint type: %s\n", ( {					    char *pipetype; switch (usb_pipetype(_urb->pipe)) {case PIPE_CONTROL:pipetype = "CONTROL"; break; case PIPE_BULK:pipetype = "BULK"; break; case PIPE_INTERRUPT:pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:pipetype = "ISOCHRONOUS"; break; default:					    pipetype = "UNKNOWN"; break;};					    pipetype;}		  ));	DWC_PRINT("  Speed: %s\n", ( {				    char *speed; switch (_urb->dev->speed) {case USB_SPEED_HIGH:speed = "HIGH"; break; case USB_SPEED_FULL:speed = "FULL"; break; case USB_SPEED_LOW:speed = "LOW"; break; default:				    speed = "UNKNOWN"; break;};				    speed;}		  ));	DWC_PRINT("  Max packet size: %d\n",		  usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe)));	DWC_PRINT("  Data buffer length: %d\n", _urb->transfer_buffer_length);	DWC_PRINT("  Transfer buffer: %p, Transfer DMA: %p\n",		  _urb->transfer_buffer, (void *) _urb->transfer_dma);	DWC_PRINT("  Setup buffer: %p, Setup DMA: %p\n",		  _urb->setup_packet, (void *) _urb->setup_dma);	DWC_PRINT("  Interval: %d\n", _urb->interval);	if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) {		int i;		for (i = 0; i < _urb->number_of_packets; i++) {			DWC_PRINT("  ISO Desc %d:\n", i);			DWC_PRINT("    offset: %d, length %d\n",				  _urb->iso_frame_desc[i].offset, _urb->iso_frame_desc[i].length);		}	}}static void dump_channel_info(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * qh){	if (qh->channel != NULL) {		dwc_hc_t *hc = qh->channel;		struct list_head *item;		dwc_otg_qh_t *qh_item;		int num_channels = _hcd->core_if->core_params->host_channels;		int i;		dwc_otg_hc_regs_t *hc_regs;		hcchar_data_t hcchar;		hcsplt_data_t hcsplt;		hctsiz_data_t hctsiz;		uint32_t hcdma;		hc_regs = _hcd->core_if->host_if->hc_regs[hc->hc_num];		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);		hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);		hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);		hcdma = dwc_read_reg32(&hc_regs->hcdma);		DWC_PRINT("  Assigned to channel %p:\n", hc);		DWC_PRINT("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);		DWC_PRINT("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);		DWC_PRINT("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",			  hc->dev_addr, hc->ep_num, hc->ep_is_in);		DWC_PRINT("    ep_type: %d\n", hc->ep_type);		DWC_PRINT("    max_packet: %d\n", hc->max_packet);		DWC_PRINT("    data_pid_start: %d\n", hc->data_pid_start);		DWC_PRINT("    xfer_started: %d\n", hc->xfer_started);		DWC_PRINT("    halt_status: %d\n", hc->halt_status);		DWC_PRINT("    xfer_buff: %p\n", hc->xfer_buff);		DWC_PRINT("    xfer_len: %d\n", hc->xfer_len);		DWC_PRINT("    qh: %p\n", hc->qh);		DWC_PRINT("  NP inactive sched:\n");		list_for_each(item, &_hcd->non_periodic_sched_inactive) {			qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry);			DWC_PRINT("    %p\n", qh_item);		}		DWC_PRINT("  NP active sched:\n");		list_for_each(item, &_hcd->non_periodic_sched_active) {			qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry);			DWC_PRINT("    %p\n", qh_item);		}		DWC_PRINT("  Channels: \n");		for (i = 0; i < num_channels; i++) {			dwc_hc_t *hc = _hcd->hc_ptr_array[i];			DWC_PRINT("    %2d: %p\n", i, hc);		}	}}#endif/** Starts processing a USB transfer request specified by a USB Request Block * (URB). mem_flags indicates the type of memory allocation to use while * processing this URB. */int dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd,

⌨️ 快捷键说明

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