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

📄 和设备文件对话(写和 ioctl).htm

📁 这是我做linux系统初始化过程分析时在网上收集到的资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
      /* 得到由进程给出的给 ioctl 的参数 */
      temp = (char *) ioctl_param;
   
      /* 找到消息的长度 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
      get_user(ch, temp);
      for (i=0; ch && i<BUF_LEN; i++, temp++)
        get_user(ch, temp);
#else
      for (i=0; get_user(temp) && i<BUF_LEN; i++, temp++)
	;
#endif

      /* 不要重新发明车轮-调用 device_write */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
      device_write(file, (char *) ioctl_param, i, 0);
#else
      device_write(inode, file, (char *) ioctl_param, i);
#endif
      break;

    case IOCTL_GET_MSG:
      /* 将当前的消息给调用进程 - 参数是一个指针,填充它 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
      i = device_read(file, (char *) ioctl_param, 99, 0); 
#else
      i = device_read(inode, file, (char *) ioctl_param, 
                      99); 
#endif
      /* 警告 - 我们假设缓冲区长度是100。如果它小于那将使缓冲区溢出而导致进程倾倒核心
       *(生成core文件)。
       *
       * 我们只允许99个字符的原因是字符串终止符 NULL 也需要空间。 */

      /* 将0放置在缓冲区尾使它适当的终止。 */
      put_user('\0', (char *) ioctl_param+i);
      break;

    case IOCTL_GET_NTH_BYTE:
      /* 这个 ioctl 既输入 (ioctl_param) 也输出(这个函数的返回值) */
      return Message[ioctl_param];
      break;
  }

  return SUCCESS;
}


/* 模块声明 *************************** */


/* 这个结构将保存当进程对我们创建的设备做什么时将调用的函数。因为这个结构的指针被保存在
 * 设备表中,所以它不能对 init_module是局部的。 NULL 是为未实现的函数保留的。 */
struct file_operations Fops = {
  NULL,   /* 偏移 */
  device_read, 
  device_write,
  NULL,   /* 读目录 */
  NULL,   /* 选择 */
  device_ioctl,   /* ioctl */
  NULL,   /* mmap */
  device_open,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  NULL,  /* 刷新 */
#endif
  device_release  /* 又名关闭 */
};


/* 初始化模块 - 登记字符设备 */
int init_module()
{
  int ret_val;

  /* 登记字符设备(至少是试图登记) */
  ret_val = module_register_chrdev(MAJOR_NUM, 
                                 DEVICE_NAME,
                                 &Fops);

  /* 负数表示错误 */
  if (ret_val < 0) {
    printk ("%s failed with %d\n",
            "Sorry, registering the character device ",
            ret_val);
    return ret_val;
  }

  printk ("%s The major device number is %d.\n",
          "Registeration is a success", 
          MAJOR_NUM);
  printk ("If you want to talk to the device driver,\n");
  printk ("you'll have to create a device file. \n");
  printk ("We suggest you use:\n");
  printk ("mknod %s c %d 0\n", DEVICE_FILE_NAME, 
          MAJOR_NUM);
  printk ("The device file name is important, because\n");
  printk ("the ioctl program assumes that's the\n");
  printk ("file you'll use.\n");

  return 0;
}


/* 清除 - 从 /proc 中注销相关文件 */
void cleanup_module()
{
  int ret;

  /* 注销设备 */
  ret = module_unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
 
  /* 如果有错误,报告它 */ 
  if (ret < 0)
    printk("Error in module_unregister_chrdev: %d\n", ret);
}
</PRE>
<P>范例 <FONT size=+1><B>chardev.h</B></FONT> <A name=442>&nbsp;</A><A 
name=443>&nbsp;</A> 
<P><PRE> 
/* chardev.h - 包含 ioctl 定义的头文件。
 *
 * 这里的声明必须在头文件中,因为他们需要被内核模块(chardev.c)和调用它的进程 (ioctl.c)知道。
 */

#ifndef CHARDEV_H
#define CHARDEV_H

#include &lt;linux/ioctl.h&gt; 



/* 主设备号。我们不能再依赖于动态的登记,因为 ioctl 需要知道它。 */
#define MAJOR_NUM 100


/* 设置设备驱动程序的消息 */
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
/* _IOR 意思是我们正在为从用户进程到内核模块的信息创建一个 ioctl 命令号。
 *
 * 第一个参数, MAJOR_NUM,是我们使用的主设备号。
 *
 * 第二个参数是命令号(可能是几个带有不同的意思的)。
 *
 * 第三个参数是我们想得到的从进程传到内核的类型。
 */

