Linux USB 驱动开发实例(一) —— USB摄像头驱动实现源码分析

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

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


具体的模块分析如下:

 一、初始化设备模块

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

        其具体实现如下: 

1、模块初始化:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. module_init (usb_spca5xx_init);   
  2.   
  3. static int __init  usb_spca5xx_init (void)   
  4. {    
  5. #ifdef CONFIG_PROC_FS                       
  6.     proc_spca50x_create ();//建立PROC设备文件   
  7. #endif /* CONFIG_PROC_FS */      
  8.     if (usb_register (&spca5xx_driver) < 0) //注册USB设备驱动      
  9.         return -1;      
  10.     info ("spca5xx driver %s registered", version);     
  11.     return 0;   
  12. }  

2、模块卸载:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. module_exit (usb_spca5xx_exit);   
  2.   
  3. static void __exit  usb_spca5xx_exit (void)   
  4. {      
  5.     usb_deregister (&spca5xx_driver); //注销USB设备驱动     
  6.     info ("driver spca5xx deregistered");   
  7. #ifdef CONFIG_PROC_FS      
  8.     proc_spca50x_destroy ();//撤消PROC设备文件   
  9. #endif /* CONFIG_PROC_FS */   
  10. }   


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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static struct usb_driver spca5xx_driver = {          
  2.     "spca5xx",           
  3.     spca5xx_probe, //注册设备自我侦测功能          
  4.     spca5xx_disconnect,//注册设备自我断开功能          
  5.     {NULL,NULL}   
  6. };  

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

a -- spca5xx_probe 具体实现如下:
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static void * spca5xx_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)   
  2. {      
  3.     struct usb_interface_descriptor *interface;          //USB设备接口描述符   
  4.     struct usb_spca50x *spca50x;                    //物理设备数据结构     
  5.     int err_probe;     
  6.     int i;      
  7.     if (dev->descriptor.bNumConfigurations != 1)        //探测设备是不是可配置       
  8.         goto nodevice;     
  9.     if (ifnum > 0)       
  10.         goto nodevice;      
  11.     interface = &dev->actconfig->interface[ifnum].altsetting[0];    
  12.     MOD_INC_USE_COUNT;      
  13.     interface = &intf->altsetting[0].desc;     
  14.     if (interface->bInterfaceNumber > 0)       
  15.         goto nodevice;      
  16.     if ((spca50x = kmalloc (sizeof (struct usb_spca50x), GFP_KERNEL)) == NULL) //分配物理地址空间       
  17.     {          
  18.         err ("couldn't kmalloc spca50x struct");         
  19.         goto error;       
  20.     }      
  21.   
  22.     memset (spca50x, 0, sizeof (struct usb_spca50x));     
  23.     spca50x->dev = dev;      
  24.     spca50x->iface = interface->bInterfaceNumber;      
  25.     if ((err_probe = spcaDetectCamera (spca50x)) < 0)       //具体物理设备查找,匹配厂商号,设备号(在子程序中)         
  26.     {          
  27.         err (" Devices not found !! ");         
  28.         goto error;       
  29.     }      
  30.     PDEBUG (0, "Camera type %s ", Plist[spca50x->cameratype].name)  
  31.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)        
  32.         init_waitqueue_head (&spca50x->frame[i].wq);     //初始化帧等待队列       
  33.         init_waitqueue_head (&spca50x->wq);            //初始化驱动等待队列     
  34.   
  35.     if (!spca50x_configure (spca50x))                  //物理设备配置(主要完成传感器侦测和图形参数配置),主要思想是给控制寄存器写值,读回其返回值,以此判断具体的传感器型号       
  36.     {          
  37.         spca50x->user = 0;          
  38.         init_MUTEX (&spca50x->lock);                  //信号量初始化         
  39.         init_MUTEX (&spca50x->buf_lock);          
  40.         spca50x->v4l_lock = SPIN_LOCK_UNLOCKED;         
  41.         spca50x->buf_state = BUF_NOT_ALLOCATED;       
  42.     }                                      
  43.     else       
  44.     {  
  45.         err ("Failed to configure camera");         
  46.             goto error;       
  47.     }   
  48.     
  49.   
  50.     /* Init video stuff */   
  51.     
  52.     spca50x->vdev = video_device_alloc ();           //设备控制块内存分配     
  53.     if (!spca50x->vdev)       
  54.         goto error;  
  55.     memcpy (spca50x->vdev, &spca50x_template, sizeof (spca50x_template));    
  56.     //系统调用的挂接,在此将驱动实现的系统调用,挂到内核中     
  57.     video_set_drvdata (spca50x->vdev, spca50x);   
  58.     
  59.         if (video_register_device (spca50x->vdev, VFL_TYPE_GRABBER, video_nr) < 0)       
  60.     {                                              
  61.     //video设备注册         
  62.         err ("video_register_device failed");         
  63.         goto error;       
  64.     }   
  65.     
  66.     spca50x->present = 1;     
  67.     if (spca50x->force_rgb)   
  68.       
  69.         info ("data format set to RGB");     
  70.     spca50x->task.sync = 0;   
  71.     
  72.     spca50x->task.routine = auto_bh;     
  73.     spca50x->task.data = spca50x;     
  74.     spca50x->bh_requested = 0;   
  75.               
  76.     MOD_DEC_USE_COUNT; //增加模块使用数     
  77.     return spca50x; //返回数剧结构   
  78. error://错误处理     
  79.     if (spca50x->vdev)       
  80.     {   
  81.         
  82.         if (spca50x->vdev->minor == -1)   
  83.          
  84.             video_device_release (spca50x->vdev);         
  85.         else   
  86.          
  87.             video_unregister_device (spca50x->vdev);         
  88.         spca50x->vdev = NULL;       
  89.     }   
  90.     
  91.     if (spca50x)       
  92.     {   
  93.         
  94.         kfree (spca50x);         
  95.         spca50x = NULL;       
  96.     }   
  97.     
  98.     MOD_DEC_USE_COUNT;     
  99.     return NULL;   
  100. nodevice:   
  101.     
  102.     return NULL;   
  103. }  


