dsp的usb驱动开发_dsp usb驱动 - CSDN
  • 开发DSP硬件驱动程序的一种方法

    千次阅读 2011-06-07 21:08:00
    开发DSP硬件驱动程序的一种方法 张 行,雷 勇 (四川大学电气信息学院 四川 成都610065) l 引 言 传统的DSP程序开发包含两方面程序:即配置、控制、中断等管理DSP片内外设、接口的硬件相关程序和基于应用的算法程序...

    开发DSP硬件驱动程序的一种方法

              行,雷 (四川大学电气信息学院 四川 成都610065)

    l

          传统的DSP程序开发包含两方面程序:即配置、控制、中断等管理DSP片内外设、接口的硬件相关程序和基于应用的算法程序。这样的系统结构,应用程序与硬件相关程序紧密的结合一起,限制了程序的可移植性和通用性,软件开发总要从零开始,存在诸多重复工作。一旦硬件平台有变化,往往与硬件程序捆绑一起的应用程序也需改动,代码的维护性和可移植性均不高。

     

    通过建立硬件驱动程序的开发模式,可使上述现象得到改善。因此,本文介绍一种开发TI公司DSP片内及片外硬件外设驱动程序的方法,并以C5000 DSPMcBSP/DMATMS320C5509USB驱动程序开发为具体对象,介绍这种方法的应用。

     

    2 基于DSP/BIOSIOM硬件驱动

    CCS应用环境中集成的实时操作系统DSP/BI-OS[1]中,硬件驱动程序最终以函数库的形式被封装起来,应用程序可不关心底层硬件外设的具体操作,通过调用DSP/BIOS相关的标准API与不同外设接口。接口按统一标准定义,即在DSP/BIOS中创建并配置硬件设备驱动

    模块为IOM(I/O Mini-driver)模式。

     

    IOM[2]DSP/BIOS的设备驱动模块的一种接口方式,配置硬件设备驱动模块为IOM模式可在DSP/BIOS的图形化界面(GUI)中方便完成。IOM模式将设备驱动程序分为两个层次:上一层是""驱动程序(class driv-er),这部分程序负责对存储缓冲区管理、由DSP/BIOS各类标准的API函数与应用程序接口,与设备硬件无关。下一层是"迷你"驱动程序(mini-driver),这部分程序集成了实际硬件相关的代码IOM接口将"迷你"驱动程序与""驱动程序联系一起,包括定义I/O数据包(IOM_Packet)以提交"迷你"驱动程序读写,定义功能函数包(IOM Fxns)完成相关初始化,打开或关闭通道,提交I/O数据传输与控制等任务,确保"迷你"驱动程序与""驱动程序运行协调一致。

     

    ""驱动程序直接在应用程序中出现,并且根据数据输入/输出的处理方式不同,有相应""驱动程序。主要是3种:流输入输出型""驱动(SIO)、管道型""驱动(PIP)和通用输入输出型""驱动(GIO)

    其中,SIO""驱动由两部分组成:SIO模块和DIO适配模块(Adapter)前者负责创建通道、数据流输入/输出DIO提供负责缓冲管理、信号同步、将API及参数与下层"迷你"驱动程序接口PIP""驱动由两部分组成:PIP模块和PIO适配模块(Adapter),前者创建管道、数据管道输入/输出,PIO提供负责缓冲管理、信号同步、将API及参数与下层"迷你"驱动程序接口GIO""驱动是一种通用输入输出接口,调用的API函数,可通过阻塞线程读写数据,直接与"迷你"驱动通信。SIOPIPGIO模块集成在DSP/BIOS中,SIO通道、PIP管道可在DSP/BIOS的输入输出模块图形化界面(GUI)中静态设置并创建,也可以在应用程序中动态创建。DIOPIO适配模块(Adapter)创建在DSP/BIOS的设备驱动模块图形化界面(GUI)中完成。

     

    由上可见,""驱动程序均为标准的API函数,故编写驱动程序的重点是"迷你"驱动程序方面。"迷你"驱动通过创建统一接口标准的功能函数包(IOM Fxns),应用程序就可以由DIO适配模块或PIO适配模块或GIO""驱动调用"迷你"驱动,控制底层硬件设备。这些统一接口标准的功能函数包括:mdBindDev:设备与"迷你"驱动绑定函数;

    mdControlChan:设备通道控制函数;mdCreateChan:设备通道创建函数;mdDeleteChan:设备通道删除函数;mdSubmitChan:按IOM数据包命令执行函数;mdUnBindDev:设备从"迷你"驱动释放函数。

     

    IOM数据包是其中一关键数据结构,为IOM驱动程序内部数据的输入输出服务。应用程序本身不会涉及IOM数据包访问,是IO适配模块、PIO适配模块或GIO""驱动通过他访问"迷你"驱动层,其中,数据结构的cmd项,即""驱动命令"迷你"驱动的mdSubmitChan功能函数执行硬件设备的读写等操作。"迷你"驱动完成相应操作,通过回调函数后向上返回该数据包。

     

    3 McBSP/DMA驱动程序开发

    这是基于C5000系列DSPMcBSPDMA硬件驱动开发。系统以TMS320VC5410CPUTLC320AD50C为音频编解码芯片,TLC320AD50CDSPMcBSP0通道接口,数据传输采用DMA方式。在传统的软件开发结构中,应用程序一般通过DMA中断服务程序控制硬件设备及数据管理。在本文推荐的软件开发结构中,硬件设备驱动程序与应用程序隔离开,他们之间通过DSP/BIOSAPI接口,包括硬件设备初始化参数的传递。

    具体开发过程如下:

     (1)IOM驱动程序

    mdBindDevDSP/BIOS启动时调用,具体完成硬件设备初始化参数传递、获取McBSPDMA资源,McBSPDMA的初始化参数用CSL配置,注意McBSP使用的是通道OmdCreateChan在应用层与硬件设备创建两个逻辑通道,即DMA接收、发送通道。分别设置初始化参数。mdSubmitChanIOM数据包数据结构的cmd项,命令"迷你"驱动执行向硬件设备的IOM写操作,即通过McBSP0输出数据。相应工程编译链接生成驱动库函数,完成IOM驱动程序。

    (2)DMA/McBSP应用程序

    在应用工程中,首先在DSP/BIOS配置工具中User-Defined Devices项进行"迷你"驱动程序注册,命名为"co-dec"。属性如图3(a)所示。注册信息中设置了驱动程序的初始化函数、IOM函数包指针、设备参数指针的名称。本应用采用IOM驱动程序的流输入输出""驱动(SIO/DIO)DIO适配模块与上述"迷你"驱动程序"codec''接口,DIO适配模块在DSP/BIOS配置工具中添加,命名为"dio codec",本应用选择DMA通道45,设置TLC320AD50C4个控制寄存器初始化参数,即"迷你"驱动程序注册信息的设备参数指针所指内容。

    然后,应用程序通过调用DSP/BIOSAPI,动态创建DMA/McBSP输入、输出通道,如:

    SIO输人、输出通道均采用双缓冲管理。获取双缓冲资源,管理缓冲数据的工作,同样由SIO相关API完成,API的使用方法可参见参考文献中所列手册。

    4  USB驱动程序开发

    这是基于C5000系列DSP(TMS320C5509A)USB硬件驱动开发。TMS320C5509A内部集成符合USB 2.0标准的全速模式USB接口。SIE[3](Serial Interface En-gine)负责将数据按照USB物理电平信号串行转并行输入或并行转串行输出,并且具有错误校验机制。UBM(USB

    Buffer Manager)负责数据缓冲管理,管理数据在SIE和缓冲RAM的输入输出,CPUUSBDMA控制器在缓冲RAM收发数据。

     

    本硬件驱动的软件开发结构与上述McBSP/DMA硬件驱动开发类似,上层为""驱动,即DSP/BIOS GIOSIO,或PIP模块,提供针对USB"迷你"驱动的各种输入输出请求。"迷你"驱动是基于DSP/BIOS关于USB模块的CSL(Chip Support Library),调用CSLAPI完成底层硬件各种复杂操作。

     (1)IOM驱动程序

    C5509 USB mdBindDevDSP/BIOS启动时调用,完成USB初始化参数传递,中断向量设置,初始化USB模块;C5509 USB mdControlChan接受如SIOcontrol"类驱动"命令,可复位USB数据通道,连接主机USB接口等工作;C5509 USB mdCreateChan创建某个USB端点的数据通道及配置数据传输方向;C5509 USB mdSubmitChan负责USB数据流输入输出管理。

     (2)USB应用程序

    DSP/BIOS配置工具中User-Defined Devices项进行"迷你"驱动程序注册,命名为"usb"。属性如图4(a)所示。本应用也采用流输入输出(SIO/DIO)DIO适配模块与上述"迷你"驱动程序"usb"接口,DIO适配模块在DSP/BIOS配置工具中添加,命名为"dio_usb",属性如图4(b)所示。

    应用程序动态创建USB的某端点为输入、输出通道,如:

    由上可知,应用层""驱动程序开发的通用性是很强的。

    5

    本文推荐的这种DSP硬件驱动开发方法,通过构建应用程序与硬件外设输入输出的统一数据接口,将接口代码层次化。当硬件设备改动后,应用程序可不做修改,应用程序的通用性、可移植性大大加强,硬件驱动程序也具有反复利用的特点。

     

    展开全文
  • Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成: 设备模块的初始化模块和卸载模块,上层软件接口模块...

           Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件),整个源程序由四个主体部分组成:

    设备模块的初始化模块和卸载模块,上层软件接口模块,数据传输模块


    具体的模块分析如下:

     一、初始化设备模块

            该驱动采用了显式的模块初始化和消除函数,即调用module_init来初始化一个模块,并在卸载时调用moduel-exit函数

            其具体实现如下: 

    1、模块初始化:

    module_init (usb_spca5xx_init); 
    
    static int __init  usb_spca5xx_init (void) 
    {  
    #ifdef CONFIG_PROC_FS                     
    	proc_spca50x_create ();//建立PROC设备文件 
    #endif /* CONFIG_PROC_FS */    
    	if (usb_register (&spca5xx_driver) < 0) //注册USB设备驱动    
    		return -1;    
    	info ("spca5xx driver %s registered", version);   
    	return 0; 
    }

    2、模块卸载:

    module_exit (usb_spca5xx_exit); 
    
    static void __exit  usb_spca5xx_exit (void) 
    {    
    	usb_deregister (&spca5xx_driver); //注销USB设备驱动   
    	info ("driver spca5xx deregistered"); 
    #ifdef CONFIG_PROC_FS    
    	proc_spca50x_destroy ();//撤消PROC设备文件 
    #endif /* CONFIG_PROC_FS */ 
    } 


    关键数据结构 USB驱动结构,即插即用功能的实现 

    static struct usb_driver spca5xx_driver = {        
    	"spca5xx",         
    	spca5xx_probe, //注册设备自我侦测功能        
    	spca5xx_disconnect,//注册设备自我断开功能        
    	{NULL,NULL} 
    };

    用两个函数调用spca5xx_probe 和spca5xx_disconnect来支持USB设备的即插即用功能:

    a -- spca5xx_probe具体实现如下:
    static void * spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) 
    {    
    	struct usb_interface_descriptor *interface;          //USB设备接口描述符 
    	struct usb_spca50x *spca50x;                    //物理设备数据结构   
    	int err_probe;   
    	int i;    
    	if (dev->descriptor.bNumConfigurations != 1)        //探测设备是不是可配置     
    		goto nodevice;   
    	if (ifnum > 0)     
    		goto nodevice;    
    	interface = &dev->actconfig->interface[ifnum].altsetting[0];  
    	MOD_INC_USE_COUNT;    
    	interface = &intf->altsetting[0].desc;   
    	if (interface->bInterfaceNumber > 0)     
    		goto nodevice;    
    	if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL) //分配物理地址空间     
    	{        
    		err ("couldn't kmalloc spca50x struct");       
    		goto error;     
    	}    
    
    	memset (spca50x, 0, sizeof (struct usb_spca50x));   
    	spca50x->dev = dev;    
    	spca50x->iface = interface->bInterfaceNumber;    
    	if ((err_probe = spcaDetectCamera (spca50x)) < 0)       //具体物理设备查找,匹配厂商号,设备号(在子程序中)       
    	{        
    		err (" Devices not found !! ");       
    		goto error;     
    	}    
    	PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name)
    	for (i = 0; i < SPCA50X_NUMFRAMES; i++)      
    		init_waitqueue_head (&spca50x->frame[i].wq);     //初始化帧等待队列     
    		init_waitqueue_head (&spca50x->wq);            //初始化驱动等待队列   
    
    	if (!spca50x_configure (spca50x))                  //物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号     
    	{        
    		spca50x->user = 0;        
    		init_MUTEX (&spca50x->lock);                  //信号量初始化       
    		init_MUTEX (&spca50x->buf_lock);        
    		spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;       
    		spca50x->buf_state = BUF_NOT_ALLOCATED;     
    	}                                    
    	else     
    	{
    		err ("Failed to configure camera");       
    			goto error;     
    	} 
      
    
    	/* Init video stuff */ 
      
    	spca50x->vdev = video_device_alloc ();           //设备控制块内存分配   
    	if (!spca50x->vdev)     
    		goto error;
    	memcpy (spca50x->vdev, &spca50x_template, sizeof (spca50x_template));  
    	//系统调用的挂接,在此将驱动实现的系统调用,挂到内核中   
    	video_set_drvdata (spca50x->vdev, spca50x); 
      
    		if (video_register_device (spca50x->vdev, VFL_TYPE_GRABBER, video_nr) < 0)     
    	{                                            
    	//video设备注册       
    		err ("video_register_device failed");       
    		goto error;     
    	} 
      
    	spca50x->present = 1;   
    	if (spca50x->force_rgb) 
        
    		info ("data format set to RGB");   
    	spca50x->task.sync = 0; 
      
    	spca50x->task.routine = auto_bh;   
    	spca50x->task.data = spca50x;   
    	spca50x->bh_requested = 0; 
    			
    	MOD_DEC_USE_COUNT; //增加模块使用数   
    	return spca50x; //返回数剧结构 
    error://错误处理   
    	if (spca50x->vdev)     
    	{ 
          
    		if (spca50x->vdev->minor == -1) 
           
    			video_device_release (spca50x->vdev);       
    		else 
           
    			video_unregister_device (spca50x->vdev);       
    		spca50x->vdev = NULL;     
    	} 
      
    	if (spca50x)     
    	{ 
          
    		kfree (spca50x);       
    		spca50x = NULL;     
    	} 
      
    	MOD_DEC_USE_COUNT;   
    	return NULL; 
    nodevice: 
      
    	return NULL; 
    }


    b -- Spca5xx_disconnect 的具体实现如下:
    static void  spca5xx_disconnect (struct usb_device *dev, void *ptr) 
    {    
    	struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;   
    	int n;    
    	MOD_INC_USE_COUNT; //增加模块使用数   
    	if (!spca50x)     
    		return;    
    	down (&spca50x->lock); //减少信号量   
    	spca50x->present = 0;  //驱动卸载置0    
    	for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //标示所有帧ABORTING状态     
    	{
    		spca50x->frame[n].grabstate = FRAME_ABORTING;     
    		spca50x->curframe = -1;   
    	
    	}
    	 for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //唤醒所有等待进程     
    	{
    		if (waitqueue_active (&spca50x->frame[n].wq))       
    			wake_up_interruptible (&spca50x->frame[n].wq);   
    		
    		if (waitqueue_active (&spca50x->wq))        
    			wake_up_interruptible (&spca50x->wq);    
    	}
    	spca5xx_kill_isoc(spca50x);  //子函数终止URB包的传输   
    	PDEBUG (3,"Disconnect Kill isoc done");    
    	up (&spca50x->lock);  //增加信号量    
    	while(spca50x->user) /如果还有进程在使用,进程切换       
    		schedule();      
    	down (&spca50x->lock);     
    	if (spca50x->vdev)  
    	{       
    		video_unregister_device (spca50x->vdev);   //注销video设备     
    		usb_driver_release_interface (&spca5xx_driver,&spca50x->dev->actconfig->interface[spca50x->iface]); //端口释放       
    		spca50x->dev = NULL;       
    	}
    	up (&spca50x->lock); 
    #ifdef CONFIG_PROC_FS        
    	destroy_proc_spca50x_cam (spca50x); //注销PROC文件 
    #endif /* CONFIG_PROC_FS */ 
           
    	if (spca50x && !spca50x->user)                      //释放内存空间        
    	{           
    		spca5xx_dealloc (spca50x);          
    		kfree (spca50x);          
    		spca50x = NULL;        
    	}    
    	MOD_DEC_USE_COUNT;                              //减少模块记数   
    	PDEBUG (3, "Disconnect complete"); 
    }



    二、上层软件接口模块:  

            该模块通过file_operations数据结构,依据V4L协议规范,实现设备的关键系统调用,实现设备文件化的UNIX系统设计特点。作为摄相头驱动,其功能在于数据采集,而没有向摄相头输出的功能,因此在源码中没有实现write系统调用。

    其关键的数据结构如下:

    static struct video_device spca50x_template = {   
    	.owner = THIS_MODULE,  
    	.name = "SPCA5XX USB Camera",   
    	.type = VID_TYPE_CAPTURE,  
    	.hardware = VID_HARDWARE_SPCA5XX,   
    	.fops = &spca5xx_fops,         
    }; 
    
    
    static struct file_operations spca5xx_fops = {   
    	.owner = THIS_MODULE,  
    	.open = spca5xx_open, //open功能   
    	.release = spca5xx_close,//close功能   
    	.read = spca5xx_read, //read功能   
    	.mmap = spca5xx_mmap, //内存映射功能   
    	.ioctl = spca5xx_ioctl, //文件信息获取  
    	.llseek = no_llseek,//文件定位功能未实现 
    }; 

    1. Open功能

    完成设备的打开和初始化,并初始化解码器模块。其具体实现如下:

    static int  spca5xx_open(struct video_device *vdev, int flags) 
    {    
    	struct usb_spca50x *spca50x = video_get_drvdata (vdev);   
    	int err;    
    	MOD_INC_USE_COUNT;                         //增加模块记数   
    	down (&spca50x->lock);                              
    	err = -ENODEV;    
    
    	if (!spca50x->present)                 //检查设备是不是存在,有不有驱动,是不是忙     
    		goto out;  
    	err = -EBUSY;   
    	if (spca50x->user)     
    		goto out;    
    	err = -ENOMEM;    
    	if (spca50x_alloc (spca50x))  
    		goto out;                    
    	
    	err = spca50x_init_source (spca50x);           //初始化传感器和解码模块,在此函数的实现中,对每一款DSP芯片的初始化都不一样,对中星微301P的DSP芯片的初始化在子函数zc3xx_init,其实现方法为寄存器填值。   
    	if (err != 0)
    	{        
    		PDEBUG (0, "DEALLOC error on spca50x_init_source\n");       
    		up (&spca50x->lock);        
    		spca5xx_dealloc (spca50x);       
    		goto out2;     
    	} 
    
    	spca5xx_initDecoder(spca50x);                  //解码模块初始化,其模块的具体实现采用的是huffman算法   	spca5xx_setFrameDecoder(spca50x);   
    	spca50x->user++;    
    	
    	err = spca50x_init_isoc (spca50x);              //初始化URB(usb request block) 包,启动摄相头,采用同步传输的方式传送数据   
    	if (err)     
    	{        
    		PDEBUG (0, " DEALLOC error on init_Isoc\n");       
    		spca50x->user--;        
    		spca5xx_kill_isoc (spca50x);       
    		up (&spca50x->lock);        
    		spca5xx_dealloc (spca50x);       
    		goto out2;
    	}    
    
    	spca50x->brightness = spca50x_get_brghtness (spca50x) << 8;   
    	spca50x->whiteness = 0; 
    
    out:    
    	up (&spca50x->lock); 
    out2:   
    	if (err)     
    		MOD_DEC_USE_COUNT;   
    	if (err)    	
    	{        
    		PDEBUG (2, "Open failed");     
    	}   
    	else     
    	{        
    		PDEBUG (2, "Open done");    
     	}    
    	return err; 
    }

    2.Close功能

    完成设备的关闭,其具体过程是:

    static void spca5xx_close(struct video_device *vdev) 
    {   
    	struct usb_spca50x *spca50x =vdev->priv;   
    	int i;   
    	PDEBUG (2, "spca50x_close");   
    	down (&spca50x->lock);  //参数设置   
    	spca50x->user--;   
    	spca50x->curframe = -1; 
      
    	if(spca50x->present)//present:是或有驱动加载     
    	{      
    		spca50x_stop_isoc (spca50x);//停止摄相头工作和数据包送       
    		spcaCameraShutDown (spca50x);//关闭摄相头,由子函数spca50x_stop_iso完成   
    		for (i = 0; i < SPCA50X_NUMFRAMES; i++)    //唤醒所有等待进程     
    		{      
    			if(waitqueue_active(&spca50x->frame[i].wq)) 
             		wake_up_interruptible (&spca50x->frame[i].wq);     
    		} 
           	if(waitqueue_active (&spca50x->wq))        
    			wake_up_interruptible (&spca50x->wq);   
    	}  
       	
    	up(&spca50x->lock); 
       	spca5xx_dealloc (spca50x);//回收内存空间   
    	
    	PDEBUG(2,"Release ressources done");   
    	MOD_DEC_USE_COUNT; 
    } 

    3、 Read功能

     完成数据的读取,其主要的工作就是将数据由内核空间传送到进程用户空间

    static long spca5xx_rea(struct video_device *dev, char * buf, unsigned long count,int noblock) 
    {   
    	struct usb_spca50x *spca50x = video_get_drvdata (dev);   
    	int i;   
    	int frmx = -1;   
    	int rc;   
    	volatile struct spca50x_frame *frame; 
    	
            if(down_interruptible(&spca50x->lock))  //获取信号量       
    		return -EINTR; 
    	
            if(!dev || !buf){//判断设备情况     
    		up(&spca50x->lock);     
    		return -EFAULT; 
    	}  
      
    	if(!spca50x->dev){     
    		up(&spca50x->lock);     
    		return -EIO; 
    	} 
      	
    	if (!spca50x->streaming){     
    		up(&spca50x->lock);     
    		return -EIO; 
    	} 
    	
            if((rc = wait_event_interruptible(spca50x->wq,     //在指定的队列上睡眠,直到参数2的条件为真 
                  spca50x->frame[0].grabstate == FRAME_DONE || 
                  spca50x->frame[1].grabstate == FRAME_DONE ||               
    	      spca50x->frame[2].grabstate == FRAME_DONE ||               
                  spca50x->frame[3].grabstate == FRAME_DONE )))	
            {               
    		up(&spca50x->lock);               
    		return rc;        
    	}  
      
    
    	for (i = 0; i < SPCA50X_NUMFRAMES; i++)         //当数据到来     
    		if (spca50x->frame[i].grabstate == FRAME_DONE)   //标识数已到       
    			frmx = i;   
    	if (frmx < 0)     
    	{ 
          
    		PDEBUG(2, "Couldnt find a frame ready to be read.");       
    		up(&spca50x->lock);       
    		return -EFAULT;     
    	} 
      
    	frame = &spca50x->frame[frmx]; 
    	PDEBUG (2, "count asked: %d available: %d", (int) count,(int) frame->scanlength);   
    	if (count > frame->scanlength)     
    		count = frame->scanlength; 
      
    	if ((i = copy_to_user (buf, frame->data, count)))   //实现用户空间和内核空间的数据贝     
    	{ 
          
    		PDEBUG (2, "Copy failed! %d bytes not copied", i);           
    		up(&spca50x->lock);       
    		return -EFAULT;     
    	} 
      
    	/* Release the frame */  
    	frame->grabstate = FRAME_READY; //标识数据已空 
    	up(&spca50x->lock);                           
    	return count;//返回拷贝的数据数 
    }

    4、Mmap功能

    实现将设备内存映射到用户进程的地址空间的功能,其关键函数是remap_page_range,其具体实现如下:

    static int spca5xx_mmap(struct video_device *dev,const char *adr, unsigned long size) 
    { 
      
    	unsigned long start = (unsigned long) adr;   
    	struct usb_spca50x *spca50x = dev->priv;   
    	unsigned long page, pos;   
    	if (spca50x->dev == NULL)     
    		return -EIO; 
    	
    	PDEBUG (4, "mmap: %ld (%lX) bytes", size, size);   
    	if(size > (((SPCA50X_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE -1)))     
    		return -EINVAL; 
           
    	if (down_interruptible(&spca50x->lock))  //获取信号量               
    		return -EINTR; 
      
    	pos = (unsigned long) spca50x->fbuf;
    	while (size > 0)  //循环实现内存映射     
    	{      			
    		page = kvirt_to_pa (pos); 
    		if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){  //实现内存映射 
    			up(&spca50x->lock); 
    			return -EAGAIN;    
    		}       
    	
    		start += PAGE_SIZE;       
    		pos += PAGE_SIZE;       
    		if (size > PAGE_SIZE)        
    			size -= PAGE_SIZE;       
    		else     
    			size = 0;     
    	} 
    
    	up(&spca50x->lock); //释放信号量   
    	return 0; 
    }

    5、Ioctl功能:  

    实现文件信息的获取功能

    static int spca5xx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 
    {       
    	struct video_device *vdev = file->private_data;        
    	struct usb_spca50x *spca50x = vdev->priv;        
    	int rc; 
           
    	if(down_interruptible(&spca50x->lock))       //获取信号量               
    		return -EINTR; 
      	
    	rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl);  //将信息传送到用户进程,其关键函数实现spca5xx_do_ioctl 
    	up(&spca50x->lock);   
    	return rc;
    } 
    

    spca5xx_do_ioctl函数的实现依赖于不同的硬件,本驱动为了支持多种芯片,实现程序过于烦琐,其主要思想是通过copy_to_user(arg,b,sizeof(struct video_capability)函数将设备信息传递给用户进程。


    三、数据传输模块

          源程序采用tasklet来实现同步快速传递数据,并通过spcadecode.c上的软件解码模块实现图形信息的解码。此模块的入口点挂节在spca_open函数中,其具体的函数为spca50x_init_isoc。当设备被打开时,同步传输数据也已经开始,并通过spca50x_move_data函数将数据传递给驱动程序,驱动程序通过轮询的办法实现对数据的访问。

    Void outpict_do_tasklet (unsigned long ptr) 
    {   
    	int err;   
    	struct spca50x_frame *taskletframe = (struct spca50x_frame *) ptr;   
    	taskletframe->scanlength = taskletframe->highwater - taskletframe->data; 
      	PDEBUG (2, "Tasklet ask spcadecoder hdrwidth %d hdrheight %d method %d",         
    		taskletframe->hdrwidth, taskletframe->hdrheight,          
    		taskletframe->method); 
      
    	err = spca50x_outpicture (taskletframe);  //输出处理过的图片数据   
    	if (err != 0)     
    	{      
    		PDEBUG (0, "frame decoder failed (%d)", err);       
    		taskletframe->grabstate = FRAME_ERROR;    
    	}   
    	else     
    	{      
    		taskletframe->grabstate = FRAME_DONE;     
    	} 
      
    	if (waitqueue_active (&taskletframe->wq))//如果有进程等待,唤醒等待进程     
    		wake_up_interruptible (&taskletframe->wq); 
    }

    值得一提的是spcadecode.c上解码模块将原始压缩图形数据流yyuyv,yuvy, jpeg411,jpeg422解码为RGB图形,但此部分解压缩算法的实现也依赖于压缩的格式,归根结底依赖于DSP(数字处理芯片)中的硬件压缩算法。 


    四.USB CORE的支持

           LINUX下的USB设备对下层硬件的操作依靠系统实现的USB CORE层,USB CORE对上层驱动提供了众多函数接口如:usb_control_msg,usb_sndctrlpipe等,其中最典型的使用为源码中对USB端点寄存器的读写函数spca50x_reg_write和spca50x_reg_read等,具体实现如下:(举spca50x_reg_write的实现,其他类似)

    static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,__u16 value) 
    {       
    	int rc;        
    	rc = usb_control_msg(dev,          //通过USB CORE提供的接口函数设置寄存器的值 
    				usb_sndctrlpipe(dev, 0), 
    		                reg, 
    		                USB_TYPE_VENDOR | USB_RECIP_DEVICE, 
    		                value, index, NULL, 0, TimeOut); 
           
    	PDEBUG(5, "reg write: 0x%02X,0x%02X:0x%02X, 0x%x", reg, index, value, rc);        
    	if (rc < 0)              
    		err("reg write: error %d", rc);        
    	return rc; 
    } 


    展开全文
  • Android 开发之 ---- 底层驱动开发(一)

    万次阅读 多人点赞 2012-05-07 10:48:48
    驱动概述  说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正...

    驱动概述

            说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正,还增加了不少内容。android 驱动 主要分两种类型:Android 专用驱动 和 Android 使用的设备驱动(linux)。

          Android 专有驱动程序:

          1)Android Ashmem 匿名共享内存; 为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。

          2)Android Logger    轻量级的LOG(日志) 驱动;

          3)Android Binder     基于 OpenBinder 框架的一个驱动;

          4)Android Power Management  电源管理模块;

          5)Low Memory Killer  低内存管理器;

          6)Android PMEM        物理内存驱动;

          7)USB Gadget             USB 驱动(基于 gaeget 框架);

          8)Ram Console           用于调试写入日志信息的设备;

          9)Time Device             定时控制设备;  

         10)Android Alarm         硬件时钟


         Android 上的设备驱动:

          1)Framebuff 显示驱动;

          2)Event 输入设备驱动;

          3)ALSA 音频驱动;

          4)OSS 音频驱动;

          5)v412摄像头:视频驱动;

          6)MTD 驱动;

          7)蓝牙驱动;

          8)WLAN 设备驱动;


     Android 专有驱动程序

          1.Android Ashmem 

                   为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。

                   设备节点:/dev/ashmen .主设备号 10.

                   源码位置: include/linux/ashmen.h    Kernel /mm/ashmen.c

                         相比于 malloc 和 anonymous/named mmap 等传统的内存分配机制,其优势是通过内核驱动提供了辅助内核的内存回收算法机制(pin/unoin)

          2.Android Logger  

                        无论是底层的源代码还上层的应用,我们都可以使用 logger 这个日志设备看、来进行调试。

                         设备节点:  /dev/log/main      /dev/log/event   /dev/log/radio

                         源码位置:include/linux/logger.h         include/linux/logger.c

          3.Android Binder     

                    IPC Binder 一种进程间通信机制。他的进程能够为其它进程提供服务 ----- 通过标准的 Linux 系统调用 API。

                    设备节点 :/dev/binder

                    源码位置:Kernel/include/linux/binder.h    Kernel/drivers/misc/binder.c

          4.Android Power Management  

                   一个基于标准 linux 电源管理的轻量级 Android 电源管理系统,在 drivers/android/power.c      kernel/power/

          5.Low Memory Killer 

                    它在用户空间中指定了一组内存临界值,当其中某个值与进程描述中的 oom_adj 值在同一范围时,该进程将被Kill掉(在parameters/adj中指定oome_adj 的最小值)。它与标准的Linux OOM机制类似,只是实现方法不同

                    源码位置:drivers/misc/lowmemorykiller.c       

          6.Android PMEM       

                    PMEM 主要作用就是向用户空间提供连续的物理内存区域。

                          1.让 GPU 或 VPU 缓冲区共享 CPU 核心。

                          2.用于 Android service 堆。

                   源码位置:include/linux/android_pmem.h drivers/android/pmem.c                        

          7.USB Gadget            

                    基于标准 Linux USB gaeget 驱动框架的设备驱动。

                    源码位置:drivers/usb/gadet/ 

          8.Ram Console         

                    为了提供调试功能,android 允许将调试日志信息写入这个设备,它是基于 RAM 的 buffer.

                    源码位置: drivers/staging/android/ram_console.c

          9.Time Device            

                   定时控制,提供了对设备进行定时控制的功能。

                   源码位置:drivers/staging/android/timed_output.c(timed_gpio.c)

        10.Android Alarm       

                    提供一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会运行的时钟基准。

                     设备节点:/dev/alarm

                     源码位置:drivers/trc/alarm.c


    Android 设备驱动

        1. Framebuffer 帧缓存设备

             Framebuffer 驱动在 Linux 中是标准的显示设备的驱动。对于 PC 系统,它是显卡的驱动 ; 对于嵌入式 SOC 处理器系统,它是 LCD 控制器或者其他显示控制器的驱动。它是一个字符设备,在文件系统中设备节点通常是 /dev/fbx 。 每个系统可以有多个显示设备 , 依次用 /dev/fbO 、 /dev/fb l
    等来表示。在 Android 系统中主设备号为 29 ,次设备号递增生成。

             Android 对 Framebuffer 驱动的使用方式是标准的 , 在 / dev / graphie / 中的 Framebuffer 设备节点由 init 进程自动创建 , 被 libui 库调用 。 Android 的 GUI 系统中 , 通过调用 Framebuffer 驱动的标准接口,实现显示设备的抽象。

             

         Framebuff的结构框架和实现 : 

              linux LCD驱动(二)--FrameBuffer  

                  Linux LCD驱动(四)--驱动的实现                                    

        2.Event输入设备驱动

             Input 驱动程序是 Linux 输入设备的驱动程序 , 分为游戏杆 (joystick) 、 鼠标 (mouse 和 mice)和事件设备 (Event queue)3 种驱动程序。其中事件驱动程序是目前通用的程序,可支持键盘 、 鼠标、触摸屏等多种输入设备。 Input 驱动程序的主设备号是 l3 ,每一种 Input 设备从设备号占 用5 位 , 3 种从设备号分配是 : 游戏杆 0 ~ 61 ; Mouse 鼠标 33 ~ 62 ; Mice 鼠标 63 ; 事件设备 64 ~ 95 ,各个具体的设备在 misc 、 touchscreen 、 keyboard 等目录中。
            Event 设备在用户空问使用 read 、 ioctl 、 poll 等文件系统的接口操作, read 用于读取输入信息, ioctl 用于获取和设置信息, poll 用于用户空间的阻塞,当内核有按键等中断时,通过在中断中唤醒内核的 poll 实现。 

            Event 输入驱动的架构和实现:

                              Linux设备驱动之——input子系统

     

         3.ALSA音频驱动

             高级 Linux 声音体系 ALSA(Advanced Linux Sound Architecture ) 是为音频系统提供驱动 的Linux 内核组件,以替代原先的开发声音系统 OSS 。它是一个完全开放源代码的音频驱动程序集 ,除了像 OSS 那样提供一组内核驱动程序模块之外 , ALSA 还专门为简化应用程序的编写提供相应的函数库,与 OSS 提供的基于 ioctl 等原始编程接口相比, ALSA 函数库使用起来要更加方便一些 

            利用该函数库,开发人员可以方便、快捷地开发出自己的应用程序,细节则留给函数库进行内部处理 。 所以虽然 ALSA 也提供了类似于 OSS 的系统接口 , 但建议应用程序开发者使用音频函数库,而不是直接调用驱动函数。

                         ALSA 驱动的主设备号为 116 ,次设备号由各个设备单独定义,主要的设备节点如下:
                                 / dev / snd / contmlCX —— 主控制 ;
                                 / dev / snd / pcmXXXc —— PCM 数据通道 ;
                                 / dev / snd / seq —— 顺序器;
                                 / dev / snd / timer —— 定义器。
            在用户空问中 , ALSA 驱动通常配合 ALsA 库使用 , 库通过 ioctl 等接口调用 ALSA 驱动程序的设备节点。对于 AIJSA 驱动的调用,调用的是用户空间的 ALsA 库的接口,而不是直接调用  ALSA 驱动程序。 ALSA 音频驱动的架构如下图所示:

                                         

            ALSA 驱动程序的主要头文件是 include / sound ./ sound . h ,驱动核心数据结构和具体驱动的注册函数是 include / sound / core . h ,驱动程序 的核心实现是 Sound / core / sound . c 文件。                     

           ALSA 驱动程序使用下面的函数注册控制和设备:

                    int snd _ pcm _ new (struct snd _ card * card , char * id , int device , int playback _ count , int capture _ count , struct snd _ pcm ** rpcm) ;

                     int snd ctl _ add(struct snd _ card * card , struct snd _ kcontrol * kcontro1) ;

             ALSA 音频驱动在内核进行 menuconfig 配置时 , 配置选项为 “ Device Drivers ” > “ Sound c ard support ” 一 > “ Advanced Linux Sound Architecture ” 。子选项包含了 Generic sound devices( 通用声音设备 ) 、 ARM 体系结构支持,以及兼容 OSS 的几个选项。 ALsA 音频驱动配置对应的文件是sound / core / Kconfig 。

          Android 没有直接使用 ALSA 驱动,可以基于 A-LSA 驱动和 ALSA 库实现 Android Audio 的硬件抽象层; ALSA 库调用内核的 ALSA 驱动, Audio 的硬件抽象层调用 ALSA 库。      


          4.OSS音频驱动

             OSS(Open Sound System开放声音系统)是 linux 上最早出现的声卡驱动。OSS 由一套完整的内核驱动程序模块组成,可以为绝大多数声卡提供统一的编程接口。

             OSS 是字符设备,主设备号14,主要包括下面几种设备文件:

              1) /dev/sndstat

                     它是声卡驱动程序提供的简单接口,它通常是一个只读文件,作用也只限于汇报声卡的当前状态。(用于检测声卡)

              2)/dev/dsp

                     用于数字采样和数字录音的设备文件。对于音频编程很重要。实现模拟信号和数字信号的转换。

              3)/dev/audio

                     类似于/dev/dsp,使用的是 mu-law 编码方式。

              4)/dev/mixer

                     用于多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。

              5)/dev/sequencer

                       这个设备用来对声卡内建的波表合成器进行操作,或者对 MIDI 总线上的乐器进行控制。

               OSS 驱动所涉及的文件主要包括:

                    kernel/include/linux/soundcard.h

                    kernel/include/linux/sound.h   定义 OSS 驱动的次设备号和注册函数

                    kernel/sound_core.c    OSS核心实现部分

               OSS驱动架构图:

           

         5.V4l2视频驱动

       V4L2是V4L的升级版本,为linux下视频设备程序提供了一套接口规范。包括一套数据结构和底层V4L2驱动接口。V4L2提供了很多访问接口,你可以根据具体需要选择操作方法。需要注意的是,很少有驱动完全实现了所有的接口功能。所以在使用时需要参考驱动源码,或仔细阅读驱动提供者的使用说明。

          V4L2的主设备号是81,次设备号:0~255,这些次设备号里也有好几种设备(视频设备、Radio设备、Teletext、VBI)。

            V4L2的设备节点: /dev/videoX, /dev/vbiX and /dev/radioX

          V4L2框架图:

            


    展开全文
  • 1,先声明,俺是个做软件的,抽风了想玩下DSP 最开始的想法是想让DSP和电脑连上首选了基于CSL,可看着看着书,看到...看文档吧,找了本《TI DSPIOS用户手册与驱动开发》,看的迷迷糊糊。上面写的高大上,什么都能...

    1,先声明,俺是个做软件的,抽风了想玩下DSP

    最开始的想法是想让DSP和电脑连上首选了基于CSL,可看着看着书,看到居然有USB driver,于是开始在网上找USB driver,花了我好长时间终于还是在TI 的WIKI上找到了,免费可以下载的地方。

    对一个对BIOS一无所知的小白来说。。。

    看文档吧,找了本《TI DSPIOS用户手册与驱动开发》,看的迷迷糊糊。上面写的高大上,什么都能用像MFC一样加个头文件就能运行OK了。弄了个大概明白,就试试吧,结果,书上的设置用的是CCS V3.3,我用的是5.5,

    N多的监视功能位置都不一样了。当时就成了,我是谁,我在那。。。。

    终于在tools看到几个书上有的,应该就这了吧。

    墨迹了半天,入主题

    DDK1.1中例子在这个文件夹

    先把驱动DEBUG 编译,方便调试代码。

    然后

    这个还是用有L的吧。

    可以选上面那个,不过生成的路径就要重设置

    然后可以一路NEXT到finish

    编译一下,会发现报错,

    把这两个加上

    BIOS也可以用其它版本,会意就好了。

    然后当然是BUILD了

    同上把APP文件夹里的ddk_1_11\apps\usb\evm5509做IMPORT,可以用SIO或者GIO的

    最开始我选了高大上的SIO,出错,所以又选了GIO(结构上相对简单)好调试

    导入工程后,又成了我是谁我在那。。。。。

    贴关键的

    注意这个选项,让你想用的有效就好了,GIO_USBTESTLCFG.TCF打不开,用没有L的看就好了,因为里面是

    environment["config._55l_"] = true;

    utils.importFile("gio_usbtestcfg.tcf");
     

    同样的,要添加 CSL INCLUDE路径,还有DDK的路径,当然现在是个.OUT了,还要添加LIB文件。

    这里要说下,USB驱动默认生成的是.l55l的扩展名,所以要选下*.*,就不贴图了

    编译,然后,我看到了USB 1.1的USB设备。

    故事到这还没完。这TEST的程序结构也不太好,自己建了个工程

    新建了个TCF(BIOS文件)DEV等各种设置抄一下,然后。编译,运行。。

    没看到新的USB设备啊。。。。又是找不到自己的感觉。

    然后蒙B的我,在想为什么,设置都OK了,运行到GIO_create怎么就失败了哪?

    硬着头皮看汇编吧,对比着GIO_CREA.C看到了MEM_calloc失败。

    写了这么多年程序,写的程序出现内存申请失败的情况都是一支手数过来的,这他喵的我8K的 DARAM申请个几10字节

    居然失败,崩溃。

    知道了是内存问题,只好回归文档了,总算在MEM_alloc的文档中看到点东东,随手翻到的。。。

    然后回到BIOS设置界面

    选择可以动态分配内存后,确定退出,然后

    我先用个大的。

    再回到MEM的属性中,选成DARAM,保存,rebuild,然后运行,

    USB来了,前后花了我一个多月的业余吃饭,喝酒时间。

    高大上是有代价的啊。。。。

    展开全文
  • Linux下的硬件驱动——USB设备(上)(驱动配置部分)USB设备越来越多,而Linux在硬件配置上仍然没有做到完全即插即用,对于Linux怎样配置和使用他们,也越来越成为困扰我们的一大问题。本文着力从Linux系统下设备...
  • ADI DSP仿真器,经常有朋友问我驱动在哪?我的内心一直在打问号,不是应该插入电脑后就直接自动安装好么?但是问的人越来越多,我就在这里说一下吧。 理论上讲,你只要用的是ADI公司的原厂仿真器,或者OpenADSP开源...
  • sky我所做的事情都是源于自己对梦想的追求--分享技术、共同创造新世界---欢迎交流:zhangbinghua2012@163.com博客园首页新随笔联系订阅管理Android 开发之 ---- 底层驱动开发(一) 【转】转自:...驱动概述 ...
  • 针对当前应用的复杂性,SOC芯片更好能能满足应用和媒体的需求,集成众多接口,用ARM做为应用处理器进行多样化的应用开发和用户界面和接口,利用DSP进行算法加速,特别是媒体的编解码算法加速,既能够保持算法的灵活...
  • 驱动开发必备硬件知识

    千次阅读 2018-02-19 14:15:09
    作为一名软件驱动开发的工程师,我们不需要去设计硬件的原理图,PCB。我们只需看懂硬件开发人员提供的硬件模块时序就行了,但是我们应该也需了解如下硬件知识。 一)处理器 1,可分为通用处理器(单片机,ARM),...
  • USB过滤驱动,实现U盘只读控制

    千次阅读 2017-08-21 22:03:20
    这是一个简单的USB过滤驱动,采用标准的WDM过滤,以DDK中的filter为原形。实现了U盘的只读控制。  说明:  1 在整个编写过程中,受到tiamo等众多高手的帮助,感激不尽。还要向他们多多学习。  2 这是我写的...
  • 《Windows驱动开发技术详解》学习笔记

    万次阅读 多人点赞 2019-02-21 09:55:36
      如果推荐 Windows 驱动开发的入门书,我强烈推荐《Windows驱动开发技术详解》。但是由于成书的时间较早,该书中提到的很多工具和环境都已不可用或找不到,而本文搜集了大部分的工具,并在 win10X64 上安装开发...
  • Android驱动开发-底层驱动开发

    千次阅读 2013-03-13 22:12:33
    Android驱动开发的一些参考资料,转载过来以后学习学习! Android 开发之 ---- 底层驱动开发(一) 驱动概述  说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 ...
  • (2) 精通C / C++ 语言,5年以上嵌入式驱动开发经验; (3) 精通USB接口协议与编程; (4) 熟悉Arm或MIPS系列SOC,TI DSP等,有一定的硬件基础知识; (5) 具有嵌入式系统下USB、Audio、Camera等驱动程序的开发...
  • 这段时间成功的开发了中星微301H摄像头的wince驱动和视频采集程序。中星微摄像头出来的数据为JPEG格式,我们将其直接读出,交给应用程序来解码,就可以显示图像。中间的过程我们可以参考Linux GSPCA的驱动,将其移植...
1 2 3 4 5 ... 20
收藏数 3,785
精华内容 1,514
关键字:

dsp的usb驱动开发