平台驱动
模块驱动: 一对多管理,系统管理效率低 加载卸载方便
设备模型:分层分级的管理
4个重要的组成部分:class device driver bus(总线)
层级:kobj-->kset/kobj-->kset-->kset
class:一类相同属性的设备的集合
device:抽象出的设备对象的基类,设备的属性
driver:抽象出的所以驱动的基类,驱动的逻辑
bus(总线):连接设备和驱动的作用
cd /sys/bus/pci/devices/
CPU
--------------------------(总线):匹配设备和驱动
drv0 dev0 dev1 dev2 drv1
最底层的设备有专门的文件描述符为:kobject
不能独立存在,描述设备对象的一个基类,从不独立存在,只是依附在某些设备中
上一级为:kset(但作为被管理时也为 kobject)
再上一级也为:kset
------------------自创:平台总线(platform bus) (plateform device)(plateform driver)
修改设备树
添加设备:
保存编译
//头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
//函数实现
int myinit(struct platform_device *pdev)
{
//获取设备资源
struct resource *res = platform_get_resource(pdev,IORESOURCE_MEM,0);
vaddr = ioremap(res->start,4);
}
int myexit(struct platform_device *pdev)
//注册
//注册
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
{ .compatible = "fs,myled", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif
static struct platform_driver myled_driver = {
.driver = {
.name = "myled",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myled_of_matches),
},
.probe = myinit,
.remove = myexit,
};
module_platform_driver(myled_driver);
//模块信息描述
MODULE_LICENSE("GPL");
驱动程序
/*===============================================
* 文件名称:mod.c
* 创 建 者: memories
* 创建日期:2023年07月06日
* 描 述:have a nice day
================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "cmd.h"
#define MA 300
#define MI 0
static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static int *gpf3con=NULL,*gpf3dat=NULL;
void addr_map(struct platform_device* pdev)
{
struct resource* conres = platform_get_resource(pdev,IORESOURCE_MEM,0);
struct resource* datres = platform_get_resource(pdev,IORESOURCE_MEM,1);
gpf3con = ioremap(conres->start,4);
gpf3dat = ioremap(datres->start,4);
}
void addr_unmap(void)
{
iounmap(gpf3con);
iounmap(gpf3dat);
}
void dev_init(void)
{
writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
printk("led on\n");
writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
printk("led off\n");
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
int myopen(struct inode *pi,struct file *pf)
{
printk("kernel open\n");
return 0;
}
int myrelease(struct inode *pi,struct file *pf)
{
printk("kernel close\n");
return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_to_user(ubuf,mbuf,len);
if(ret != 0)
return -1;
printk("now read\n");
return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_from_user(mbuf,ubuf,len);
if(ret != 0)
return -1;
printk("now write\n");
return len;
}
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_ON:
led_on();
break;
case LED_OFF:
led_off();
break;
};
return 0;
}
static const struct file_operations myfops={
.release = myrelease,
.open = myopen,
.read = myread,
.write = mywrite,
.unlocked_ioctl = myioctl,
};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
int ret = 1;
//up: kernel
//1.registed 把设备对象注册到系统中
no = MKDEV(MA,MI);//组合主次设备号
ret = register_chrdev_region(no,count,name);
if(ret != 0)
{
printk("reg is error\n");
return -1;
}
//2.init 设备初始化,抽象出来一个对象
cdev_init(&mydev,&myfops);
//3.add 添加设备
ret = cdev_add(&mydev,no,count);
if(ret != 0)
{
unregister_chrdev_region(no,count);
return -1;
}
//down:hardware
printk("myinit ok\n");
//1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
printk("121212\n");
addr_map(pdev);
//2.dev init
dev_init();
return 0;
}
static int myexit(struct platform_device* pdev)
{
//和内核相关
cdev_del(&mydev);
unregister_chrdev_region(no,count);
printk("myexit ok\n");
//和硬件相关
//1.解除映射
addr_unmap();
return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
{ .compatible = "fs,myled", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif
static struct platform_driver myled_driver = {
.driver = {
.name = "myled",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myled_of_matches),
},
.probe = myinit,
.remove = myexit,
};
module_platform_driver(myled_driver);
//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");
应用程序
/*===============================================
* 文件名称:mainopen.c
* 创 建 者: memories
* 创建日期:2023年07月06日
* 描 述:have a nice day
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "cmd.h"
int main(int argc, char *argv[])
{
char wbuf[20]="12122122142";
char rbuf[20]={0};
int ret = 0;
int fd = open("/dev/mydev",O_RDWR);
if(fd < 0)
{
printf("open failed fd is %d\n",fd);
return -1;
}
while(1)
{
ioctl(fd,LED_ON);
sleep(1);
ioctl(fd,LED_OFF);
sleep(1);
}
close(fd);
return 0;
}
Linux内存映射
物理内存地址从0x40000000开始
虚拟内存地址从0开始,因为全地址覆盖0~2^32次方
4k称为一个✌页
虚拟地址空间---------------mmu(映射表)--------------物理内存地址
Linux用户空间内存分配
_ malloc()
_ calloc()
_ realloc()
free();
linux内核分配空间
按页分配:_ _get_free_pages()
物理内存空间连续的
_ kmalloc():请求精确字节的内存 32~128k
_ vmalloc():物理内存不一定连续,与kmalloc同
IO与内存访问
1.CPU访问不到寄存器,所以把寄存器映射到内存,让CPU访问
2.CPU访问IO空间,通过端口访问寄存器
{//—mmap 文件映射到内存
//?mmap是什么
mmap是把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等操作。
//?为什么用mmap
{
1. 用mmap替代文件操作(read,write)访问设备,效率高. 它是用户空间访问内核空间的一种高效率方式。
mmap -- 映射文件到虚拟内存
read,write -- copy_to_user 拷贝
对比read write,mmap无需每次都copy_to_user拷贝一次. 它仅需一次映射,以后都直接操作内存buf,效率高。
2. 用共享内存方式,方便进程间通讯,且效率高。
采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,
而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件
}
//mmap原型
{
void* mmap ( void * addr , //指定映射的起始地址, 通常设为NULL, 由系统指定
size_t len , //映射到内存的文件长度
int prot , //映射区的保护方式, PROT_EXEC: 映射区可被执行 PROT_READ: 可读 PROT_WRITE: 可写
int flags , //MAP_SHARED:写入映射区的数据会复制回文件, 且允许其他映射该文件的进程共享。
//MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write), 对此区域所做的修改不会写回原文件。
int fd , //由open返回的文件描述符, 代表要映射的文件
off_t offset //以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射
)
}
{//?mmap 怎么用
#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/mman.h>
int main()
{
int fd;
char *start;
//char buf[PAGE_SIZE];
char *buf;
/*打开文件*/
fd = open("/dev/mydev",O_RDWR);
buf = (char *)malloc(PAGE_SIZE);
memset(buf, 0, PAGE_SIZE);
start=mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
/* 读出数据 */
strcpy(buf,start);
sleep (1);
printf("buf 1 = %s\n",buf);
/* 写入数据 */
strcpy(start,"Buf Is Not Null!");
/* 再次读出数据*/
memset(buf, 0, PAGE_SIZE);
strcpy(buf,start);
sleep (1);
printf("buf 2 = %s\n",buf);
munmap(start,PAGE_SIZE); /*解除映射*/
free(buf);
close(fd);
return 0;
}
}
驱动:
char *kbuf = (char *)kmalloc(PAGE_SIZE, GFP_KERNEL);
int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_IO;//表示对设备IO空间的映射
vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出
if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
vma->vm_start,//虚拟空间的起始地址
virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等
{
return -EAGAIN;
}
return 0;
}
static struct file_operations myops = {
.open = myled_open,
.release = myled_release,
.mmap = myled_mmap
};
}
Linux中断
只需要设置设备树
中断注册到设备里面
申请IRQ:
irq_map(pdev);
irq_unmap();
驱动程序
/*===============================================
* 文件名称:mod.c
* 创 建 者: memories
* 创建日期:2023年07月06日
* 描 述:have a nice day
================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "cmd.h"
#define MA 300
#define MI 0
static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static char *kbuf;
struct resource* irqres = NULL;
irqreturn_t handler(int irqno,void *arg)
{
printk("okokok\n");
return IRQ_HANDLED;
}
int irq_map(struct platform_device* pdev)
{
struct resource* irqres = platform_get_resource(pdev,IORESOURCE_IRQ,0);
int ret = request_irq(irqres->start,handler,irqres->flags,"myirq",NULL);
if(ret != 0)
return ret;
return 0;
}
void irq_unmap(void)
{
free_irq(irqres->start,NULL);
}
/*
void dev_init(void)
{
writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
printk("led on\n");
writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
printk("led off\n");
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
*/
int myopen(struct inode *pi,struct file *pf)
{
return 0;
}
int myrelease(struct inode *pi,struct file *pf)
{
return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_to_user(ubuf,mbuf,len);
if(ret != 0)
return -1;
printk("now read\n");
return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_from_user(mbuf,ubuf,len);
if(ret != 0)
return -1;
printk("now write\n");
return len;
}
/*
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_ON:
led_on();
break;
case LED_OFF:
led_off();
break;
};
return 0;
}
*/
int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_IO;//表示对设备IO空间的映射
vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出
if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
vma->vm_start,//虚拟空间的起始地址
virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等
{
return -EAGAIN;
}
return 0;
}
static const struct file_operations myfops={
.release = myrelease,
.open = myopen,
.read = myread,
.write = mywrite,
// .unlocked_ioctl = myioctl,
// .mmap = myled_mmap,
};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
int ret = 1;
kbuf = (char *)kmalloc(32, GFP_KERNEL);
//up: kernel
//1.registed 把设备对象注册到系统中
no = MKDEV(MA,MI);//组合主次设备号
ret = register_chrdev_region(no,count,name);
if(ret != 0)
{
printk("reg is error\n");
return -1;
}
//2.init 设备初始化,抽象出来一个对象
cdev_init(&mydev,&myfops);
//3.add 添加设备
ret = cdev_add(&mydev,no,count);
if(ret != 0)
{
unregister_chrdev_region(no,count);
return -1;
}
//down:hardware
printk("myinit ok\n");
//1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
printk("121212\n");
irq_map(pdev);
//2.dev init
// dev_init();
return 0;
}
static int myexit(struct platform_device* pdev)
{
//和内核相关
cdev_del(&mydev);
unregister_chrdev_region(no,count);
printk("myexit ok\n");
//和硬件相关
//1.解除映射
irq_unmap();
return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
{ .compatible = "fs,mykey", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif
static struct platform_driver myled_driver = {
.driver = {
.name = "mykey",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myled_of_matches),
},
.probe = myinit,
.remove = myexit,
};
module_platform_driver(myled_driver);
//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");
利用按键中断,完成开关灯操作
exynos4412-fs4412---------------> key2 ------------->LED5
驱动程序
/*===============================================
* 文件名称:mod.c
* 创 建 者: memories
* 创建日期:2023年07月06日
* 描 述:have a nice day
================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "cmd.h"
#define MA 301
#define MI 0
static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;
static char mbuf[32]={0};
static char *kbuf;
struct resource* irqres = NULL;
static int flag = 0;
irqreturn_t handler(int irqno,void *arg)
{
int ret = 0;
printk("okokok\n");
if(flag == 0)
{
ret = copy_from_user(mbuf,"on",32);
printk("mbuf= %s\n",mbuf);
if(ret != 0)
return -1;
flag = 1;
}
else
{
ret = copy_from_user(mbuf,"of",32);
printk("mbuf= %s\n",mbuf);
if(ret != 0)
return -1;
flag = 0;
}
return IRQ_HANDLED;
}
int irq_map(struct platform_device* pdev)
{
struct resource* irqres = platform_get_resource(pdev,IORESOURCE_IRQ,0);
int ret = request_irq(irqres->start,handler,irqres->flags,"myirq",NULL);
if(ret != 0)
return ret;
return 0;
}
void irq_unmap(void)
{
free_irq(irqres->start,NULL);
}
/*
void dev_init(void)
{
writel(((readl(gpf3con)) & ~(0xf<<20)) | (0x1<<20),gpf3con);
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
void led_on(void)
{
printk("led on\n");
writel(readl(gpf3dat)|(0x1<<5),gpf3dat);
}
void led_off(void)
{
printk("led off\n");
writel(readl(gpf3dat)&~(0x1<<5),gpf3dat);
}
*/
int myopen(struct inode *pi,struct file *pf)
{
return 0;
}
int myrelease(struct inode *pi,struct file *pf)
{
return 0;
}
ssize_t myread (struct file *pf, char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_to_user(ubuf,mbuf,len);
printk("qudong read\n");
if(ret != 0)
return -1;
printk("now read\n");
return len;
}
ssize_t mywrite (struct file *pf, const char __user *ubuf, size_t len, loff_t *poff)
{
int ret = 0;
ret = copy_from_user(mbuf,ubuf,len);
if(ret != 0)
return -1;
printk("now write\n");
return len;
}
/*
long myioctl (struct file *pf, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_ON:
led_on();
break;
case LED_OFF:
led_off();
break;
};
return 0;
}
*/
int myled_mmap(struct file *pf, struct vm_area_struct *vma)
{
vma->vm_flags |= VM_IO;//表示对设备IO空间的映射
vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出
if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
vma->vm_start,//虚拟空间的起始地址
virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位
vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍
vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等
{
return -EAGAIN;
}
return 0;
}
static const struct file_operations myfops={
.release = myrelease,
.open = myopen,
.read = myread,
.write = mywrite,
// .unlocked_ioctl = myioctl,
// .mmap = myled_mmap,
};//文件操作集
//2.init/exit fun
static int myinit(struct platform_device* pdev)
{
int ret = 1;
kbuf = (char *)kmalloc(32, GFP_KERNEL);
//up: kernel
//1.registed 把设备对象注册到系统中
no = MKDEV(MA,MI);//组合主次设备号
ret = register_chrdev_region(no,count,name);
if(ret != 0)
{
printk("reg is error\n");
return -1;
}
//2.init 设备初始化,抽象出来一个对象
cdev_init(&mydev,&myfops);
//3.add 添加设备
ret = cdev_add(&mydev,no,count);
if(ret != 0)
{
unregister_chrdev_region(no,count);
return -1;
}
//down:hardware
printk("myinit ok\n");
//1.映射,内核的物理地址转换为虚拟地址paddr-->vaddr
printk("121212\n");
irq_map(pdev);
//2.dev init
// dev_init();
return 0;
}
static int myexit(struct platform_device* pdev)
{
//和内核相关
cdev_del(&mydev);
unregister_chrdev_region(no,count);
printk("myexit ok\n");
//和硬件相关
//1.解除映射
irq_unmap();
return 0 ;
}
//3.reg kernel
#ifdef CONFIG_OF
static const struct of_device_id myled_of_matches[] = {
{ .compatible = "fs,mykey", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, myled_of_matches);
#endif
static struct platform_driver myled_driver = {
.driver = {
.name = "mykey",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(myled_of_matches),
},
.probe = myinit,
.remove = myexit,
};
module_platform_driver(myled_driver);
//模块信息描述
//4.mod info
MODULE_LICENSE("GPL");
应用程序
/*===============================================
* 文件名称:mainopen.c
* 创 建 者: memories
* 创建日期:2023年07月06日
* 描 述:have a nice day
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include "cmd.h"
int main(int argc, char *argv[])
{
char *start;
char wbuf[20]="12122122142";
char rbuf[32]={0};
int ret = 0;
int fd1 = 0;
int fd = open("/dev/mydev",O_RDWR);
if(fd < 0)
{
printf("open failed fd is %d\n",fd);
return -1;
}
while(1)
{
printf("yingyong\n");
sleep(1);
ret = read(fd,rbuf,32);
if(ret < 0)
{
perror("read");
return -1;
}
printf("rbuf=%s\n",rbuf);
if(strncmp(rbuf,"on",2) == 0)
{
int fd1 = open("/dev/mydev1",O_RDWR);
if(fd1 < 0)
{
printf("open failed fd1 is %d\n",fd1);
break;
}
printf("open led\n");
ioctl(fd1,LED_ON);
}
else if(strncmp(rbuf,"of",2) == 0)
{
int fd1 = open("/dev/mydev1",O_RDWR);
if(fd1 < 0)
{
printf("open failed fd1 is %d\n",fd1);
break;
}
printf("close led\n");
ioctl(fd1,LED_OFF);
}
memset(rbuf,0,32);
}
close(fd);
close(fd1);
return 0;
}
return -1;
}
while(1)
{
printf("yingyong\n");
sleep(1);
ret = read(fd,rbuf,32);
if(ret < 0)
{
perror("read");
return -1;
}
printf("rbuf=%s\n",rbuf);
if(strncmp(rbuf,"on",2) == 0)
{
int fd1 = open("/dev/mydev1",O_RDWR);
if(fd1 < 0)
{
printf("open failed fd1 is %d\n",fd1);
break;
}
printf("open led\n");
ioctl(fd1,LED_ON);
}
else if(strncmp(rbuf,"of",2) == 0)
{
int fd1 = open("/dev/mydev1",O_RDWR);
if(fd1 < 0)
{
printf("open failed fd1 is %d\n",fd1);
break;
}
printf("close led\n");
ioctl(fd1,LED_OFF);
}
memset(rbuf,0,32);
}
close(fd);
close(fd1);
return 0;
}