b -- Spca5xx_disconnect  的具体实现如下:
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static void  spca5xx_disconnect (struct usb_device *dev, void *ptr)   
  2. {      
  3.     struct usb_spca50x *spca50x = (struct usb_spca50x *) ptr;     
  4.     int n;      
  5.     MOD_INC_USE_COUNT; //增加模块使用数     
  6.     if (!spca50x)       
  7.         return;      
  8.     down (&spca50x->lock); //减少信号量     
  9.     spca50x->present = 0;  //驱动卸载置0      
  10.     for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //标示所有帧ABORTING状态       
  11.     {  
  12.         spca50x->frame[n].grabstate = FRAME_ABORTING;       
  13.         spca50x->curframe = -1;     
  14.       
  15.     }  
  16.      for (n = 0; n < SPCA50X_NUMFRAMES; n++)       //唤醒所有等待进程       
  17.     {  
  18.         if (waitqueue_active (&spca50x->frame[n].wq))         
  19.             wake_up_interruptible (&spca50x->frame[n].wq);     
  20.           
  21.         if (waitqueue_active (&spca50x->wq))          
  22.             wake_up_interruptible (&spca50x->wq);      
  23.     }  
  24.     spca5xx_kill_isoc(spca50x);  //子函数终止URB包的传输     
  25.     PDEBUG (3,"Disconnect Kill isoc done");      
  26.     up (&spca50x->lock);  //增加信号量      
  27.     while(spca50x->user) /如果还有进程在使用,进程切换         
  28.         schedule();        
  29.     down (&spca50x->lock);       
  30.     if (spca50x->vdev)    
  31.     {         
  32.         video_unregister_device (spca50x->vdev);   //注销video设备       
  33.         usb_driver_release_interface (&spca5xx_driver,&spca50x->dev->actconfig->interface[spca50x->iface]); //端口释放         
  34.         spca50x->dev = NULL;         
  35.     }  
  36.     up (&spca50x->lock);   
  37. #ifdef CONFIG_PROC_FS          
  38.     destroy_proc_spca50x_cam (spca50x); //注销PROC文件   
  39. #endif /* CONFIG_PROC_FS */   
  40.          
  41.     if (spca50x && !spca50x->user)                      //释放内存空间          
  42.     {             
  43.         spca5xx_dealloc (spca50x);            
  44.         kfree (spca50x);            
  45.         spca50x = NULL;          
  46.     }      
  47.     MOD_DEC_USE_COUNT;                              //减少模块记数     
  48.     PDEBUG (3, "Disconnect complete");   
  49. }  



