Embedded 版 (精华区)

发信人: Zinux (Linux技工), 信区: Embedded_system
标  题: 驱动程序
发信站: 哈工大紫丁香 (2001年10月26日18:43:34 星期五), 站内信件


发信人: clown (梧桐叶), 信区: UKP
标  题: 驱动程序
发信站: UNIX编程 (2001年10月26日11:31:00 星期五), 站内信件

//dev.c

//the driver of the virtual character device /dev/vir_chr_dev
#define MODULE
#define __KERNEL__
//#define EXPORT_SYMTAB
#define __NO_VERSION__

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include <linux/errno.h>
#include <asm/uaccess.h>


#define DEV_MAJOR 61
#define DEV_MINOR 0
#define DEV_NAME "vir_chr_dev"
//#mknod /dev/vir_chr_dev c 61 0

static int read_busy;
static int write_busy;

#define MAX_SIZE 32
struct vir_buf {
    int size;
    char buf[MAX_SIZE];
    struct vir_buf *next;
};
extern struct vir_buf *rd_head, *wr_head;

//static DECLARE_WAIT_QUEUE_HEAD(vir_queue);

ssize_t read_vir(struct file *, char *, size_t, loff_t *);
ssize_t write_vir(struct file *, const char *, size_t, loff_t *);
int open_vir(struct inode *inode, struct file *file);
int release_vir(struct inode *inode, struct file *file);
int release_vir(struct inode *inode, struct file *file);

struct file_operations virtual_fops = {
    THIS_MODULE,
    NULL,
    read_vir,
    write_vir,
    NULL,
    NULL,
    NULL,
    NULL,
    open_vir,
    NULL,
    release_vir,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

extern int driver_loaded;  file://a flag to see wether the device driver
 is
loaded.
loaded.
extern int ker_read();
extern int ker_write();

int init_module(void)
{
    int res;
    printk("<1>Installing the virtual deviec\n");
    if((res = register_chrdev(DEV_MAJOR, DEV_NAME, &virtual_fops)) < 
0) {
        printk("<1>can't get major %d\n", DEV_MAJOR);
        return res;
    }
    read_busy = 0;
    write_busy = 0;
    driver_loaded = 1;
    printk("<1>Install succeed\n");
    return 0;
}

void cleanup_module()
{
    int res;
    printk("<1>Unstalling the virtual device\n");
    printk("<1>Unstalling the virtual device\n");
    if((res = unregister_chrdev(DEV_MAJOR, DEV_NAME)) < 0) {
        printk("<1>can't unintall the device, major %d\n", DEV_MAJOR);
        return;
    }
    printk("<1>Unstall succeed\n");
    return;
}

int open_vir(struct inode *inode, struct file *file)
{
    if(MINOR(inode->i_rdev) != 0) {
        printk("<1>open error\n");
        return -ENODEV;
    }
    if((file->f_flags & O_ACCMODE) == O_RDONLY) {
        if(read_busy) {
            printk("<1>open error, open device more than once\n");
            return -EBUSY;
        } else {
            printk("<1>open device for reading\n");
            read_busy++;
            MOD_INC_USE_COUNT;
            MOD_INC_USE_COUNT;
            return 0;
        }
    } else if((file->f_flags & O_ACCMODE) == O_WRONLY) {
        if(write_busy) {
            printk("<1>write error, write more than once\n");
            return -EBUSY;
        } else {
            printk("<1>open device for writing\n");
            write_busy++;
            MOD_INC_USE_COUNT;
            return 0;
        }
    } else
        return -ENXIO;
}

int release_vir(struct inode *inode, struct file *file)
{

    if(MINOR(inode->i_rdev) != 0) {
        printk("<1>close error\n");
        return -ENODEV;
        return -ENODEV;
    }
    if((file->f_flags & O_ACCMODE) == O_RDONLY) {
        printk("<1>close device for reading\n");
        read_busy = 0;
    } else if((file->f_flags & O_ACCMODE) == O_WRONLY) {
        printk("<1>close device for writing\n");
        write_busy = 0;
    }
    MOD_DEC_USE_COUNT;
    return 0;
}

ssize_t read_vir(struct file *file, char *buf, size_t count, loff_t 
*off)
{
    int len;
    unsigned long flags;
    struct vir_buf *p;

    save_flags(flags);
    cli();
    if(rd_head == NULL) {
        //interruptible_sleep_on(&vir_queue);
        //interruptible_sleep_on(&vir_queue);
        //the function provided by ker.o
        if(ker_write() < 0) {
            printk("<1>ker_write error\n");
            restore_flags(flags);
            return -EFAULT;
        }
    }
    len = count < rd_head->size ? count : rd_head->size;
    if(copy_to_user(buf, rd_head->buf, len) != 0) {
        printk("<1>copy_to_user error\n");
        restore_flags(flags);
        return -EFAULT;
    }
    printk("<1>kernel->application: %s\n", rd_head->buf);
    p = rd_head;
    rd_head = rd_head->next;
    *off += len;
    kfree(p);
    restore_flags(flags);

    return len;
}
}

ssize_t write_vir(struct file *file, const char *buf, size_t count, 
loff_t
*off)
{
    int len;
    unsigned long flags;
    struct vir_buf *p, *q;
    len = count < MAX_SIZE ? count : MAX_SIZE;
    if((p = kmalloc(sizeof(struct vir_buf), GFP_ATOMIC)) == NULL) {
        printk("<1>kmalloc error\n");
        return -ENOMEM;
    }
/*
    if(access_ok(VERIFY_READ, buf, sizeof(buf)) == 0) {
        printk("<1>the memory in application layer can't read\n");
        return -EFAULT;
    }
*/
    save_flags(flags);
    cli();
    if(copy_from_user(p->buf, buf, len) != 0) {
        printk("<1>copy_from_user error\n");
        printk("<1>copy_from_user error\n");
        kfree(p);
        restore_flags(flags);
        return -EFAULT;
    }
    p->size = len;
    p->next = NULL;

    if(wr_head == NULL)
        wr_head = p;
    else {
        q = wr_head;
        while(q->next != NULL)
            q = q->next;
        q->next = p;
    }
    *off += len;
    printk("<1>application->kernel: %s\n", wr_head->buf);
    restore_flags(flags);

    //call the ker.o function to read the buffer
    if(ker_read() < 0) {
        printk("<1>ker_read error\n");

        return -EFAULT;
    }

    return len;
}

--

  puke! 
  技工而已

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.239.152]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.361毫秒