Qseecom 8916平台的usb gadget解读(1)

最近对usb系统感兴趣,于是大概看了一下,按照网上一位网友的描述,gadget分为三层

第一层就是udc,具体对应的文件是/kernel/drivers/usb/gadget/ci13xxx_udc.c 

/* CI13XXX UDC descriptor & global resources */
struct ci13xxx {
<span style="white-space:pre">	</span>spinlock_t<span style="white-space:pre">		</span>  *lock;      /* ctrl register bank access */
<span style="white-space:pre">	</span>void __iomem              *regs;      /* registers address space */


<span style="white-space:pre">	</span>struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
<span style="white-space:pre">	</span>struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
<span style="white-space:pre">	</span>struct usb_request        *status;    /* ep0 status request */
<span style="white-space:pre">	</span>void                      *status_buf;/* GET_STATUS buffer */


<span style="white-space:pre">	</span>struct usb_gadget          gadget;     /* USB slave device */
<span style="white-space:pre">	</span>struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
<span style="white-space:pre">	</span>u32                        ep0_dir;    /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in  ci13xxx_ep[hw_ep_max / 2]
<span style="white-space:pre">	</span>u8                         suspended;  /* suspended by the host */
<span style="white-space:pre">	</span>u8                         configured;  /* is device configured */
<span style="white-space:pre">	</span>u8                         test_mode;  /* the selected test mode */
<span style="white-space:pre">	</span>bool                       rw_pending; /* Remote wakeup pending flag */
<span style="white-space:pre">	</span>struct delayed_work        rw_work;    /* remote wakeup delayed work */
<span style="white-space:pre">	</span>struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
<span style="white-space:pre">	</span>struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
<span style="white-space:pre">	</span>int                        vbus_active; /* is VBUS active */
<span style="white-space:pre">	</span>int                        softconnect; /* is pull-up enable allowed */
<span style="white-space:pre">	</span>unsigned long dTD_update_fail_count;
<span style="white-space:pre">	</span>struct usb_phy            *transceiver; /* Transceiver struct */
<span style="white-space:pre">	</span>struct clk                *system_clk;
<span style="white-space:pre">	</span>bool                      skip_flush; /* skip flushing remaining EP
<span style="white-space:pre">						</span>upon flush timeout for the
<span style="white-space:pre">						</span>first EP. */
};
以上的数据结构以及函数是UDC的硬件层,不同的UDC采取不同的策略。s3c2410是集成的USB设备控制器,所以就是采用platform驱动的形式来注册的。如果系统是外接的USB设备控制器,那么则会采用相应总线的注册形式,比如PCI等。platform驱动的唯一目的就是分配资源以及初级初始化硬件,对于USB设备层和功能驱动层都没有影响。UDC层与USB设备层是通过另外的数据结构进行交互的。这种方式就是使用两个结构体与两个函数, 两个结构体分别是struct usb_gadget与struct usb_gadget_driver,他们都是嵌入在struct s3c2410_udc结构中的,但是是由不同软件层的代码初始化的。首先看struct usb_gadget,他是在定义memory的时候就进行了初始化,是在UDC层中初始化的。而struct usb_gadget_driver是在USB设备层中初始化的,他是通过usb_gadget_register_driver(struct usb_gadget_driver *driver)函数从USB设备层传过来然后赋值给memory的。这里出现一个关键的函数usb_gadget_register_driver(struct usb_gadget_driver *driver)这个函数就是UDC层与USB设备层进行交互的函数。设备设备层通过调用它与UDC层联系在一起。这个函数将usb_gadget与usb_gadget_driver联系在一起。向USB设备层提供usb_gadget_register_driver(struct usb_gadget_driver *driver)是UDC层的基本任务,但是UDC层要做的不仅如此,UDC层还需要提供为usb_gadget服务的相关函数,这些函数会通过usb_gadget传递给USB设备层。UDC层还需要提供USB设备的中断处理程序,中断处理尤其重要。因为所有的USB传输都是由主机发起,而有没有USB传输完全由USB中断判定,所以USB中断处理程序是整个软件架构的核心。UDC层主要提供以下的函数与数据结构:

usb_gadget操作函数集合

static const struct usb_gadget_ops usb_gadget_ops = {
	.vbus_session	= ci13xxx_vbus_session,
	.wakeup		= ci13xxx_wakeup,
	.vbus_draw	= ci13xxx_vbus_draw,
	.pullup		= ci13xxx_pullup,
	.udc_start	= ci13xxx_start,
	.udc_stop	= ci13xxx_stop,
};
端点操作函数

