记smarthome驱动,包括测试程序

//Environment : ubuntu 10.04

//tool : gcc

//platform : i386 machine

//smarthome.c

// ====================================================
#include<linux/module.h>
#include<linux/init.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/seq_file.h>
#include<linux/proc_fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<asm/io.h>
#include<asm/system.h>
#include<asm/uaccess.h>

#define DEV_ON 1
#define DEV_OFF 0

#define LIGHTNUM 6
#define TVNUM 1
#define AIRCONDNUM 4
#define HUGNUM 10


#define DEV_SUM LIGHTNUM + TVNUM + AIRCONDNUM + HUGNUM


#define MEM_CLEAR 0x01
#define SMARHOMEDEV_MAJOR 0//using dynamic major


static int SmartHomeDevice_major = SMARHOMEDEV_MAJOR;
int SmartHomeDevice_nr_devs =1;

typedef struct _tagSmartHomeDevice{
struct cdev cdev;
        char lightsSwitch[LIGHTNUM];
        char TVSwitch[TVNUM];
        char AirCondSwitch[AIRCONDNUM];
        char Hug[HUGNUM];


}SmartHomeDevice;

SmartHomeDevice *pSmartHomeDev;
static loff_t SmartHomeDevice_llseek(struct file *filp,loff_t offset,int orig);
static void SmartHomeDevice_setup_cdev(SmartHomeDevice *dev,int index);
static ssize_t SmartHomeDevice_read(struct file * flip, char __user* buf,size_t count,loff_t *ppos);
static ssize_t SmartHomeDevice_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos);
static int SmartHomeDevice_ioctl(struct inode *inodep, struct file *filp,unsigned int cmd, unsigned long arg);
static int SmartHomeDevice_open(struct inode *inode, struct file *filp);

static const struct file_operations SmartHomeDevice_fops = {
    .owner = THIS_MODULE,
.open = SmartHomeDevice_open,
    .llseek = SmartHomeDevice_llseek,
    .read = SmartHomeDevice_read,
    .write = SmartHomeDevice_write,
    .ioctl = SmartHomeDevice_ioctl
};

