【Linux Device Driver】—(3.1)—ioctl——代码

《Linux Device Driver》这本书的却做的很好,对于一个初学者来说虽然有点难度,但是只要认真看,绝对是大有裨益的!

好了,昨天把ioctl的原理以及涉及到的代码贴了一下,今天就做了做实验,感觉还凑合,所以就贴出来!对自己也算是做个笔记吧!

今天这个实验主要就是通过ioctl来控制LED灯的亮灭,虽然有点简单,但是毕竟也是需要花费点时间的。

1、驱动程序①、tiny6410_led_ioctl.c

#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <asm/io.h>#include <linux/miscdevice.h>#include <linux/device.h>#include <linux/cdev.h>#include <linux/ioctl.h>#include "tiny6410_led_ioctl.h"MODULE_LICENSE("GPL");static struct cdev cdev;static dev_t devno;struct class *tiny6410_class;static int major;volatile unsigned long *gpkcon0 = NULL;volatile unsigned long *gpkcon1 = NULL;volatile unsigned long *gpkdat = NULL;int led_open(struct inode *inode, struct file *filp){/* LED1 - 4 分别对应GPK4 -7 *//* 设置LED 引脚为输出引脚 */*gpkcon0 &= (((0x1) << (4*4)) | ((0x1) << (5*4)) | ((0x1) << (6*4)) | ((0x1) << (7*4)));/* 对应管脚置高,使LED 全灭 */*gpkdat |= 0xf0;return 0;}static ssize_t led_write(struct file *filp, char __user *buf, size_t size, loff_t *ppos){/* LED 全部熄灭或者全部打开 */int val;copy_from_user(&val, buf, size);/* 点灯 */if(val == 1) {*gpkdat &= ~((1<<4) | (1<<5) | (1<<6) | (1<<7));}/* 灭灯 */else {*gpkdat |= ((1<<4) | (1<<5) | (1<<6) | (1<<7));}}static unsigned long led_getdat(void){return ((*gpkdat >> 4)&0x0f);}static void led_setdat(int dat){*gpkdat = (*gpkdat & ~(0xf<<4)) |((dat&0xf) << 4);}int led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){int err = 0;int ret = 0;int ioarg = 0;/* 检测命令的有效性 */if(_IOC_TYPE(cmd) != LED_IOCTL_MAGIC)return -EINVAL;if(_IOC_NR(cmd) >= LED_IOCTL_MAXNR)return -EINVAL;/* 根据命令类型,检测空间是否可以访问,当然有的函数可以省去此步骤。如copy_to_user,下面的就是应用到了,这里为了以后参照,所以也写上了 */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 LED_IOCTL_IOPRINT:printk("<---CMD LED_IOCTL DONE--->\n");break;/* 获取当前LED 灯的显值 */case LED_IOCTL_IOGETDAT:ioarg = led_getdat();ret = put_user(ioarg, (int *)arg);printk("[Call LED_IOCTL_IOGETDAT!]");break;/* 设置当前LED 灯 */case LED_IOCTL_IOSETDAT:ret = get_user(ioarg, (int *)arg);led_setdat(ioarg);break;default:return -EINVAL;}return ret;}static const struct file_operations led_fops ={.open  = led_open,.write  = led_write,.owner = THIS_MODULE,.unlocked_ioctl = led_ioctl,};static void tiny6410_led_pin_setup(void){gpkcon0 = (volatile unsigned long *)ioremap(0x7F008800, 16);gpkcon1 = gpkcon0 + 1;gpkdat = gpkcon0 + 2;}static void tiny6410_led_pin_release(void){iounmap(gpkcon0);iounmap(gpkcon1);iounmap(gpkdat);}static int __init led_init(void){/*alloc_chrdev_region(&devno, 0, 1, "tiny6410_led");major = MAJOR(devno);*/major = 255;devno = MKDEV(major, 0);register_chrdev_region(devno, 1, "tiny6410_led_ioctl");/* 初始化cdev 结构 */cdev_init(&cdev,&led_fops);cdev.owner = THIS_MODULE;/* 注册字符设备 */cdev_add(&cdev, devno,1);tiny6410_class = class_create(THIS_MODULE, "led_class");device_create(tiny6410_class, NULL, MKDEV(major, 0), NULL, "tiny6410_led_ioctl"); tiny6410_led_pin_setup();return 0;}static void __exit led_exit(void){tiny6410_led_pin_release();device_destroy(tiny6410_class, MKDEV(major, 0));class_destroy(tiny6410_class);cdev_del(&cdev);unregister_chrdev_region(devno, 1);}module_init(led_init);module_exit(led_exit);

②、tiny6410_led_ioctl.h

#ifndef _LED_H_#define _LED_H_#include <linux/ioctl.h>/* 定义幻数 */#define LED_IOCTL_MAGIC 'k'/* 定义命令 */#define LED_IOCTL_IOPRINT_IO(LED_IOCTL_MAGIC, 1)#define LED_IOCTL_IOGETDAT_IOR(LED_IOCTL_MAGIC, 2, int)#define LED_IOCTL_IOSETDAT_IOW(LED_IOCTL_MAGIC, 3, int)/* 命令总数 */#define LED_IOCTL_MAXNR 3#endif

2、测试程序①、tiny6410_led_ioctl_app.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "tiny6410_led_ioctl.h"#define DEVICE_NAME"/dev/tiny6410_led_ioctl"int binstr_to_int(char *binstr){int ret = 0;int i = 0;char bnum[5];memset(bnum,'0',4);int len = strlen(binstr);if(len > 4)strcpy(bnum,binstr + len - 4);elsestrcpy(bnum + 4 - len,binstr);for(i = 0;i < 4;i ++){ret <<= 1;ret += (bnum[i] == '0' ? 1 : 0);}return ret;}int main(int argc,char **argv){if(argc > 2){printf("Usage: %s <binary code>\n""example: %s 1001 -- Will turn on led 0 and 3, and turn off led 1 and 2.\n",argv[0],argv[0]);_exit(EXIT_FAILURE);}int fd,arg;if((fd = open(DEVICE_NAME,O_RDWR)) == -1){printf("Open dev error!\n");_exit(EXIT_FAILURE);}if(argc == 1){ioctl(fd,LED_IOCTL_IOGETDAT,&arg);printf("led dat: %d.\n",arg);}else{arg = binstr_to_int(argv[1]);printf("arg = %d.\n",arg);ioctl(fd,LED_IOCTL_IOSETDAT,&arg);}_exit(EXIT_SUCCESS);}

3、测试结果

害怕攀登高峰的人,永远在山下徘徊。

【Linux Device Driver】—(3.1)—ioctl——代码

相关文章:

你感兴趣的文章:

标签云: