OTG驱动分析(二)
来源:互联网 发布:ds数据精灵使用教程 编辑:程序博客网 时间:2024/05/17 01:09
2. 定义platform_device下的struct resource设备资源结构
3. 定义 platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
4. 调用platform_device_register将platform_device结构
注 册上面4个过程调用结束后,设备的信息就被注册到系统中,等待驱动的使用 下面是按照上面顺序贴出代码
static struct platform_device __maybe_unused dr_udc_device = {
. name = "fsl-usb2-udc" ,
. id = - 1,
. dev = {
. release = dr_udc_release,
. dma_mask = & dr_udc_dmamask,
. coherent_dma_mask = 0xffffffff,
} ,
. resource = otg_resources,
. num_resources = ARRAY_SIZE( otg_resources) ,
} ;
我们可以看到resource和OTG的resource一样,使用的都是OTG那 部分资源
定义platform_device下的struct resource设备资源结构
static struct resource otg_resources[ ] = {
[ 0] = {
. start = ( u32) ( USB_OTGREGS_BASE) ,
. end = ( u32) ( USB_OTGREGS_BASE + 0x1ff) ,
. flags = IORESOURCE_MEM,
} ,
[ 1] = {
. start = MXC_INT_USB_OTG,
. flags = IORESOURCE_IRQ,
} ,
} ;
定义platform_device下的DEV设备下的平台私有数据(就是该设备私有的数据)
static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
. name = "DR" ,
. platform_init = usbotg_init,
. platform_uninit = usbotg_uninit,
. phy_mode = FSL_USB2_PHY_UTMI_WIDE,
. power_budget = 500, /* via RT9706 */
. gpio_usb_active = gpio_usbotg_utmi_active,
. gpio_usb_inactive = gpio_usbotg_utmi_inactive,
. transceiver = "utmi" ,
. wake_up_enable = _wake_up_enable,
} ;
/*将设备注册 进系统*/
static inline void dr_register_udc( void )
{
PDATA- > operating_mode = DR_UDC_MODE; //在OTG功能设备注册的时候这里的模式是“FSL_USB2_DR_OTG ”, 时还不知道为什么不开始就直接把模式写成这个而是后该,现在知道了 因为主从和OTG都在用一个资源,所以谁用就的把模式该了。
/*#define PDATA (&dr_utmi_config)PDATA指的就是上面的结构 */
dr_udc_device. dev. platform_data = PDATA;
if ( platform_device_register( & dr_udc_device) )
printk( KERN_ERR "usb: can't register DR gadget/n" ) ;
else
printk( KERN_INFO "usb: DR gadget (%s) registered/n" ,
PDATA- > transceiver) ;
}
上面就完成了设备的注册。
下面看看驱动和设备的链接。
static struct platform_driver udc_driver = {
. remove = __exit_p( fsl_udc_remove) ,
/* these suspend and resume are not usb suspend and resume * /
. suspend = fsl_udc_suspend, //切换到主设备后的处理过程
. resume = fsl_udc_resume, //切换到从设备的处理过程
. probe = fsl_udc_probe,
. driver = {
. name = driver_name, //就是fsl-usb2-udc,用于匹配设备的
. owner = THIS_MODULE,
},
}
将驱动注册进系统,如果发现了设备就调用Probe函数,因为我们上面注册了设备所以必然调用Probe
static int __init udc_init( void )
{
printk( KERN_INFO "%s (%s)/n" , driver_desc, DRIVER_VERSION) ;
return platform_driver_register( & udc_driver) ;//驱动注册进系统
}
发现设备后调用PROBE函数
static int __init fsl_udc_probe( struct platform_device * pdev)
{
struct resource * res;
struct fsl_usb2_platform_data * pdata = pdev- > dev. platform_data;
int ret = - ENODEV;
unsigned int i;
u32 dccparams, portsc;
if ( strcmp ( pdev- > name, driver_name) ) {
VDBG( "Wrong device/n" ) ;
return - ENODEV;
}
/********************************************************/
static struct fsl_udc *udc_controller;
全局变量定义
/*******************************************************/
udc_controller = kzalloc( sizeof ( struct fsl_udc) , GFP_KERNEL) ;
if ( udc_controller = = NULL ) {
ERR( "malloc udc failed/n" ) ;
return - ENOMEM;
}
udc_controller- > pdata = pdata; //私有变量赋值
# ifdef CONFIG_USB_OTG
/* Memory and interrupt resources will be passed from OTG */
udc_controller- > transceiver = otg_get_transceiver( ) ;//在OTG功能中已经通过otg_set_transceiver 设置了transceiver结构,这里面就可以GET
if ( ! udc_controller- > transceiver) {
printk( KERN_ERR "Can't find OTG driver!/n" ) ;
ret = - ENODEV;
goto err1a;
}
res = otg_get_resources( ) ; //获得资源
if ( ! res) {
DBG( "resource not registered!/n" ) ;
return - ENODEV;
}
# else
if ( ( pdev- > dev. parent) & &
( to_platform_device( pdev- > dev. parent) - > resource) ) {
pdev- > resource =
to_platform_device( pdev- > dev. parent) - > resource;
pdev- > num_resources =
to_platform_device( pdev- > dev. parent) - > num_resources;
}
res = platform_get_resource( pdev, IORESOURCE_MEM, 0) ;
if ( ! res) {
ret = - ENXIO;
goto err1a;
}
if ( ! request_mem_region( res- > start, resource_size( res) ,
driver_name) ) {
ERR( "request mem region for %s failed /n" , pdev- > name) ;
ret = - EBUSY;
goto err1a;
}
# endif
/*将物理地址映射为驱动可以访问的虚拟地址*/
dr_regs = ioremap( res- > start, resource_size( res) ) ;
if ( ! dr_regs) {
ret = - ENOMEM;
goto err1;
}
pdata- > regs = ( void * ) dr_regs; //私有数据接收映射地址
/*
* do platform specific init: check the clock, grab/config pins, etc.
*/
/*调用私有数据的初始化函数,关于初始化函数下面分析*/
if ( pdata- > platform_init & & pdata- > platform_init( pdev) ) {
ret = - ENODEV;
goto err2a;
}
if ( pdata- > have_sysif_regs)
usb_sys_regs = ( struct usb_sys_interface * )
( ( u32) dr_regs + USB_DR_SYS_OFFSET) ;
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl( & dr_regs- > dccparams) ;
if ( ! ( dccparams & DCCPARAMS_DC) ) {
ERR( "This SOC doesn't support device role/n" ) ;
ret = - ENODEV;
goto err2;
}
/* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */
udc_controller- > max_ep = ( dccparams & DCCPARAMS_DEN_MASK) * 2;
# ifdef CONFIG_USB_OTG
res+ + ;
udc_controller- > irq = res- > start;
# else
udc_controller- > irq = platform_get_irq( pdev, 0) ;
# endif
if ( ! udc_controller- > irq) {
ret = - ENODEV;
goto err2;
}
/*注册中断,该中断和OTG的中断共享一个*/
ret = request_irq( udc_controller- > irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller) ;
if ( ret ! = 0) {
ERR( "cannot request irq %d err %d /n" ,
udc_controller- > irq, ret) ;
goto err2;
}
/* Initialize the udc structure including QH member and other member */
/*对一些资源进行空间开辟等初始化操作*/
if ( struct_udc_setup( udc_controller, pdev) ) {
ERR( "Can't initialize udc data structure/n" ) ;
ret = - ENOMEM;
goto err3;
}
if ( ! udc_controller- > transceiver) {
/* initialize usb hw reg except for regs for EP,
* leave usbintr reg untouched */
dr_controller_setup( udc_controller) ;
}
/* Setup gadget structure */
udc_controller- > gadget. ops = & fsl_gadget_ops;
udc_controller- > gadget. is_dualspeed = 1;
udc_controller- > gadget. ep0 = & udc_controller- > eps[ 0] . ep;
INIT_LIST_HEAD( & udc_controller- > gadget. ep_list) ;
udc_controller- > gadget. speed = USB_SPEED_UNKNOWN;
udc_controller- > gadget. name = driver_name;
/* Setup gadget.dev and register with kernel */
dev_set_name( & udc_controller- > gadget. dev, "gadget" ) ;
udc_controller- > gadget. dev. release = fsl_udc_release;
udc_controller- > gadget. dev. parent = & pdev- > dev;
ret = device_register( & udc_controller- > gadget. dev) ;
if ( ret < 0)
goto err3;
if ( udc_controller- > transceiver) {
udc_controller- > gadget. is_otg = 1;
/* now didn't support lpm in OTG mode*/
device_set_wakeup_capable( & pdev- > dev, 0) ;
}
/* setup QH and epctrl for ep0 */
ep0_setup( udc_controller) ;
/* setup udc->eps[] for ep0 */
struct_ep_setup( udc_controller, 0, "ep0" , 0) ;
/* for ep0: the desc defined here;
* for other eps, gadget layer called ep_enable with defined desc
*/
udc_controller- > eps[ 0] . desc = & fsl_ep0_desc;
udc_controller- > eps[ 0] . ep. maxpacket = USB_MAX_CTRL_PAYLOAD;
/* setup the udc->eps[] for non-control endpoints and link
* to gadget.ep_list */
for ( i = 1; i < ( int ) ( udc_controller- > max_ep / 2) ; i+ + ) {
char name[ 14] ;
sprintf ( name, "ep%dout" , i) ;
struct_ep_setup( udc_controller, i * 2, name, 1) ;
sprintf ( name, "ep%din" , i) ;
struct_ep_setup( udc_controller, i * 2 + 1, name, 1) ;
}
/* use dma_pool for TD management */
udc_controller- > td_pool = dma_pool_create( "udc_td" , & pdev- > dev,
sizeof ( struct ep_td_struct) ,
DTD_ALIGNMENT, UDC_DMA_BOUNDARY) ;
if ( udc_controller- > td_pool = = NULL ) {
ret = - ENOMEM;
goto err4;
}
if ( g_iram_size) {
for ( i = 0; i < IRAM_PPH_NTD; i+ + ) {
udc_controller- > iram_buffer[ i] =
USB_IRAM_BASE_ADDR + i * g_iram_size;
udc_controller- > iram_buffer_v[ i] =
IO_ADDRESS( udc_controller- > iram_buffer[ i] ) ;
}
}
# ifdef POSTPONE_FREE_LAST_DTD
last_free_td = NULL ;
# endif
/* disable all INTR */
fsl_writel( 0, & dr_regs- > usbintr) ;
dr_wake_up_enable( udc_controller, false ) ;
udc_controller- > stopped = 1;
portsc = fsl_readl( & dr_regs- > portsc1) ;
portsc | = PORTSCX_PHY_LOW_POWER_SPD;
fsl_writel( portsc, & dr_regs- > portsc1) ;
if ( udc_controller- > pdata- > usb_clock_for_pm)
udc_controller- > pdata- > usb_clock_for_pm( false ) ;
create_proc_file( ) ;
return 0;
err4:
device_unregister( & udc_controller- > gadget. dev) ;
err3:
free_irq( udc_controller- > irq, udc_controller) ;
err2:
if ( pdata- > platform_uninit)
pdata- > platform_uninit( pdata) ;
err2a:
iounmap( ( u8 __iomem * ) dr_regs) ;
err1:
if ( ! udc_controller- > transceiver)
release_mem_region( res- > start, resource_size( res) ) ;
err1a:
kfree( udc_controller) ;
udc_controller = NULL ;
return ret;
}
当设备使用主设备时 DEVICE的处理
static int udc_suspend( struct fsl_udc * udc)
{
u32 mode, usbcmd;
/* open clock for register access */
if ( udc_controller- > pdata- > usb_clock_for_pm)
udc_controller- > pdata- > usb_clock_for_pm( true ) ;
mode = fsl_readl( & dr_regs- > usbmode) & USB_MODE_CTRL_MODE_MASK;
usbcmd = fsl_readl( & dr_regs- > usbcmd) ;
pr_debug( "%s(): mode 0x%x stopped %d/n" , __func__ , mode, udc- > stopped) ;
/*
* If the controller is already stopped, then this must be a
* PM suspend. Remember this fact, so that we will leave the
* controller stopped at PM resume time.
*/
if ( udc- > stopped) {
pr_debug( "gadget already stopped, leaving early/n" ) ;
udc- > already_stopped = 1;
goto out;
}
if ( mode ! = USB_MODE_CTRL_MODE_DEVICE) {
pr_debug( "gadget not in device mode, leaving early/n" ) ;
goto out;
}
udc- > stopped = 1;
/* if the suspend is not for switch to host in otg mode */
if ( ( ! ( udc- > gadget. is_otg) ) | |
( fsl_readl( & dr_regs- > otgsc) & OTGSC_STS_USB_ID) ) {
dr_wake_up_enable( udc, true ) ;
dr_phy_low_power_mode( udc, true ) ;
}
/* stop the controller */
usbcmd = fsl_readl( & dr_regs- > usbcmd) & ~ USB_CMD_RUN_STOP;
fsl_writel( usbcmd, & dr_regs- > usbcmd) ;
printk( KERN_INFO "USB Gadget suspended/n" ) ;
out:
if ( udc_controller- > pdata- > usb_clock_for_pm)
udc_controller- > pdata- > usb_clock_for_pm( false ) ;
return 0;
}
当切换到从设备时调用
static int fsl_udc_resume( struct platform_device * pdev)
{
pr_debug( "%s(): stopped %d already_stopped %d/n" , __func__ ,
udc_controller- > stopped, udc_controller- > already_stopped) ;
/*
* If the controller was stopped at suspend time, then
* don't resume it now.
*/
if ( udc_controller- > already_stopped) {
udc_controller- > already_stopped = 0;
pr_debug( "gadget was already stopped, leaving early/n" ) ;
return 0;
}
/* Enable DR irq reg and set controller Run */
if ( udc_controller- > stopped) {
dr_wake_up_enable( udc_controller, false ) ;
dr_phy_low_power_mode( udc_controller, false ) ;
mdelay( 1) ;
dr_controller_setup( udc_controller) ;
dr_controller_run( udc_controller) ;
}
udc_controller- > usb_state = USB_STATE_ATTACHED;
udc_controller- > ep0_dir = 0;
printk( KERN_INFO "USB Gadget resumed/n" ) ;
return 0;
}
上面的两个函数就是在上一篇OTG 一中介绍的
gadget_pdrv- > resume ( gadget_pdev ) ;
gadget_pdrv - > suspend ( gadget_pdev , otg_suspend_state ) ;
这两处就是只想的这个函数。而把 前面的函数和上面这两个指针链接的地方就是在OTG中的
fsl_otg_start_gadget 函数。
从 上面我们可以看到以下几点:
1.OTG 功能的从设备使用的资源和私有数据与OTG设备的一致,(主设备也是一致)
2. 从设备主要为OTG功能提供fsl_udc_resume和udc_suspend两个函数。
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(二)
- OTG驱动分析(一)
- USB OTG驱动分析
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- USB OTG驱动分析(一)
- OTG Transceiver --- ISP1301 的驱动代码分析(一)
- JVM 集成化工具JConsole
- memcached: error while loading shared libraries: libevent-2.0.so.5: cannot o解决
- 适应iPhone5的尺寸
- java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码
- [转]JQuery.Ajax之错误调试帮助信息
- OTG驱动分析(二)
- TreeView 拖动排序
- 对象引用类型
- 10个直接可以用的jQuery代码片段
- 学习IOS编程必须要知道的一些知识
- hdu 2829 Lawrence
- JVM调优
- USB On-The-Go引脚 说明
- 显示DIV边框,通过margin设置DIV的位置