二、上层软件接口模块:   

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

其关键的数据结构如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static struct video_device spca50x_template = {     
  2.     .owner = THIS_MODULE,    
  3.     .name = "SPCA5XX USB Camera",     
  4.     .type = VID_TYPE_CAPTURE,    
  5.     .hardware = VID_HARDWARE_SPCA5XX,     
  6.     .fops = &spca5xx_fops,           
  7. };   
  8.   
  9.   
  10. static struct file_operations spca5xx_fops = {     
  11.     .owner = THIS_MODULE,    
  12.     .open = spca5xx_open, //open功能     
  13.     .release = spca5xx_close,//close功能     
  14.     .read = spca5xx_read, //read功能     
  15.     .mmap = spca5xx_mmap, //内存映射功能     
  16.     .ioctl = spca5xx_ioctl, //文件信息获取    
  17.     .llseek = no_llseek,//文件定位功能未实现   
  18. };   

1. Open功能

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int  spca5xx_open(struct video_device *vdev, int flags)   
  2. {      
  3.     struct usb_spca50x *spca50x = video_get_drvdata (vdev);     
  4.     int err;      
  5.     MOD_INC_USE_COUNT;                         //增加模块记数     
  6.     down (&spca50x->lock);                                
  7.     err = -ENODEV;      
  8.   
  9.     if (!spca50x->present)                 //检查设备是不是存在,有不有驱动,是不是忙       
  10.         goto out;    
  11.     err = -EBUSY;     
  12.     if (spca50x->user)       
  13.         goto out;      
  14.     err = -ENOMEM;      
  15.     if (spca50x_alloc (spca50x))    
  16.         goto out;                      
  17.       
  18.     err = spca50x_init_source (spca50x);           //初始化传感器和解码模块,在此函数的实现中,对每一款DSP芯片的初始化都不一样,对中星微301P的DSP芯片的初始化在子函数zc3xx_init,其实现方法为寄存器填值。     
  19.     if (err != 0)  
  20.     {          
  21.         PDEBUG (0, "DEALLOC error on spca50x_init_source\n");         
  22.         up (&spca50x->lock);          
  23.         spca5xx_dealloc (spca50x);         
  24.         goto out2;       
  25.     }   
  26.   
  27.     spca5xx_initDecoder(spca50x);                  //解码模块初始化,其模块的具体实现采用的是huffman算法      spca5xx_setFrameDecoder(spca50x);     
  28.     spca50x->user++;      
  29.       
  30.     err = spca50x_init_isoc (spca50x);              //初始化URB(usb request block) 包,启动摄相头,采用同步传输的方式传送数据     
  31.     if (err)       
  32.     {          
  33.         PDEBUG (0, " DEALLOC error on init_Isoc\n");         
  34.         spca50x->user--;          
  35.         spca5xx_kill_isoc (spca50x);         
  36.         up (&spca50x->lock);          
  37.         spca5xx_dealloc (spca50x);         
  38.         goto out2;  
  39.     }      
  40.   
  41.     spca50x->brightness = spca50x_get_brghtness (spca50x) << 8;     
  42.     spca50x->whiteness = 0;   
  43.   
  44. out:      
  45.     up (&spca50x->lock);   
  46. out2:     
  47.     if (err)       
  48.         MOD_DEC_USE_COUNT;     
  49.     if (err)          
  50.     {          
  51.         PDEBUG (2, "Open failed");       
  52.     }     
  53.     else       
  54.     {          
  55.         PDEBUG (2, "Open done");      
  56.     }      
  57.     return err;   
  58. }  

