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

📄 spca5xx-fenxi.c

📁 Spac5xx的实现是按照标准的USB VIDEO设备的驱动框架编写(其具体的驱动框架可参照/usr/src/linux/drivers/usb/usbvideo.c文件)
💻 C
📖 第 1 页 / 共 2 页
字号:
    }

  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_isoc完成

  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;

}

2. Read功能:

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

static long 

spca5xx_read(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;                                //返回拷贝的数据数

}

3. 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;

}

4.  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;

}

 

以上为驱动程序的具体框架说明,以及其中的关键数据结构和函数说明。
 
 

⌨️ 快捷键说明

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