Linux中与驱动相关的ioctl函数

一:    ioctl函数的作用

    ioctl用于向设备发控制和配置命令 ,有些命令也需要读写一些数据,但这些数据是不能用read/write读写的,称为Out-of-band数据。也就是说,read/write读写的数据是in-band数据,是I/O操作的主体,而ioctl命令传送的是控制信息 ,其中的数据是辅助的数据。

    ioctl是设备驱动程序中对设备的I/O通道进行管理的函数,所谓对I/O通道进行管理,就是对设备的一些特性进行控制 ,例如,在串口线上收发数据通过read/write操作,而串口的波特率、校验位、停止位通过ioctl设置,A/D转换的结果通过read读取,而A/D转换的精度和工作频率通过ioctl设置。
    ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。
    如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那就是蛮拧了。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。
  
  所以,我们就使用ioctl来实现控制的功能 。要记住,用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

二: ioctl()用法
    int ioctl(int fd, ind cmd, …);

其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。下面是一个关于V4L视频采集中用到的用ioctl来配置视频采集设备(USB摄像头)的一些特性参数的例子:

1.   定义设备结构体

    struct vdIn {
    int fd ; //设备描述符
    char *videodevice ; //设备节点,在linux下,通用的视频采集设备节点为/dev/video0
    struct video_mmap vmmap;
    struct video_capability videocap;
    int mmapsize;
    struct video_mbuf videombuf;
    struct video_picture videopict;
    struct video_window videowin;
    struct video_channel videochan;   
    int cameratype ;
    char *cameraname;
    char bridge[9];
    int sizenative; // available size in jpeg
    int sizeothers;    // others palette
    int palette; // available palette
    int norme ; // set spca506 usb video grabber
    int channel ; // set spca506 usb video grabber
    int grabMethod ;
    unsigned char *pFramebuffer;
    unsigned char *ptframe[4];
    int framelock[4];
    pthread_mutex_t grabmutex;
    int framesizeIn ;
    volatile int frame_cour;
    int bppIn;
    int  hdrwidth;
    int  hdrheight;
    int  formatIn;
    int signalquit;   
    };

2.   设备节点赋值, "/dev/video0"是真实的物理摄像头设备在linux中的表示

    if (videodevice == NULL || *videodevice == 0)
    {
      videodevice = "/dev/video0";
    }

3.  调用 设备 初始化函数

   struct vdIn videoIn;  //在spcav4l.h中定义
   videodevice = "/dev/video0"; //节点
   int width = 352;  //宽
   int height = 288;   //高
   int format = VIDEO_PALETTE_JPEG; //格式
   int grabmethod = 1;

   memset (&videoIn, 0, sizeof (struct vdIn));
  if (init_videoIn(&videoIn, videodevice, width, height, format,grabmethod) != 0)
    
    if(debug) printf (" damned encore rate !!/n");

4.   设备初始化函数传值

  int init_videoIn (struct vdIn *vd, char *device, int width, int height,
          int format, int grabmethod)
{
  int err = -1;
  int i;
  if (vd == NULL || device == NULL)
    return -1;
  if (width == 0 || height == 0)
    return -1;
  if(grabmethod < 0 || grabmethod > 1)
      grabmethod = 1; //read by default;
    // check format
  vd->videodevice = NULL;
  vd->cameraname = NULL;
  vd->videodevice = NULL;
  vd->videodevice = (char *) realloc (vd->videodevice, 16);
  vd->cameraname = (char *) realloc (vd->cameraname, 32);


  snprintf (vd->videodevice, 12, "%s", device);
  if(debug) printf("video %s /n",vd->videodevice);


  memset (vd->cameraname, 0, sizeof (vd->cameraname));
  memset(vd->bridge, 0, sizeof(vd->bridge));
  vd->signalquit = 1;//信号设置
  vd->hdrwidth = width;
  vd->hdrheight = height;
  /*          compute the max frame size   */
  vd->formatIn = format; //传进来的 format = VIDEO_PALETTE_JPEG;
  vd->bppIn = GetDepth (vd->formatIn);
 

  vd->grabMethod = grabmethod;        //mmap or read
  vd->pFramebuffer = NULL;
  /* init and check all setting */


  err = init_v4l (vd); // V4L初始化函数
  ....................................................
}

相关推荐