static int SmartHomeDevice_open(struct inode *inode, struct file *filp){
    filp->private_data = pSmartHomeDev;
    return 0;
}

 static int SmartHomeDevice_ioctl(struct inode *inodep, struct file *filp,unsigned int cmd, unsigned long arg){
    //SmartHomeDevice *dev = filp->private_data;

    switch(cmd){
    case MEM_CLEAR:
        //memset(dev->mem,0,GLOBALMEM_SIZE);
        printk(KERN_INFO "SmartHomeDevice is set to zero \n");
    break;
    default: return -EINVAL; 
    }
    return 0;
}

 static void SmartHomeDevice_setup_cdev(SmartHomeDevice* dev , int index){
    int err,devno=MKDEV(SmartHomeDevice_major,index);
    cdev_init(&dev->cdev,&SmartHomeDevice_fops);
    dev->cdev.owner = THIS_MODULE;
    dev->cdev.ops= &SmartHomeDevice_fops;
    err= cdev_add(&dev->cdev,devno,1);
    if(err)
        printk(KERN_NOTICE "ERROR %d adding SmartHomeDevice",err);
}

 static ssize_t SmartHomeDevice_read(struct file * filp, char __user* buf,size_t count,loff_t *ppos){

unsigned long p = *ppos;
    int ret =0;

SmartHomeDevice *dev = filp->private_data;

    if(p >= DEV_SUM) return count? -ENXIO : 0;
    if(p >= DEV_SUM- p){
            count = DEV_SUM-p;
    }
    if(copy_to_user(buf,(void*)(dev->lightsSwitch+ p),count)){
ret= -EFAULT;
}
    else{
        *ppos += count;
        ret = count;
    }
    return ret;
}

 static ssize_t SmartHomeDevice_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos){
unsigned long p = *ppos;
char* pChar= 0;
    int ret = 0 ,i =0;
    SmartHomeDevice *dev = filp->private_data;
if(dev == NULL){
return 0;
}

    if(p >= DEV_SUM){
        return count? -ENXIO :0;
    }
    if(count > DEV_SUM - p){
        count = DEV_SUM - p;
    }

if(copy_from_user(dev->lightsSwitch + p,buf,count)){
        ret = -EFAULT;
    }
    else{
        *ppos =+ count;
        ret = count;
        printk(KERN_INFO "written %d bytes from %ld \n", count ,p);
pChar = dev->lightsSwitch;
for(i=0;((i<count) && (pChar != NULL));i++,pChar++)
{
switch(*pChar){
case DEV_OFF: printk("write OFF data \n");break;
case DEV_ON: printk("write ON data \n");break;
default:  printk("write error data \n"); break;
}
}
     }
return ret;
}

 static loff_t SmartHomeDevice_llseek(struct file *filp,loff_t offset,int orig)
{
    loff_t ret = 0;
    switch(orig)
    {
        case 0:
            if(offset <0 ){
                ret = -EINVAL;
                break;
            }
            if((unsigned int )offset > DEV_SUM){
                ret = - EINVAL;
                break;
            }
            filp->f_pos = (unsigned int)offset;
            ret = filp->f_pos;
        break;


        case 1:
            if((filp->f_pos+ offset) > DEV_SUM){
                ret = -EINVAL;
                break;
            }
            if((filp->f_pos+ offset)<0)
            {
                ret = -EINVAL;
                break;
            }
            filp->f_pos += offset;
            ret = filp->f_pos;
        break;
        default:
            ret = -EINVAL;
        break;
    }
return ret;
}
 int SmartHomeDevice_read_procmem(char *buf, char **start, off_t offset,
                   int count, int *eof, void *data)
 {
//int i, j, len = 0;
//int limit = count - 80; /* Don't print more than this */
//struct SmartHomeDevice_dev *d  = pSmartHomeDev;
//*eof = 1;
return 0;
}
 
 /*
  * Here are our sequence iteration methods.  Our "position" is
  * simply the device number.
  */
 static void *SmartHomeDevice_seq_start(struct seq_file *s, loff_t *pos)
 {
if (*pos >= SmartHomeDevice_nr_devs)
return NULL; /* No more to read */
return pSmartHomeDev + *pos;
 }
 static void *SmartHomeDevice_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (*pos >= SmartHomeDevice_nr_devs)
return NULL;
return pSmartHomeDev + *pos;
}


static void SmartHomeDevice_seq_stop(struct seq_file *s, void *v)
{
/* Actually, there's nothing to do here */
}


static int SmartHomeDevice_seq_show(struct seq_file *s, void *v)
{
//struct SmartHomeDevice_dev *dev = (struct SmartHomeDevice_dev *) v;
//struct SmartHomeDevice_qset *d;
//int i;
//seq_printf(s, "\nDevice %i: qset %i, q %i, sz %li\n",
// 1000, 800,
// 120, 110);
return 0;
}
 /*
   * Tie the sequence operators up.
   */
  static struct seq_operations SmartHomeDevice_seq_ops = {
 .start = SmartHomeDevice_seq_start,
 .next  = SmartHomeDevice_seq_next,
 .stop  = SmartHomeDevice_seq_stop,
 .show  = SmartHomeDevice_seq_show
  };

 /*
  * Now to implement the /proc file we need only make an open
  * method which sets up the sequence operators.
  */
 static int SmartHomeDevice_proc_open(struct inode *inode, struct file *file)
 {
return seq_open(file, &SmartHomeDevice_seq_ops);
 }
 /*
  * Create a set of file operations for our proc file.
  */
 static struct file_operations SmartHomeDevice_proc_ops = {
.owner   = THIS_MODULE,
.open  = SmartHomeDevice_proc_open,
.read  = seq_read,
.llseek  = seq_lseek,
.release = seq_release
 };
 


//===========Create proc file ===========
static void SmartHomeDevice_create_proc(void)
{
struct proc_dir_entry *entry;
entry = create_proc_read_entry("SmartHomeDevice", 0 /* default mode */,
NULL /* parent dir */, SmartHomeDevice_read_procmem,
NULL /* client data */);
if (entry)
entry->proc_fops = &SmartHomeDevice_proc_ops;
}


