JZ2440开发板之LED支持lseek

驱动

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

#define DEVICENAME "myled"
#define gpfcon_addr 0x56000050
#define gpfdat_addr 0x56000054

static unsigned int major=0;
static struct class *myclass=NULL;
static struct class_device  *mydev;

static volatile unsigned long *gpfcon=NULL;
static volatile unsigned long *gpfdat=NULL;

#define GPFCON *gpfcon
#define GPFDAT *gpfdat

#define LED_NUM 3

static int my_dev_open(struct inode *inode, struct file *file)
{
    //配置LED管脚模式
    GPFCON &=~( (3<<8)|(3<<10)|(3<<12) );
    GPFCON |= ((1<<8) | (1<<10) | (1<<12));

    //默认灯全部关闭
    GPFDAT |= ((7<<4));
    return 0;
}

//自定义read 支持lseek
static ssize_t my_dev_read (struct file *pfile, char __user *buf, size_t count, loff_t *ppos)
{
    loff_t cur_pos =*ppos;
    unsigned char i=0,ledbuf[10];

    //读取数量小于0直接返回
    if(count<0)
        return 0;

    //当前位置超过了可读数量直接返回
    if(cur_pos>=LED_NUM)
        return 0;

    //如果当前位置加上读取数量超过可读取的数量,只能读取有效的数量
    if(cur_pos+count>LED_NUM)
        count=LED_NUM-cur_pos;

    //读取每个灯的状态
    for(i=0;i<LED_NUM;i++)
    {
        if(GPFDAT &(1<<(i+4)))
            ledbuf[i]='1';
        else
            ledbuf[i]='0';
    }
    copy_to_user(buf,&ledbuf[cur_pos],count);   //拷贝指定位置指定数量的数据

    *ppos+=count;      //重新定义当前位置
    return count;
}

static ssize_t my_dev_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    loff_t cur_pos =*ppos;
    unsigned char i=0,ledbuf[10];

    //读取数量小于0直接返回
    if(count<0)
        return 0;

    //当前位置超过了可读数量直接返回
    if(cur_pos>=LED_NUM)
        return 0;

    //如果当前位置加上读取数量超过可读取的数量,只能读取有效的数量
    if(cur_pos+count>LED_NUM)
        count=LED_NUM-cur_pos;

    copy_from_user(&ledbuf[cur_pos], buf,count);
    for(i=0;i<count;i++)
    {
        if(ledbuf[i+cur_pos]=='0')
            GPFDAT &= ~(1<<(i+3+cur_pos));
        else
            GPFDAT |=  (1<<(i+3+cur_pos));
    }

    *ppos+=count;
    return count;
}

//自定义LSEEK
static loff_t my_dev_llseek (struct file *pfile, loff_t loft, int whence)
{
    loff_t tmp;
    switch(whence)
    {
        case SEEK_SET: 
            tmp=loft;
            break;
        case SEEK_CUR:
            tmp=pfile->f_pos+loft;
            break;
        case SEEK_END: 
            tmp=LED_NUM+loft;
            break;
        default:
            return -EINVAL;
            break;
    }
    if(tmp<0 || tmp>LED_NUM)
        return -EINVAL;

    pfile->f_pos = tmp;
    return tmp;
}


static struct file_operations my_dev_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   my_dev_open,     
    .write  =   my_dev_write,
    .read   =   my_dev_read,
    .llseek  =   my_dev_llseek,
};



static int my_dev_init(void)
{

    major = register_chrdev(0,DEVICENAME, &my_dev_fops); // 注册, 告诉内核
    myclass = class_create(THIS_MODULE,DEVICENAME);
    mydev=class_device_create(myclass, NULL, MKDEV(major,0), NULL, "led");

    //地址映射
    gpfcon=(volatile unsigned long *)ioremap(gpfcon_addr,4);
    gpfdat=(volatile unsigned long *)ioremap(gpfdat_addr,4);

    printk("led is init...\n");
    return 0;
}

static void my_dev_exit(void)
{
    iounmap(gpfcon);
    iounmap(gpfdat);

    class_device_unregister(mydev);
    class_destroy(myclass);
    unregister_chrdev(major, DEVICENAME); // 卸载
    printk("led is exit\n");
}

module_init(my_dev_init);
module_exit(my_dev_exit);
MODULE_LICENSE("GPL");

app

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>

int main()
{
    unsigned char rdbuf[4]={"0000"},wrbuf[3]={"110"};
    int fd,tmp=0;
    char tmp1='0',tmp2;
    fd = open("/dev/led",O_RDWR);
    if(fd<0)
        printf("led open is fail\n");
    else
        printf("led open success\n");
    lseek(fd,2,SEEK_SET);
    write(fd,&tmp1,1);

    lseek(fd,0,SEEK_SET);
    read(fd,rdbuf,3);
    printf("buf is %s\n",rdbuf);
    while(1)
    {
        sleep(2);
        close(fd);
        return 0;
    }

}

效果

[root@JZ2440 002led]# insmod led.ko
led is init...
[root@JZ2440 002led]# ./app
led open success
buf is 0110
[root@JZ2440 002led]# ./app
led open success
buf is 1010
[root@JZ2440 002led]# ./app
led open success
buf is 1100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值