static const struct usb_ep_ops usb_ep_ops = {
	.enable	       = ep_enable,
	.disable       = ep_disable,
	.alloc_request = ep_alloc_request,
	.free_request  = ep_free_request,
	.queue	       = ep_queue,
	.dequeue       = ep_dequeue,
	.set_halt      = ep_set_halt,
	.set_wedge     = ep_set_wedge,
	.fifo_flush    = ep_fifo_flush,
};
USB 中断处理程序

static irqreturn_t udc_irq(void)
{
	struct ci13xxx *udc = _udc;
	irqreturn_t retval;
	u32 intr;

	trace();

	if (udc == NULL) {
		err("ENODEV");
		return IRQ_HANDLED;
	}

	spin_lock(udc->lock);

	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
		spin_unlock(udc->lock);
		return IRQ_NONE;
	}

	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
		if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
				USBMODE_CM_DEVICE) {
			spin_unlock(udc->lock);
			return IRQ_NONE;
		}
	}
	intr = hw_test_and_clear_intr_active();
	if (intr) {
		isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
		isr_statistics.hndl.idx &= ISR_MASK;
		isr_statistics.hndl.cnt++;

		/* order defines priority - do NOT change it */
		if (USBi_URI & intr) {
			isr_statistics.uri++;
			if (!hw_cread(CAP_PORTSC, PORTSC_PR))
				pr_info("%s: USB reset interrupt is delayed\n",
								__func__);
			isr_reset_handler(udc);
		}
		if (USBi_PCI & intr) {
			isr_statistics.pci++;
			isr_resume_handler(udc);
		}
		if (USBi_UEI & intr)
			isr_statistics.uei++;
		if (USBi_UI  & intr) {
			isr_statistics.ui++;
			udc->gadget.xfer_isr_count++;
			isr_tr_complete_handler(udc);
		}
		if (USBi_SLI & intr) {
			isr_suspend_handler(udc);
			isr_statistics.sli++;
		}
		retval = IRQ_HANDLED;
	} else {
		isr_statistics.none++;
		retval = IRQ_NONE;
	}
	spin_unlock(udc->lock);

	return retval;
}
USB设备层
        USB设备层,虽然名字上与设备相关。但是属于硬件无关层。这一层相关的代码是composite.c,composite.h。这一层的功能是隔离Gadget功能驱动与硬件相关层。使得功能驱动直接与USB设备层交互不用考虑硬件的相关细节。还有USB设备层提供了USB设备的一些基本数据结构,不同的Gadget功能驱动可以共同调用。如果没有这一层,则每一个功能驱动都需要实现自己的USB设备,导致了代码重用率很高。这一层向下与UDC层进行交互,向上与Gadget功能驱动层进行交互。在UDC层已经介绍了USB设备层向下与UDC层交互方式主要是通过调用usb_gadget_register_driver(struct usb_gadget_driver *driver),这个函数是UDC层提供的。而这个函数传递的参数就是一个usb_gadget_driver的结构体。以下是这个结构体定义:

struct usb_gadget_driver {
	char			*function;
	enum usb_device_speed	max_speed;
	int			(*bind)(struct usb_gadget *gadget,
					struct usb_gadget_driver *driver);
	void			(*unbind)(struct usb_gadget *);
	int			(*setup)(struct usb_gadget *,
					const struct usb_ctrlrequest *);
	void			(*disconnect)(struct usb_gadget *);
	void			(*suspend)(struct usb_gadget *);
	void			(*resume)(struct usb_gadget *);

	/* FIXME support safe rmmod */
	struct device_driver	driver;

	u8			usb_core_id;
};
在composite.c中声明了一个这样的一个结构体变量:composite_driver,这个结构体变量就是传给usb_gadget_register_driver(struct usb_gadget_driver *driver)的参数。

static const struct usb_gadget_driver composite_driver_template = {
	.bind		= composite_bind,
	.unbind		= composite_unbind,

	.setup		= composite_setup,
	.disconnect	= composite_disconnect,

	.suspend	= composite_suspend,
	.resume		= composite_resume,

	.driver	= {
		.owner		= THIS_MODULE,
	},
};
以上所有的函数集都需要自己实现,这些函数的大部分参数都是usb_gadget。可以看出这些函数都是与UDC层相关的。以上数据结构是与UDC进行交互的,下面的数据结构以及函数是USB设备层与Gadget功能驱动层进行交互的。

struct usb_composite_dev {
	struct usb_gadget		*gadget;   //指向gadget的指针 
	struct usb_request		*req;

	struct usb_configuration	*config;

