Linux Driver(3) - 最基本的開關讀寫(3)vchar.h:#ifndef _VIRTUAL_CHAR_DEVICE_H_#define _VIRTUAL_CHAR_DEVICE_H_#include #ifndef VCHAR_MEM_SIZE#define VCHAR_MEM_SIZE 128#endif#ifndef VIRTUAL_CHAR_DEVICE_MAJOR#define VIRTUAL_CHAR_DEVICE_MAJOR 0   // dynamic major by default#endif#ifndef VIRTUAL_CHAR_DEVICE_NR_DEVS#define VIRTUAL_CHAR_DEVICE_NR_DEVS 1    // number of bare virtual devices#endif#ifdef VIRTUAL_CHAR_DEVICE_DEBUG    #ifdef __KERNEL__        #define TRACE(fmt, args...) printk( KERN_DEBUG "vchar: " fmt, ## args)    #else        #define TRACE(fmt, args...) fprintf(stderr, fmt, ## args)    #endif#else    #define TRACE(fmt, args...)#endifint vchar_open(struct inode *inode, struct file *filp);int vchar_release(struct inode *inode, struct file *filp);ssize_t vchar_read(struct file *filp, char __user *buf, size_t size,  loff_t *ppos);ssize_t vchar_write(struct file *filp, const char 酒店打工__user *buf,  size_t size, loff_t *ppos);#endif // _VIRTUAL_CHAR_DEVICE_H_vchar.c: #include <linux/module.h>#include <linux/types.h>#include <linux/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>#include "ioctl.h"#define VIRTUAL_CHAR_DEVICE_DEBUG#include "vchar.h"int vchar_major = VIRTUAL_CHAR_DEVICE_MAJOR;int vchar_minor = 0;int vchar_nr_devs = VIRTUAL_CHAR_DEVICE_NR_DEVS;const char* vchar_name = "vchar";typedef struct _vchar_dev{    struct cdev cdev; // char device    unsigned char mem[VCHAR_MEM_SIZE];}vchar_dev;vchar_dev* vchar_devp;// file operation structconst struct file_operations vchar_fops ={  .owner = THIS_MODULE, // .llseek = vchar_llseek,  .read = vchar_read,  .write = vchar_write, // .ioctl = vchar_ioctl,  .open = vchar_open,  室內裝潢.release = vchar_release,};int vchar_open(struct inode *inode, struct file *filp){    filp->private_data = vchar_devp;    return 0;}int vchar_release(struct inode *inode, struct file *filp){    return 0;}ssize_t vchar_read(struct file *filp, char __user *buf,        size_t size, loff_t *ppos){    unsigned long offset =  *ppos;    unsigned int count = size; // count of data    int ret = 0;    vchar_dev *devp = filp->private_data;    // count the lenght of read correctly    if (offset >= VCHAR_MEM_SIZE)      return count ?  - ENXIO: 0;    if (count > VCHAR_MEM_SIZE - offset)      count = VCHAR_MEM_SIZE - offset;    // copy data to user-space    if (copy_to_user(buf, (void*)(devp->mem + offset), count))    {        ret =  買屋- EFAULT;    }    else    {        *ppos += count;        ret = count;        TRACE("read %d bytes(s) from %ld\n", count, offset);    }    return ret;}ssize_t vchar_write(struct file *filp, const char __user *buf,        size_t size, loff_t *ppos){    unsigned long offset =  *ppos;    unsigned int count = size; // count of data    int ret = 0;    vchar_dev *devp = filp->private_data;    // count the lenght of write correctly    if (offset >= VCHAR_MEM_SIZE)        return count ?  - ENXIO: 0;    if (count > VCHAR_MEM_SIZE - offset)        count = VCHAR_MEM_SIZE - offset;     // get the data from user-space     if 土地買賣(copy_from_user(devp->mem + offset, buf, count))     {        ret =  - EFAULT;     }     else     {        *ppos += count;        ret = count;        TRACE("written %d bytes(s) from %d\n", count, offset);     }     return ret;}// initiate and register cdevstatic void vchar_setup_cdev(vchar_dev* devp, int index){    int error, devno = MKDEV(vchar_major, index);    cdev_init(&devp->cdev, &vchar_fops);    devp->cdev.owner = THIS_MODULE;    devp->cdev.ops = &vchar_fops;    error = cdev_add(&devp->cdev, devno, vchar_nr_devs);    if (error)        TRACE("Error %d adding vchar%d\n", error, index);}int 房屋貸款vchar_init(void){    int result;    dev_t devno = 0; // device number    // asking for a device number, default is 0    if (vchar_major)    {          devno = MKDEV(vchar_major, vchar_minor);          result = register_chrdev_region(devno, vchar_nr_devs, vchar_name);    }    else // 0 is dynamic    {          result = alloc_chrdev_region(&devno, vchar_minor, vchar_nr_devs, vchar_name);          vchar_major = MAJOR(devno);    }    if (result < 0)        return result;    // allocate memory for devp    vchar_devp = kmalloc(sizeof(vchar_dev), GFP_KERNEL);    if (!vchar_devp)    {        // unregister device before return 西裝外套error        unregister_chrdev_region(devno, vchar_nr_devs);        return result = -ENOMEM;    }    memset(vchar_devp, 0, sizeof(vchar_dev));    vchar_setup_cdev(vchar_devp, 0);    TRACE("schar is loaded...\n");    return 0;}void vchar_exit(void){    cdev_del(&vchar_devp->cdev);   // delete char device    kfree(vchar_devp);     // free device memory    unregister_chrdev_region(MKDEV(vchar_major, vchar_minor), vchar_nr_devs); // free device number    TRACE("schar is unloaded...\n");}MODULE_AUTHOR("Hughes");MODULE_LICENSE("Dual BSD/GPL");module_init(vchar_init);module_exit(vchar_exit); 說明: vchar_init:依vchar_major的值來決定用動態的還是靜態的裝置編號,預設為0,這裡表示使用動態的方法申請。接著使用 kmalloc來分配憶體給 vchar_devp,vchar_devp為我們自定義的結構,內含節能燈具cdev結構。kmalloc類似malloc,用法差不多。 接著呼叫vchar_setup_cdev()來註冊字元裝置。vchar_exit:呼叫 cdev_del 摧毀 vchar_devp裡的cdev,釋放 vchar_devp的記憶體,最後再取消已註冊的字元裝置編號。vchar_setup_cdev: 使用cdev_init來初始化 cdev,並設定 file_operations給kernel,最後呼叫 cdev_add來將cdev加入kernel。vchar_open、vchar_release:在open時,用filp->private_data來儲存我們的vchar_devp。release在這裡並沒有做任何事。vchar_read、vchar_write: 我們有在vchar_devp結構裡宣告了一個大小為128的記憶體,用來放讀寫的資料。read、write很像,在這裡作的動作差不多,差別是一個是 copy資料到user-space,另一個是從 user-space得到資料。filp :在這裡是用來得到vchar_dev指標,也就是open時存的 filp->private_data。buf :是用來和user-space傳輸資料用的,我們不應該直接操作 buf(因為很多原因),應該用安全的函式,       在這裡我們使用copy_to_user和copy_from_user,使用上類似memcpy。size:這裡指的是要讀寫的資料大小ppos:這裡是偏移值的指標大概的流程就是檢查偏移值和要讀寫的資料大小後,再做讀寫的動作。main.c:#include <sys/types.h>#include 關鍵字排名<unistd.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <stdio.h>#include <fcntl.h>#include <error.h>#define BUF_SIZE 130int main(void){    int fd;    ssize_t len=0;    const char* dev_name = "/dev/vchar";    unsigned char buf[BUF_SIZE] = {0};    fd = open(dev_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);    if (fd)    {        memset(buf, 1, BUF_SIZE);        len = write(fd, buf, BUF_SIZE);        printf("write: %d bytes\n", len);        close(fd);    }    else    {        perror("test_vchar::write");    }    fd = open(dev_name, O_RDWR);    len = read(fd, buf, BUF_SIZE);    if (len > 0)    西裝{        printf("read: %d bytes\n", len);    }    else    {        perror("test_vchar::read");    }    len = read(fd, buf, BUF_SIZE);    if (len > 0)    {        printf("read: %d bytes\n", len);    }    else    {        perror("test_vchar::read");    }    close(fd);}說明:這隻程式是user-space的,即是輸入make app後,產生的test_vchar程式。主要就是測試讀寫的功能,這裡是測試讀寫大於128的資料。5. 使用方法1.產生所需的Makefile、vchar_load.sh、vchar_unload.sh、vchar.c、vchar.h、main.c。2.輸入make,產生並載入vchar module。3.輸入make app,產生test_vchar4.輸入./test_vchar,執行程式後看vchar的反應。5.要看vchar driver 輸出的訊息,請輸入 dmesg | tail。


.msgcontent .wsharing ul li { text-indent: 0; }


酒店兼職
分享

Facebook
Plurk
YAHOO!

創作者介紹

Sean Penn

wl84wllzyt 發表在 痞客邦 PIXNET 留言(0) 人氣()