分类: 嵌入式
2010-08-07 22:47:45
scull.h
/* * scull.h -- definitions for the char module * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files. The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates. No warranty is attached; * we cannot take responsibility for errors or fitness for use. * * $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $ */ #ifndef _SCULL_H_ #define _SCULL_H_ #include #define SCULL_DEBUG //定义调试的宏,将会在proc目录下创建文件 /* * Macros to help debugging */ #undef PDEBUG /* undef it, just in case */ #ifdef SCULL_DEBUG # ifdef __KERNEL__ /* This one if debugging is on, and kernel space */ # define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args) # else /* This one for user space */ # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args) # endif #else # define PDEBUG(fmt, args...) /* not debugging: nothing */ #endif #undef PDEBUGG #define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */ #ifndef SCULL_MAJOR #define SCULL_MAJOR 0 /* 该变量为0,将会动态分配设备编号*/ #endif #ifndef SCULL_NR_DEVS #define SCULL_NR_DEVS 4 /*将会这侧四个设备scull0到scull3 */ #endif #ifndef SCULL_P_NR_DEVS #define SCULL_P_NR_DEVS 4 /* scullpipe0 through scullpipe3 */ #endif /* * The bare device is a variable-length region of memory. * Use a linked list of indirect blocks. * * "scull_dev->data" points to an array of pointers, each * pointer refers to a memory area of SCULL_QUANTUM bytes. * * The array (quantum-set) is SCULL_QSET long. */ #ifndef SCULL_QUANTUM #define SCULL_QUANTUM 4000 //量子大小 #endif #ifndef SCULL_QSET #define SCULL_QSET 1000 //数组大小 #endif /* * The pipe device is a simple circular buffer. Here its default size */ #ifndef SCULL_P_BUFFER #define SCULL_P_BUFFER 4000 #endif /* * Representation of scull quantum sets. */ struct scull_qset { void **data; struct scull_qset *next; }; struct scull_dev { struct scull_qset *data; /* 指向第一个量子集的指针 */ int quantum; /*当前量子大小*/ int qset; /*当前数组大小*/ unsigned long size; /*保存在其中的数据总量*/ unsigned int access_key; /* 由sculluid和scullpriv使用 */ struct semaphore sem; /* 互斥信号量*/ struct cdev cdev; /*字符设备结构*/ }; /* * */ #define TYPE(minor) (((minor) >> 4) & 0xf) /* high nibble */ #define NUM(minor) ((minor) & 0xf) /* low nibble */ /* * The different configurable parameters */ extern int scull_major; /* main.c */ extern int scull_nr_devs; extern int scull_quantum; extern int scull_qset; extern int scull_p_buffer; /* pipe.c */ /* * Prototypes for shared functions */ int scull_p_init(dev_t dev); void scull_p_cleanup(void); int scull_access_init(dev_t dev); void scull_access_cleanup(void); int scull_trim(struct scull_dev *dev); ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); loff_t scull_llseek(struct file *filp, loff_t off, int whence); int scull_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); /* * Ioctl definitions */ /* 使用‘k’作为幻数*/ #define SCULL_IOC_MAGIC 'k' /* Please use a different 8-bit number in your code */ #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0) /* * S 通过指针设置(set) * T 表示直接用参数值通知(tell) * G 表示获取(get):通过设置指针来应答 * Q表示查询(query),通过返回值应答 * X 表示交换(exchange):原子的交换G和S * H 表示切换(shift):原子地交换T和Q */ #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int) #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int) #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3) #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4) #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int) #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int) #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7) #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8) #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int) #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int) #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11) #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12) /* * The other entities only have "Tell" and "Query", because they're * not printed in the book, and there's no need to have all six. * (The previous stuff was only there to show different ways to do it. */ #define SCULL_P_IOCTSIZE _IO(SCULL_IOC_MAGIC, 13) #define SCULL_P_IOCQSIZE _IO(SCULL_IOC_MAGIC, 14) /* ... more to come */ #define SCULL_IOC_MAXNR 14 #endif /* _SCULL_H_ */ |
container_of介绍
container_of的定义在内核的include/linux/kernel.h文件中:
/** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) |
它的作用那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。
当我们成功insmod了一个设备驱动的时候,当我们使用mknod创建一个与驱动对应的设备文件节点,这个设备文件节点所对应的就是struct inode结构体的一个实例,这个结构体有一个字段i_cdev,是个struct cdev类型的指针,它会指向设备结构体的cdev字段,使用container_of就可以获得指向struct scull_dev结构体的指针,即整个结构体的指针。
当一个设备驱动对应多个设备(子设备)时,你就知道container_of发挥的作用了!当你针对每一个设备调用open时,因为每个设备对应的设备文件节点不一样,那么根据该节点的i_cdev字段所计算的设备结构体指针也不一样,你就可以找到特定节点所对应的设备结构体!而不至于对不同的子设备编写 大同小异的各自的设备驱动。scull驱动程序就是这样的一个例子。
ioctl命令参数说明
Linux下使用ioctl时会选择分配不同命令的编号,并非是任意指定0、1…的数值,直接使用0、1…等命令编号作为ioctl参数将会无意间的产生意想不到的结果。为安全起见,我们应遵循Linux内核的约定方法来选择ioctl号,首先应阅读内核目录下的Documentation/ioctl-number.txt文档和include/asm/ioctl.h头文件,该头文件定义了要使用的位字段(幻数)、序数、传送方向以及参数大小等。ioctl-number.txt文件中罗列了内核所使用的幻数,这样选择自己的幻数时就可以避免和内核冲突。
还是在scull的基础之上做个实验吧。
scull_test.c #include #include #include #include #include #define DEVICE_NUM 4 int main() { int i,j,ret,fd[DEVICE_NUM]; char str_name[10]; char read_buf[10]; char write_buf[10]={1,2,3,4,5,6,7,8,9,10}; for(i=0;i { sprintf(str_name,"/dev/scull%d",i); printf("open %s\n",str_name); fd[i] = open(str_name,O_WRONLY); if(fd[i] <= 0) { printf("Do not exit the device,can't open\n"); return -1; } ret = write(fd[i],write_buf,10); if(ret <= 0) printf("wirte error!\n"); else { printf("scull%d:write %d data to scull!\n",i,ret); for(j = 0;j printf("write_buf[%d]=%d ",j,write_buf[j]); printf("\n"); } close(fd[i]); sprintf(str_name,"/dev/scull%d",i); printf("open %s\n",str_name); fd[i] = open(str_name,O_RDONLY); if(fd[i] <= 0) { printf("Do not exit the device,can't open\n"); return -1; } ret = read(fd[i],read_buf,10); if(ret <= 0) printf("read data error from scull\n"); else { printf("scull%d:read %d data from read_buf ok\n",i,ret); for(j = 0;j printf("read_buf[%d]=%d ",j,read_buf[j]); printf("\n"); } close(fd[i]); } exit(0); } Makefile: OBJS = scull_test CROSS_COMPILE = arm-linux- CC = $(CROSS_COMPILE)gcc .PHONY:module module: $(CC) -o $(OBJS) $(OBJS).c .PHONY:clean clean: rm -rf *~ *.o $(OBJS) |