//================================


int SmartHomeDevice_init(void){
int result;
dev_t devno = MKDEV(SmartHomeDevice_major,0);

if(SmartHomeDevice_major){
result = register_chrdev_region(devno,1,"smarthome");
}
else{
result = alloc_chrdev_region(&devno,0,1,"smarthome");
        SmartHomeDevice_major = MAJOR(devno);
}
    if(result<0){
        return result;
    }
pSmartHomeDev = kmalloc(sizeof(SmartHomeDevice), GFP_KERNEL);
if (!pSmartHomeDev){ 
result = -ENOMEM;
goto fail_malloc;
}
memset(pSmartHomeDev,0,sizeof(SmartHomeDevice));

SmartHomeDevice_setup_cdev(pSmartHomeDev,0);
//SmartHomeDevice_create_proc(); //we don't need proc debug
return 0;


fail_malloc:
unregister_chrdev_region(devno, 1);
    return result;
}


void SmartHomeDevice_exit(void){
    cdev_del(&pSmartHomeDev->cdev);
kfree(pSmartHomeDev);
    unregister_chrdev_region(MKDEV(SmartHomeDevice_major,0),1);
}


MODULE_AUTHOR("NOBODY");
MODULE_LICENSE("GPL");
module_param(SmartHomeDevice_major,int,S_IRUGO);
module_init(SmartHomeDevice_init);
module_exit(SmartHomeDevice_exit);


//================makefile=========================

KERN_DIR := /lib/modules/$(shell uname -r)/build

OBJ := smarthome.o

all:
make -C $(KERN_DIR) M=`pwd` modules 

clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order

obj-m += $(OBJ)


//======================testFile.c==================
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define LIGHTNUM 6
#define TVNUM 1
#define AIRCONDNUM 4
#define HUGNUM 10

#define DEV_SUM LIGHTNUM + TVNUM + AIRCONDNUM + HUGNUM

/*
  *  testfile <dev> <on|off>
  */


void print_usage(char *file)
{
    printf("Usage:\n");
    printf("%s <dev> <device nmae> <number> <on|off>\n",file);
    printf("device name is :light/TV/air-condtion/hug");
    printf("eg. \n");
    printf("%s /dev/smarthome  light 0 on\n", file);
    printf("%s /dev/smarthome  TV 0 on\n", file);
    printf("%s /dev/smarthome  air-condition 0 on\n", file);
    printf("%s /dev/smarthome  hug 0 on\n", file);
}
int main(int argc, char **argv)
{
    int fd;
char* filename;
char lightsSwitch[LIGHTNUM]={0,0,0,0,0,0};
char TVSwitch[TVNUM]={0};
char AirCondSwitch[AIRCONDNUM]={0,0,0,0};
char HugSwitch[HUGNUM]={0,0,0,0,0,0};
int num,i;

    if (argc != 5)
    {
        print_usage(argv[0]);
        return 0;
    }

    filename = argv[1];

    fd = open(filename, O_RDWR);
    if (fd < 0)
    {
        printf("error, can't open %s\n", filename);
        return 0;
    }

    if (!strcmp("light", argv[2]))
    {
        num=atoi(argv[3]);
if(!strcmp("on", argv[4])){
lightsSwitch[num] = 1;
}else lightsSwitch[num] = 0;
for(i=0;i<LIGHTNUM;i++){
printf("lightswtich[%d] = %d  \n " , i , lightsSwitch[i]);
}
        write(fd, lightsSwitch, LIGHTNUM,0);
    }
    else if (!strcmp("TV", argv[2]))
    {
    num=atoi(argv[3]);
       if(!strcmp("on", argv[4])){
TVSwitch[num] = 1;
}else TVSwitch[num] = 0;
        write(fd, TVSwitch, TVNUM,LIGHTNUM);
    }
    else if (!strcmp("air-condition", argv[2]))
    {
        num=atoi(argv[3]);
       if(!strcmp("on", argv[4])){
AirCondSwitch[num] = 1;
}else AirCondSwitch[num] = 0;
        write(fd, AirCondSwitch, AIRCONDNUM,TVNUM+LIGHTNUM);
    }
     else if (!strcmp("hug", argv[2]))
    {
        num=atoi(argv[3]);
        if(!strcmp("on", argv[4])){
HugSwitch[num] = 1;
}else HugSwitch[num] = 0;
        write(fd, HugSwitch, AIRCONDNUM,TVNUM+LIGHTNUM+AIRCONDNUM);
    }
    
    return 0;
}

