linux驱动按键控制led灯

2019-07-13 09:03发布

IO端口操作

1.基本概念
机器的组成:
.处理器
.总线
.IO外设

2.IO映射及使用
1)申请IO

struct resource *request_mem_region(resource_size_t start,resource_size_t n,const char *name)
void release_mem_region(resource_size_t start,resource_size_t n)

2)映射IO

void __iomem *ioremap(unsigned long phys_addr,size_t size)
void  iounmap(void __iomem);

3)使用端口
int ioread32(void __iomem *)
iowrite32(value,void __iomem *) 实例: driver.c #include #include #include #include #include #include #include #include "myioctl.h" #include #include struct resource *ptr = NULL; unsigned long *gpj2con = NULL; //led unsigned long *gph2con = NULL; //key static dev_t dev_num=0; static struct cdev *cdev_p; int led_open(struct inode *inode,struct file *file) { printk("led kernel open func init "); // led init int val; val = ioread32(gpj2con); val &=~(0xF<<0); val |=(0x1<<0); iowrite32(val,gpj2con); val = ioread32(gpj2con+1); val |=(0x1<<0); iowrite32(val,gpj2con+1); // key init val = ioread32(gph2con); val &=~(0xf<<0); iowrite32(val,gph2con); return 0; } int led_close(struct inode *inode,struct file *file) { printk("led kernel close func init "); return 0; } char kbuf[100]; ssize_t led_write(struct file *file, char __user *buf, size_t count, loff_t *offset) { //memcpy(kbuf,buf,count); if(copy_from_user(kbuf,buf,count)) { printk("copy data form user fail "); return -EFAULT; } return 0; } //获取key值 ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { int kbuf = (*(gph2con + 1) & (0x1)); printk("gph2dat[0] = %d ",kbuf); if(copy_to_user(buf,&kbuf,count)) { printk("copy data to user fail "); return -EFAULT; } return 0; } int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { printk("cmd=%d;arg=%d ",cmd,arg); if (_IOC_NR(cmd)>=MAGIC_MAX) return -1; if (_IOC_TYPE(cmd)!=TYPE) return -1; int val; switch(_IOC_NR(cmd)) { case 0: printk("led on "); //*(vaddr + 1) &=~(0x1<<0); val = ioread32(gpj2con+1); val &=~(0x1<<0); iowrite32(val,gpj2con+1); break; case 1: printk("led off "); //*(vaddr + 1) |=(0x1<<0); val = ioread32(gpj2con+1); val |=(0x1<<0); iowrite32(val,gpj2con+1); break; case 2: //led on or off val = ioread32(gpj2con+1); val ^= (0x1<<0); iowrite32(val,gpj2con+1); break; } return 0; } struct file_operations led_fops={ .owner=THIS_MODULE, .open = led_open, .release = led_close, .write = led_write, .read = led_read, .ioctl = led_ioctl, }; int __init led_init(){ printk("led init "); int ret; ret = alloc_chrdev_region(&dev_num,0,1,"led-xx"); if (ret < 0) { printk("chrdev num fail "); return -1; } printk("dev num=%d ; major = %d ; minor = %d ;",dev_num,MAJOR(dev_num),MINOR(dev_num)); cdev_p = cdev_alloc(); cdev_init(cdev_p,&led_fops); ret = cdev_add( cdev_p,dev_num,1 ); if (ret) { printk("cdev add fail "); return -1; } //申请io端口,请求分配指定的I/O内存资源。led-xx可以改? ptr = request_mem_region(0xe0200280,0x1000,"led-xx"); if (ptr == NULL) { printk("request_mem_region fail "); return -1; } //映射io gpj2con = (unsigned long *)ioremap(0xe0200280,0x1000); if (gpj2con == NULL) { printk("ioremap fail "); return -1; } //这里不用申请io? gph2con = (unsigned long *)ioremap(0xe0200c40,0x1000); if (gph2con == NULL) { printk("ioremap fail "); return -1; } return 0; } void __exit led_exit(){ iounmap(gpj2con); iounmap(gph2con); release_mem_region(0xe0200280,0x1000); release_mem_region(0xe0200c40,0x1000); cdev_del(cdev_p); unregister_chrdev_region(dev_num,1); printk("led exit "); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("LEDxx"); MODULE_AUTHOR("XX"); MODULE_DESCRIPTION("xx test"); myioctl.h #define LED_NUM1 1 #define LED_NUM2 2 #define STEP_MOTO 3 #define MOTO_ON 0 #define MOTO_OFF 1 #define TYPE 'K' #define MAGIC_MAX 3 #define LED_ON _IO(TYPE,0) #define LED_OFF _IO(TYPE,1) #define LED_EOR _IO(TYPE,2) app.c #include #include #include #include #include #include "myioctl.h" int key_val; int main(int argc,char **argv) { int fd = open("/dev/xxled",O_RDWR); if(fd < 0) { printf("open fail "); return -1; } while(1) { //循环read读取key的值 read(fd,&key_val,4);//读4个字节,32位 if(key_val == 0) { // 按下去抖 do{ usleep(100000); read(fd,&key_val,4); }while(key_val == 0); //读取到按下就ioctl修改led灯状态 ioctl(fd,LED_EOR); } //300毫秒读一次 usleep(300000); } close(fd); return 0; }
makefile obj-m += led.o KERNEL_DIR := /usr/mkdrv/src/android-kernel-samsung-dev all: make modules -C $(KERNEL_DIR) M=`pwd` arm-linux-gcc app.c -o app cp led.ko app /nfs make clean clean: make modules clean -C $(KERNEL_DIR) M=`pwd`