2.Close功能

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static void spca5xx_close(struct video_device *vdev)   
  2. {     
  3.     struct usb_spca50x *spca50x =vdev->priv;     
  4.     int i;     
  5.     PDEBUG (2, "spca50x_close");     
  6.     down (&spca50x->lock);  //参数设置     
  7.     spca50x->user--;     
  8.     spca50x->curframe = -1;   
  9.     
  10.     if(spca50x->present)//present:是或有驱动加载       
  11.     {        
  12.         spca50x_stop_isoc (spca50x);//停止摄相头工作和数据包送         
  13.         spcaCameraShutDown (spca50x);//关闭摄相头,由子函数spca50x_stop_iso完成     
  14.         for (i = 0; i < SPCA50X_NUMFRAMES; i++)    //唤醒所有等待进程       
  15.         {        
  16.             if(waitqueue_active(&spca50x->frame[i].wq))   
  17.                 wake_up_interruptible (&spca50x->frame[i].wq);       
  18.         }   
  19.         if(waitqueue_active (&spca50x->wq))          
  20.             wake_up_interruptible (&spca50x->wq);     
  21.     }    
  22.       
  23.     up(&spca50x->lock);   
  24.     spca5xx_dealloc (spca50x);//回收内存空间     
  25.       
  26.     PDEBUG(2,"Release ressources done");     
  27.     MOD_DEC_USE_COUNT;   
  28. }   

3、 Read功能

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static long spca5xx_rea(struct video_device *dev, char * buf, unsigned long count,int noblock)   
  2. {     
  3.     struct usb_spca50x *spca50x = video_get_drvdata (dev);     
  4.     int i;     
  5.     int frmx = -1;     
  6.     int rc;     
  7.     volatile struct spca50x_frame *frame;   
  8.       
  9.         if(down_interruptible(&spca50x->lock))  //获取信号量         
  10.         return -EINTR;   
  11.       
  12.         if(!dev || !buf){//判断设备情况       
  13.         up(&spca50x->lock);       
  14.         return -EFAULT;   
  15.     }    
  16.     
  17.     if(!spca50x->dev){       
  18.         up(&spca50x->lock);       
  19.         return -EIO;   
  20.     }   
  21.       
  22.     if (!spca50x->streaming){       
  23.         up(&spca50x->lock);       
  24.         return -EIO;   
  25.     }   
  26.       
  27.         if((rc = wait_event_interruptible(spca50x->wq,     //在指定的队列上睡眠,直到参数2的条件为真   
  28.               spca50x->frame[0].grabstate == FRAME_DONE ||   
  29.               spca50x->frame[1].grabstate == FRAME_DONE ||                 
  30.           spca50x->frame[2].grabstate == FRAME_DONE ||                 
  31.               spca50x->frame[3].grabstate == FRAME_DONE )))    
  32.         {                 
  33.         up(&spca50x->lock);                 
  34.         return rc;          
  35.     }    
  36.     
  37.   
  38.     for (i = 0; i < SPCA50X_NUMFRAMES; i++)         //当数据到来       
  39.         if (spca50x->frame[i].grabstate == FRAME_DONE)   //标识数已到         
  40.             frmx = i;     
  41.     if (frmx < 0)       
  42.     {   
  43.         
  44.         PDEBUG(2, "Couldnt find a frame ready to be read.");         
  45.         up(&spca50x->lock);         
  46.         return -EFAULT;       
  47.     }   
  48.     
  49.     frame = &spca50x->frame[frmx];   
  50.     PDEBUG (2, "count asked: %d available: %d", (int) count,(int) frame->scanlength);     
  51.     if (count > frame->scanlength)       
  52.         count = frame->scanlength;   
  53.     
  54.     if ((i = copy_to_user (buf, frame->data, count)))   //实现用户空间和内核空间的数据贝       
  55.     {   
  56.         
  57.         PDEBUG (2, "Copy failed! %d bytes not copied", i);             
  58.         up(&spca50x->lock);         
  59.         return -EFAULT;       
  60.     }   
  61.     
  62.     /* Release the frame */    
  63.     frame->grabstate = FRAME_READY; //标识数据已空   
  64.     up(&spca50x->lock);                             
  65.     return count;//返回拷贝的数据数   
  66. }  

4、Mmap功能

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int spca5xx_mmap(struct video_device *dev,const char *adr, unsigned long size)   
  2. {   
  3.     
  4.     unsigned long start = (unsigned long) adr;     
  5.     struct usb_spca50x *spca50x = dev->priv;     
  6.     unsigned long page, pos;     
  7.     if (spca50x->dev == NULL)       
  8.         return -EIO;   
  9.       
  10.     PDEBUG (4, "mmap: %ld (%lX) bytes", size, size);     
  11.     if(size > (((SPCA50X_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE -1)))       
  12.         return -EINVAL;   
  13.          
  14.     if (down_interruptible(&spca50x->lock))  //获取信号量                 
  15.         return -EINTR;   
  16.     
  17.     pos = (unsigned long) spca50x->fbuf;  
  18.     while (size > 0)  //循环实现内存映射       
  19.     {                   
  20.         page = kvirt_to_pa (pos);   
  21.         if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){  //实现内存映射   
  22.             up(&spca50x->lock);   
  23.             return -EAGAIN;      
  24.         }         
  25.       
  26.         start += PAGE_SIZE;         
  27.         pos += PAGE_SIZE;         
  28.         if (size > PAGE_SIZE)          
  29.             size -= PAGE_SIZE;         
  30.         else       
  31.             size = 0;       
  32.     }   
  33.   
  34.     up(&spca50x->lock); //释放信号量     
  35.     return 0;   
  36. }  

5、Ioctl功能:  

实现文件信息的获取功能

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int spca5xx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)   
  2. {         
  3.     struct video_device *vdev = file->private_data;          
  4.     struct usb_spca50x *spca50x = vdev->priv;          
  5.     int rc;   
  6.          
  7.     if(down_interruptible(&spca50x->lock))       //获取信号量                 
  8.         return -EINTR;   
  9.         
  10.     rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl);  //将信息传送到用户进程,其关键函数实现spca5xx_do_ioctl   
  11.     up(&spca50x->lock);     
  12.     return rc;  
  13. }   

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


三、数据传输模块

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

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. Void outpict_do_tasklet (unsigned long ptr)   
  2. {     
  3.     int err;     
  4.     struct spca50x_frame *taskletframe = (struct spca50x_frame *) ptr;     
  5.     taskletframe->scanlength = taskletframe->highwater - taskletframe->data;   
  6.       PDEBUG (2, "Tasklet ask spcadecoder hdrwidth %d hdrheight %d method %d",           
  7.         taskletframe->hdrwidth, taskletframe->hdrheight,            
  8.         taskletframe->method);   
  9.     
  10.     err = spca50x_outpicture (taskletframe);  //输出处理过的图片数据     
  11.     if (err != 0)       
  12.     {        
  13.         PDEBUG (0, "frame decoder failed (%d)", err);         
  14.         taskletframe->grabstate = FRAME_ERROR;      
  15.     }     
  16.     else       
  17.     {        
  18.         taskletframe->grabstate = FRAME_DONE;       
  19.     }   
  20.     
  21.     if (waitqueue_active (&taskletframe->wq))//如果有进程等待,唤醒等待进程       
  22.         wake_up_interruptible (&taskletframe->wq);   
  23. }  

值得一提的是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的实现,其他类似)

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,__u16 value)   
  2. {         
  3.     int rc;          
  4.     rc = usb_control_msg(dev,          //通过USB CORE提供的接口函数设置寄存器的值   
  5.                 usb_sndctrlpipe(dev, 0),   
  6.                         reg,   
  7.                         USB_TYPE_VENDOR | USB_RECIP_DEVICE,   
  8.                         value, index, NULL, 0, TimeOut);   
  9.          
  10.     PDEBUG(5, "reg write: 0x%02X,0x%02X:0x%02X, 0x%x", reg, index, value, rc);          
  11.     if (rc < 0)                
  12.         err("reg write: error %d", rc);          
  13.     return rc;   
  14. }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

