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`
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