学习android以来,对于其从上到下的调用接口一直是做些修修补补的工作,为了系统的掌握Android从上到下的调用关系,更好的写好驱动以便为应用所调用,转载并学习了
老罗的Android之旅
的文章,收益颇深,在此表示感谢!
按照老罗的描述,添加kernel中hello设备驱动,编译,仅在hello_create_proc时出现错误,经查看知道owner不是结构proc_dir_entry中的的变量,屏蔽编译ok,代码更改如下:
- /*创建/proc/hello文件*/
- static void hello_create_proc(void) {
- struct proc_dir_entry* entry;
- entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
- if(entry) {
- // entry->owner = THIS_MODULE; //Harvey remove
- entry->read_proc = hello_proc_read;
- entry->write_proc = hello_proc_write;
- }
- }
其余按照说明,验证ok,为了增加理解,自己添加dev/hello的ioctl,代码修改如下:
- /* 定义幻数 */
- #define HELLODEV_IOC_MAGIC 't'
- /* 定义命令 */
- #define HELLODEV_IOCPRINT _IO(HELLODEV_IOC_MAGIC, 1) //没参数
- #define HELLODEV_IOCGETDATA _IOR(HELLODEV_IOC_MAGIC, 2, int) //读
- #define HELLODEV_IOCSETDATA _IOW(HELLODEV_IOC_MAGIC, 3, int) //写
- static int hello_ioctl(struct inode *inode, struct file *fp,unsigned int cmd, unsigned long arg);
- /*设备文件操作方法表*/
- static struct file_operations hello_fops = {
- .owner = THIS_MODULE,
- .open = hello_open,
- .release = hello_release,
- .read = hello_read,
- .write = hello_write,
- .ioctl = hello_ioctl,//harvey add
- };
- static int hello_ioctl(struct inode *inode, struct file *fp,
- unsigned int cmd, unsigned long arg)
- {
- int err = 0;
- int ret = 0;
- struct hello_android_dev* dev;
- void __user *argp = (void __user *)arg;
- /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/
- dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
- /* 检测命令的有效性 */
- if (_IOC_TYPE(cmd) != HELLODEV_IOC_MAGIC)
- return -EINVAL;
- //if (_IOC_NR(cmd) > MEMDEV_IOC_MAXNR)
- // return -EINVAL;
- /* 根据命令类型,检测参数空间是否可以访问 */
- if (_IOC_DIR(cmd) & _IOC_READ)
- err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
- /* 根据命令,执行相应的操作 */
- switch(cmd) {
- /* 打印当前设备信息 */
- case HELLODEV_IOCPRINT:
- printk("<--- CMD MEMDEV_IOCPRINT Done--->\n\n");
- break;
- /* 获取参数 */
- case HELLODEV_IOCGETDATA:
- if(copy_to_user(argp, &(dev->val), sizeof(dev->val)))
- {
- printk("do gpio_ioctl:copy_from_user error!\n");
- ret = -EFAULT;
- }
- else
- {
- printk("<--- CMD Get DATA Done %d--->\n",dev->val);
- }
- break;
- /* 设置参数 */
- case HELLODEV_IOCSETDATA:
- if (copy_from_user(&(dev->val), argp, sizeof(dev->val)))
- {
- printk("do gpio_ioctl:copy_from_user error!\n");
- ret = -EFAULT;
- }
- else
- {
- printk("<--- CMD Set DATA Done %d--->\n",dev->val);
- }
- break;
- default:
- return -EINVAL;
- }
- return ret;
- }
修改external/hello来调用ioctl,验证ok,代码如下:
- /* 定义幻数 */
- #define HELLODEV_IOC_MAGIC 't'
- /* 定义命令 */
- #define HELLODEV_IOCPRINT _IO(HELLODEV_IOC_MAGIC, 1) //没参数
- #define HELLODEV_IOCGETDATA _IOR(HELLODEV_IOC_MAGIC, 2, int) //读
- #define HELLODEV_IOCSETDATA _IOW(HELLODEV_IOC_MAGIC, 3, int) //写
- int main(int argc, char** argv)
- {
- ……
- ioctl(fd,HELLODEV_IOCPRINT);
- printf("Read original value:\n");
- //read(fd, &val, sizeof(val));
- //fread( &val, sizeof(val),1,fd);
- ioctl(fd,HELLODEV_IOCGETDATA,&val);
- printf("%d.\n\n", val);
- val = 5;
- printf("Write value %d to %s \n\n", val, DEVICE_NAME);
- // fwrite(&val, sizeof(val),1,fd);
- ioctl(fd,HELLODEV_IOCSETDATA,&val);
- printf("Read the value again:\n");
- ioctl(fd,HELLODEV_IOCGETDATA,&val);
- ……
- }