	/* private: */
	/* internals */
	unsigned int			suspended:1;
	struct usb_device_descriptor	desc;
	struct list_head		configs;
	struct list_head		gstrings;
	struct usb_composite_driver	*driver;   //指向<span style="font-family: Arial;">usb_composite_driver的指针</span>

	u8				next_string_id;
	char				*def_manufacturer;

	/* the gadget driver won't enable the data pullup
	 * while the deactivation count is nonzero.
	 */
	unsigned			deactivations;

	/* the composite driver won't complete the control transfer's
	 * data/status stages till delayed_status is zero.
	 */
	int				delayed_status;

	/* protects deactivations and delayed_status counts*/
	spinlock_t			lock;
};

这个结构代表一个USB设备。可以看出结构体中有设备描述符以及配置。还有指向usb_gadget与usb_compsite_driver的指针。说明这个结构体联系了UDC层与功能驱动层。这个结构内嵌在了usb_gadget中,是在composite_bind函数中分配与初始化的。

这里的函数名变了哦,从之前那位网友的文章里的usb_composite_register变成了下面这个

int usb_composite_probe(struct usb_composite_driver *driver)
{
	struct usb_gadget_driver *gadget_driver;
	u8 core_id;

	if (!driver || !driver->dev || !driver->bind)
		return -EINVAL;

	if (!driver->name)
		driver->name = "composite";

	core_id = driver->gadget_driver.usb_core_id;
	driver->gadget_driver = composite_driver_template;
	gadget_driver = &driver->gadget_driver;

	gadget_driver->function =  (char *) driver->name;
	gadget_driver->driver.name = driver->name;
	gadget_driver->max_speed = driver->max_speed;

	if (core_id)
		gadget_driver->usb_core_id = core_id;

	pr_debug("%s(): gadget_driver->usb_core_id:%d\n", __func__,
					gadget_driver->usb_core_id);
	return usb_gadget_probe_driver(gadget_driver);
}
这个函数是由Gadget功能驱动层调用的,他简单初始化了composite_driver。然后调用usb_gadget_register_driver。composite是usb_composite_drver类型的全局指针这里赋值了功能驱动传递过来的driver。所以功能驱动层与USB设备层联系在了一起,usb_gadget_register_driver调用后UDC层与USB设备层联系到了一起。usb_composite_register是在功能驱动的模块初始化的函数中进行的调用。所以只要功能驱动一加载,三个软件层就通过数据结构联系在了一起。

看看哪些地方调用到了这个函数

Acm_ms.c (drivers\usb\gadget): return usb_composite_probe(&acm_ms_driver);
Android.c (drivers\usb\gadget): ret = usb_composite_probe(&android_usb_driver);
Audio.c (drivers\usb\gadget): return usb_composite_probe(&audio_driver);
Cdc2.c (drivers\usb\gadget): return usb_composite_probe(&cdc_driver);
Composite.c (drivers\usb\gadget): * usb_composite_probe() - register a composite driver
Composite.c (drivers\usb\gadget):int usb_composite_probe(struct usb_composite_driver *driver)
Composite.c (drivers\usb\gadget):EXPORT_SYMBOL_GPL(usb_composite_probe);
Composite.h (include\linux\usb):extern int usb_composite_probe(struct usb_composite_driver *driver);
Ether.c (drivers\usb\gadget): return usb_composite_probe(&eth_driver);
Gmidi.c (drivers\usb\gadget): return usb_composite_probe(&midi_driver);
G_ffs.c (drivers\usb\gadget): ret = usb_composite_probe(&gfs_driver);
Hid.c (drivers\usb\gadget): status = usb_composite_probe(&hidg_driver);
Mass_storage.c (drivers\usb\gadget): return usb_composite_probe(&msg_driver);
Multi.c (drivers\usb\gadget): return usb_composite_probe(&multi_driver);
Ncm.c (drivers\usb\gadget): return usb_composite_probe(&ncm_driver);
Nokia.c (drivers\usb\gadget): return usb_composite_probe(&nokia_driver);
Printer.c (drivers\usb\gadget): status = usb_composite_probe(&printer_driver);
Serial.c (drivers\usb\gadget): return usb_composite_probe(&gserial_driver);
Tcm_usb_gadget.c (drivers\usb\gadget): ret = usb_composite_probe(&usbg_driver, usb_target_bind);
Webcam.c (drivers\usb\gadget): return usb_composite_probe(&webcam_driver);
Zero.c (drivers\usb\gadget): return usb_composite_probe(&zero_driver);   //这个就是那个基础版


剩下的就可以参考http://blog.csdn.net/yaozhenguo2006/article/details/7690707这篇文章里的zero了








  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值