/* 得到设备驱动程序的消息 */
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
 /* 这个 IOCTL 用于输出,得到设备驱动程序的消息。然而我们仍然需要缓冲区作为输入放置消息,因为
  * 它已经被进程分配了。
  */


/* 得到消息的第n个字节 */
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
 /* 这个 IOCTL 既用于输入也用于输出。它接受来自用户的一个数 n ,然后返回 Message[n]。 */


/* 设备文件名 */
#define DEVICE_FILE_NAME "char_dev"


#endif
</PRE>
<P><A name=446>&nbsp;</A> <A name=447>&nbsp;</A> <A name=448>&nbsp;</A> <A 
name=449>&nbsp;</A> 
<P>范例 <FONT size=+1><B>ioctl.c</B></FONT> <A name=454>&nbsp;</A><A 
name=455>&nbsp;</A> 
<P><PRE> 
/* ioctl.c - 进程使用 ioctl 去控制内核模块
 *
 * 直到现在我们都使用 cat 做输入和输出。但是现在我们需要做 ioctl ,这需要写自己的进程。
 */

/* Copyright (C) 1998 by Ori Pomerantz */
 

/* 设备细节,例如 ioctl号和主设备号 */
#include "chardev.h"    


#include &lt;fcntl.h&gt;      /* 打开 */ 
#include &lt;unistd.h&gt;     /* 退出 */
#include &lt;sys/ioctl.h&gt;  /* ioctl */



/*  ioctl 调用函数 */

ioctl_set_msg(int file_desc, char *message)
{
  int ret_val;

  ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);

  if (ret_val &lt; 0) {
    printf ("ioctl_set_msg failed:%d\n", ret_val);
    exit(-1);
  }
}



ioctl_get_msg(int file_desc)
{
  int ret_val;
  char message[100]; 

  /* 警告 - 这是危险的,因为我们没有告诉内核它允许写多远,因此它可能使缓冲区溢出。
   * 在真正的产品程序中,我们应该使用两个 ioctl - 一个告诉内核缓冲区长度而另一个填充缓冲区
   */
  ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);

  if (ret_val &lt; 0) {
    printf ("ioctl_get_msg failed:%d\n", ret_val);
    exit(-1);
  }

  printf("get_msg message:%s\n", message);
}



ioctl_get_nth_byte(int file_desc)
{
  int i;
  char c;

  printf("get_nth_byte message:");

  i = 0;
  while (c != 0) {
    c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);

    if (c &lt; 0) {
      printf(
      "ioctl_get_nth_byte failed at the %d'th byte:\n", i);
      exit(-1);
    }

    putchar(c);
  } 
  putchar('\n');
}




/* 主函数 - 调用 ioctl 函数 */
main()
{
  int file_desc, ret_val;
  char *msg = "Message passed by ioctl\n";

  file_desc = open(DEVICE_FILE_NAME, 0);
  if (file_desc &lt; 0) {
    printf ("Can't open device file: %s\n", 
            DEVICE_FILE_NAME);
    exit(-1);
  }

  ioctl_get_nth_byte(file_desc);
  ioctl_get_msg(file_desc);
  ioctl_set_msg(file_desc, msg);

  close(file_desc); 
}
</PRE>
<P><A name=458></A> 
<P>
<HR>
<!--Navigation Panel--><A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node19.html" 
name=tex2html599><IMG height=24 alt=next 
src="和设备文件对话(写和 IOCTL).files/next_motif.gif" width=37 align=bottom border=0></A> 
<A href="http://yangxingjun.myrice.com/chinesehow/kernel/mpg.html" 
name=tex2html595><IMG height=24 alt=up src="和设备文件对话(写和 IOCTL).files/error.htm" 
width=26 align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node17.html" 
name=tex2html589><IMG height=24 alt=previous 
src="C:\Documents and Settings\nonoka\My Documents\和设备文件对话(写和 IOCTL).files\error(1).htm" 
width=63 align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node1.html" 
name=tex2html597><IMG height=24 alt=contents 
src="和设备文件对话(写和 IOCTL).files/contents_motif.gif" width=65 align=bottom 
border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node34.html" 
name=tex2html598><IMG height=24 alt=index 
src="和设备文件对话(写和 IOCTL).files/index_motif.gif" width=43 align=bottom 
border=0></A> <BR><B>Next:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node19.html" 
name=tex2html600>启动参数</A> <B>Up:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/mpg.html" 
name=tex2html596>Linux 内核模块编程</A> <B>Previous:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node17.html" 
name=tex2html590>将 /proc 作为输入</A> <!--End of Navigation Panel-->
<ADDRESS><I></I><BR><I>1999-05-19</I> </ADDRESS></BODY></HTML>

⌨️ 快捷键说明

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