System Center 2012R2之SCVMM云部署SCOM(2-2)

SCVMM云部署SCOM安装过程1、在SCVMM中&#xff0c;使用WINDOWS SERVER 2012母盘创建云主机SCOM在SCVMM中先创建到一个私有云指定一个私有云名称选择资源主机指定逻辑网络默认选负载衡器跳过VIP模板跳过选择端口&#xff0c;下一步选择存储分类指定存储的VM路径各只读共享默认设…

Linux USB 驱动开发实例(二)—— USB 鼠标驱动注解及测试

参考2.6.14版本中的driver/usb/input/usbmouse.c。鼠标驱动可分为几个部分&#xff1a;驱动加载部分、probe部分、open部分、urb回调函数处理部分。 一、驱动加载部分 [cpp] view plaincopy static int __init usb_mouse_init(void) { int retval usb_register(&a…

MySQL5.6 更改字段属性仍旧会锁全表,注意这个坑!

如图&#xff1a;如果开发让修改表字段属性&#xff0c;建议用pt-online-schema-change。MySQL5.6的在线DDL会锁全表。注意这个坑。另外&#xff0c;增加、删除字段或索引不会锁全表&#xff0c;删除主键会锁全表。

Linux USB 驱动开发实例 (三)—— 基于USB总线的无线网卡浅析

回顾一下USB的相关知识 USB(Universal Serial Bus)总线又叫通用串行外部总线&#xff0c;它是20世纪90年代发展起来的。USB接口现在得到了广泛的应用和普及&#xff0c;现在的PC机中都带有大量的USB接口。它最大的特点就是方便通用、支持热插拔并且可以在一个接口上插上多个设备…

Linux 设备驱动开发思想 —— 驱动分层与驱动分离

前面我们学习I2C、USB、SD驱动时&#xff0c;有没有发现一个共性&#xff0c;就是在驱动开发时&#xff0c;每个驱动都分层三部分&#xff0c;由上到下分别是&#xff1a; 1、XXX 设备驱动 2、XXX 核心层 3、XXX 主机控制器驱动 而需要我们编写的主要是设备驱动部分&#xff0c…

CortexM0开发 —— UART时序分析

通用异步收发传输器(UniversalAsynchronousReceiver/Transmitter)&#xff0c;通常称作UART&#xff0c;是一种异步收发传输器。将数据由串行通信与并行通信间作传输转换&#xff0c;作为并行输入成为串行输出的芯片UART是一种通用串行数据总线&#xff0c;用于异步通信。该总线…

CortexM0开发 —— LPC11C14的UART使用方法

LPC1100系列微控制器UART LPC1100系列Cortex-M0微控制器具有一个符合16C550工业标准的异步串行口&#xff08;UART&#xff09;。此口同时增加了调制解调器&#xff08;Modem&#xff09;接口&#xff0c;DSR、DCD和RI Modem信号是只用于LQFP48和PLCC44封装的管脚配置。 特性…

Linux SD卡驱动开发(一) —— SD 相关基础概念

一.SD/MMC卡基础概念 1.1.什么是MMC卡 MMC&#xff1a;MMC就是MultiMediaCard的缩写&#xff0c;即多媒体卡。它是一种非易失性存储器件&#xff0c;体积小巧(24mm*32mm*1.4mm)&#xff0c;容量大,耗电量低,传输速度快&#xff0c;广泛应用于消费类电子产品中。 1.2.什么是SD卡…

Linux SD卡驱动开发(二) —— SD 卡驱动分析HOST篇

回顾一下前面的知识&#xff0c;MMC 子系统范围三个部分&#xff1a; HOST 部分是针对不同主机的驱动程序&#xff0c;这一部是驱动程序工程师需要根据自己的特点平台来完成的。 CORE 部分: 这是整个MMC 的核心存&#xff0c;这部分完成了不同协议和规范的实现&#xff0c;并为…

MVC应用程序显示RealPlayer(rm)视频