//====================编译驱动文件============================
$ make
$ sudo insmod smarthome.ko
$ cat /proc/devices
250 smarthome
//创建 dev 节点
$ sudo mknod /dev/smarthome c 250 0
//=====================编译testFile.c============================
$ gcc -c testFile.c
$ gcc -o testFile testFile.o
//============================运行测试程序======================
//使用root权限运行
$ sudo ./testFile /dev/smarthome air-condition 3 on

//==============查看打印信息===================================
/使用root权限
$ cd /var/log
root@ubuntu:/var/log# echo > kern.log 
root@ubuntu:/var/log# cat kern.log 

Oct 15 01:31:58 ubuntu kernel: [27769.446685] written 4 bytes from 0 
Oct 15 01:31:58 ubuntu kernel: [27769.446692] write OFF data  //0
Oct 15 01:31:58 ubuntu kernel: [27769.446694] write OFF data  //1
Oct 15 01:31:58 ubuntu kernel: [27769.446696] write OFF data  //2
Oct 15 01:31:58 ubuntu kernel: [27769.446697] write ON data   //  3 this  is on 

PS:BUG:我们看到写入的位置都是0开始的,所以write的最后一个参数根本没用,写不了指定的位置,于是查看write的原型:
定义函数
 
ssize_t write (int fd,const void * buf,size_t count); 
ssize_t write (int fd,const void * buf,size_t count);
故第四个参数根本没用,在查询,发现还有pwrite的这个函数:原型
ssize_t pwrite(unsigned int fd, const char __user *buf,size_t count, loff_t pos)
我编译出来的ARM版本的是这样子的:
// linux/fs/read_write.c
write:内核实现
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed);
if (file) {
loff_t pos = file_pos_read(file);
ret = vfs_write(file, buf, count, &pos);
file_pos_write(file, pos);
fput_light(file, fput_needed);
}
return ret;
}
pwrite:内核实现
asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
     size_t count, loff_t pos)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
if (pos < 0)
return -EINVAL;
file = fget_light(fd, &fput_needed);
if (file) {
ret = -ESPIPE;
if (file->f_mode & FMODE_PWRITE)  
ret = vfs_write(file, buf, count, &pos);
fput_light(file, fput_needed);
}
return ret;
}


//  linux/include/asm-arm/unistd.h
//系统调用确实这样子调用,这些函数都是有固定位置的
#define __NR_restart_syscall(__NR_SYSCALL_BASE+  0)
#define __NR_exit (__NR_SYSCALL_BASE+  1)
#define __NR_fork (__NR_SYSCALL_BASE+  2)
#define __NR_read (__NR_SYSCALL_BASE+  3)
#define __NR_write (__NR_SYSCALL_BASE+  4)
#define __NR_open (__NR_SYSCALL_BASE+  5)
#define __NR_close (__NR_SYSCALL_BASE+  6)

具体不做讨论!

可以看到pwrite是带文件位置的访问,所以只要把测试代码中的write改为pwrite即可指定四个参数的文件对应位置写入数据了!

编译测试:

root@ubuntu:/home/liqinghan/workspace/smartHome# ./testFile /dev/smarthome air-condition 2 on

root@ubuntu:/home/liqinghan/workspace/smartHome# tail /var/log/kern.log 


Oct 15 20:22:21 ubuntu kernel: [ 6881.225695] written 4 bytes from 7 
Oct 15 20:22:21 ubuntu kernel: [ 6881.225701] write OFF data 
Oct 15 20:22:21 ubuntu kernel: [ 6881.225704] write OFF data 
Oct 15 20:22:21 ubuntu kernel: [ 6881.225705] write ON data 
Oct 15 20:22:21 ubuntu kernel: [ 6881.225707] write OFF data 


//



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

john_liqinghan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值