2008 May 12th Monday (五月 十二日 月曜日)

本文介绍了一个使用ioctl()函数与字符设备交互的例子。通过一个具体的字符设备驱动程序,演示了ioctl()函数如何设置和获取设备消息,以及如何获取消息中特定位置的字节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

There is a example of talking with ioctl(). /* * chardev.c - Create an input/output character device */ #include <linux/kernel.h> /*We're doing kernel work*/ #include <linux/module.h> /*Specifically, a module*/ #include <linux/fs.h> #include <asm/uaccess.h> /*for get_user and put_user*/ #include "chardev.h" #define SUCCESS 0 #define DEVICE_NAME "char_dev" #define BUF_LEN 80 /* * Is the device open right now? Usedtoprevent * concurent access into the same device */ static int Device_Open=0; /* * The message the device will give when asked */ static char Message[BUF_LEN]; /* * How far did the process reading the message get? * Useful if the message is larger than the size of the * buffer we get to fill in device_read. */ static char *Message_Ptr; /* * This is called whenever a process attempts to open the device file */ static int device_open(struct inode *inode, struct file *file){ #ifdefDEBUG     printk("device_open(%p)/n",file); #endif     /*     * We don't want to talk to two processes at the same time     */     if(Device_Open)         return -EBUSY;             Device_Open++;         /*     * Initialize the message     */         Message_Ptr = Message;     try_module_get(THIS_MODULE);     return SUCCESS; } static int device_release(struct inode *inode, struct file *file){ #ifdefDEBUG     printk("device_release(%p,%p)/n",inode,file); #endif     /*     * We're now ready for our next caller     */     Device_Open--;         module_put(THIS_MODULE);     return SUCCESS; } /* * This function is called whenever a process which has already opened the * device file attempts to read from it. */ static ssize_t device_read(struct file *file, /*seeinclude/linux/fs.h */     char__user *buffer, /*buffer to be filled with data*/     size_t length, /*length of the buffer */     loff_t *offset) {     /*     * Number of bytes actually written to the buffer     */     int bytes_read=0; #ifdefDEBUG     printk("device_read(%p,%p,%d)/n",file,buffer,length); #endif     /*     * If we're at the end of the message, return 0     * (which signifies end of file)     */     if(*Message_Ptr==0)         return 0;         /*     * Actually put the data into the buffer     */     while (length && *Message_Ptr){         /*         * Because the buffer is in the user data segment,         * not the kernel data segment, assignmentwouldn't         * work. Instead, we have to use put_user which         * copies data from the kernel data segment to the         * user data segment.         */         put_user(*(Message_Ptr++), buffer++);         length--;         bytes_read++;     } #ifdefDEBUG     printk("Read%dbytes,%dleft/n",bytes_read,length); #endif     /*     * Read functions are supposed to return the number     * of bytes actually insertedintothebuffer     */     return bytes_read; } /* * This function is called when somebody tries to * write into our device file. */ staticssize_t device_write(struct file *file,     const char__user *buffer, size_t length, loff_t *offset) {     int i; #ifdefDEBUG     printk("device_write(%p,%s,%d)",file,buffer,length); #endif     for(i=0;i<length && i<BUF_LEN;i++)         get_user(Message[i],buffer+i);         Message_Ptr=Message;     /*     * Again, return the number of input characters used     */     return i; } /* * This function is called whenever a process tries to do an ioctl on our * device file. We get two extra parameters (additional to the inode and file * structures, which all device functions get): the number of the ioctl called * and the parameter given to the ioctl function. * * If the ioctl is write or read/write (meaning output is returned to the * calling process), the ioctl call returns the outputofthisfunction. * */ int device_ioctl(struct inode *inode, /*see include/linux/fs.h*/     struct file *file, /*ditto*/     unsigned int ioctl_num, /*number and param for ioctl*/     unsigned long ioctl_param) {     int i;     char *temp;     char ch;         /*     * Switch according to the ioctl called     */     switch(ioctl_num){     case IOCTL_SET_MSG:         /*         * Receive a pointer to a message(in user space) and set that         * to be the device's message. Get the parameter givento         * ioctl by the process.         */         temp=(char*)ioctl_param;         /*         * Find the length of the message         */         get_user(ch,temp);         for(i=0; ch && i<BUF_LEN; i++,temp++)             get_user(ch,temp);         device_write(file,(char *)ioctl_param,i,0);         break;     case IOCTL_GET_MSG:         /*         * Give the current message to the calling process -         * the parameter we got is a pointer, fill it.         */         i = device_read(file, (char *)ioctl_param, 99, 0);         /*         * Put a zero at the end of the buffer, so it will be         * properly terminated         */         put_user('/0',(char*)ioctl_param+i);         break;     case IOCTL_GET_NTH_BYTE:         /*         * This ioctl is both input (ioctl_param) and         * output (the return value of this function)         */         return Message[ioctl_param];         break;         }     return SUCCESS; } /* * This structure will hold the functions to be called * when a process does something to the device we * created. Since a pointer to this structureiskeptin * the devices table, it can't be local to * init_module. NULL is for unimplemented functions. */ struct file_operationsFops={     .read=device_read,     .write=device_write,     .ioctl=device_ioctl,     .open= device_open,     .release=device_release, /*a.k.a.close*/ }; int init_module() {     int ret_val;     /*     * Register the character device (atleast try)     */     ret_val=register_chrdev(MAJOR_NUM,DEVICE_NAME,&Fops);     /*     * Negative values signify an error     */     if(ret_val<0){         printk("%sfailedwith%d/n",         "Sorry,registeringthecharacterdevice",ret_val);         return ret_val;     }     printk("%sThe major device number is%d./n", "Registerationisasuccess",MAJOR_NUM);     printk("If you want to talk to the device driver,/n");     printk("you'llhavetocreateadevicefile. /n");     printk("We suggest you use:/n");     printk("mknod%s c%d0/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; } void cleanup_module() {     int ret;     /*     * Unregister the device     */     ret=unregister_chrdev(MAJOR_NUM,DEVICE_NAME);     /*     * If there's an error, report it     */     if(ret<0)         printk("Error in module_unregister_chrdev:%d/n",ret); } /* * chardev.h - the header file with the ioctl definitions. * * The declarations here have to be in a header file, because * they need to be known both to the kernel module * (inchardev.c)and the process calling ioctl(ioctl.c) */ #ifndef CHARDEV_H #define CHARDEV_H #include <linux/ioctl.h> /* * The major device number. We can't rely on dynamic * registration any more, because ioctls need to know * it. */ #define MAJOR_NUM 100 /* * Set the message of the device driver */ #define IOCTL_SET_MSG_IOR(MAJOR_NUM,0,char*) /* * _IOR means that we're creating an ioctl command * number for passing information from a user process * to the kernel module. * * The first arguments, MAJOR_NUM, is the major device * number we're using. * * The second argument is the number of the command * (there could be several with different meanings). * * The third argument is the type we want to get from * the process to the kernel. */ /* * Get the message of the device driver */ #define IOCTL_GET_MSG_IOR(MAJOR_NUM,1,char*) /* * This IOCTL is used for output, to get the message * of the device driver. However, we still need the * buffer to place the message in to be input, * as it is allocated by the process. */ /* * Get the n'th byte of the message */ #define IOCTL_GET_NTH_BYTE_IOWR(MAJOR_NUM,2,int) /* * The IOCTL is used for both input and output. It * receives from the user a number, n, and returns * Message[n]. */ /* * The name of the device file */ #define DEVICE_FILE_NAME "char_dev" #endif /* ioctl.c */ #include "chardev.h" #include <fcntl.h> /*open*/ #include <unistd.h> /*exit*/ #include <sys/ioctl.h> /*ioctl*/ ioctl_set_msg(intfile_desc,char*message) {     int ret_val;     ret_val=ioctl(file_desc,IOCTL_SET_MSG,message);     if(ret_val<0){         printf("ioctl_set_msg failed:%d/n",ret_val);         exit(-1);     } } ioctl_get_msg(intfile_desc) {     int ret_val;     char message[100];     /*     * Warning - this is dangerous because wedon't tell     * the kernel how far it's allowed to write, so it     * might overflow the buffer. Inarealproduction     * program, we would have used two ioctls - onetotell     * the kernel the buffer length and another to give     * it the buffer to fill     */     ret_val=ioctl(file_desc,IOCTL_GET_MSG,message);     if(ret_val<0){         printf("ioctl_get_msg failed:%d/n",ret_val);         exit(-1);     }     printf("get_msg message:%s/n",message); } ioctl_get_nth_byte(intfile_desc) {     int i;     char c;         printf("get_nth_bytemessage:");         i = 0;     while(c!=0){         c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);         if(c<0){             printf("ioctl_get_nth_byte failed at the%d'th byte:/n", i);             exit(-1);         }         putchar(c);     }     putchar('/n'); } main() {     int file_desc, ret_val;     char*msg="Message passed by ioctl/n";         file_desc=open(DEVICE_FILE_NAME,0);         if(file_desc<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); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值