本篇博文是演示MVC应用程序显示RealPlayer视频。 客户端能观看到RealPlayer视频&#xff0c;前提条件是需要安装RealPlayer客户端&#xff0c;就是想看Falsh或理WMV视频一样&#xff0c;均要安装客户端或相关插件等。 Insus.NET实现方法&#xff0c;还是在控制器中Render RealP…

Linux从入门到精通系列之PPTP

Linux从入门到精通系列之PPTP今天我们来说下怎么在linux环境下如何搭建PPTP-&#xff0c;PPTP&#xff08;Point to Point Tunneling Protocol&#xff09;&#xff0c;即点对点隧道协议。该协议是在PPP协议的基础上开发的一种新的增强型安全协议&#xff0c;支持多协议虚拟专用…

Linux SD卡驱动开发(三) —— SD 卡驱动分析CORE篇

废话不多说&#xff0c;直接切进主题&#xff1a; Linux在内核源码的drivers/mmc/core文件夹下为我们的提供了一系列SD卡的接口服务函数。可以查看Makefile如下 可见&#xff0c;core文件夹下有针对总线的服务bus.c&#xff0c;针对主控制器的服务host.c&#xff0c;针对SD卡的…

Python数值计算:一 使用Pylab绘图(1)

Pylab的使用 学习使用Python进行科学计算&#xff0c;然而很难找到简单实用&#xff0c;又循序渐进的例子。正好手边有一本《Matlab可视化大学物理学》&#xff0c;里面的例子非常清晰地解释了Matlab在物理学中的应用。重新使用Python实现这些例子&#xff0c;学习了Python&…

Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作

前面对SD卡控制器有了一个基本的介绍。其实SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法&#xff0c;当然不同的控制器对硬件控制的方法不尽相同&#xff0c;但是他们最终都能像core层提交一个统一的封装有操作方法的数据结构&#xff0c;那便是即将闪亮登场…

Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

Core层中有两个重要函数 mmc_alloc_host 用于构造host&#xff0c;前面已经学习过&#xff0c;这里不再阐述&#xff1b;另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe&#xff0c;现在就来回顾一下这个函数的作用。先简要的概括一下这个函数的功能&#xff…

navicat连接oracle 报 ORA-12737 set CHS16GBK

2019独角兽企业重金招聘Python工程师标准>>> 1首 先&#xff0c;我们打开“工具”-->"选项"菜单&#xff0c;见到如下界面&#xff0c;依据OCI library(oci.dll) 路径&#xff0c;导航到 navicat oci 目录下&#xff0c;备份里面的文件&#xff08;通过…

Linux SD卡驱动开发(六) —— SD卡启动过程总体分析

一、工作流程 mmc驱动主要文件包括 drivers/mmc/card/block.c drivers/mmc/card/queue.c drivers/mmc/core/core.c drivers/mmc/core/host.c drivers/mmc/core/ 内核启动时&#xff0c;首先执行core/core.c的mmc_init&#xff0c;注册mmc、sd总线&#xff0c;以及一个host clas…

svn怎么上传文件 — 百度经验无耻推广

2019独角兽企业重金招聘Python工程师标准>>> svn怎么上传文件 — 欢乐地点进去捧场 PS&#xff1a;觉得笔者太无耻&#xff0c;直接在下方评论抨击 转载于:https://my.oschina.net/cenqingbo/blog/212284

apache 重写和虚拟目录配置

要求&#xff1a;假如我请求一个地址&#xff1a;www.lxy.com/news-sport-id123.html转成&#xff1a;www.lxy.com/show.php?catenews&classsport&id123步骤&#xff1a;①首先我们需要在apache中启用rewrite模块打开apache的httpd.conf文件&#xff0c;找到#LoadModu…

JavaScript代码片段

简介&#xff1a;本文收集了我常用的JavaScript代码片段&#xff0c;欢迎提意见&#xff01; 大灰狼边敲门边说&#xff1a;“小兔子乖乖&#xff0c;把门儿开开&#xff01;” 小兔子听到后&#xff0c;连忙去开门&#xff1a;“来喽&#xff01;” 兔妈妈对小兔子喊道&#x…