Linux Driver(4) - 多個裝置、ioctl、lseekLinux Driver(3) - 最基本的開關讀寫 ),來增加一些功能。1. 多個裝置2. ioctl、lseek函式共有3個步驟。1. 修改scripts,改成建造4 個 nodes2. 修改vhcar.h,並新增 ioctl.h3. 修改vchar.c1. 修改scripts,改成建造4 個 nodes:先把他改成多個裝置,這裡我們設定為4個,那首先就要在 /dev 底下創造 4 個 nodes。先修改 vchar_load.sh 和 vchar_unload.sh。vchar_load.sh:把rm -f /dev/$module || exit 1mknod /dev/$module c $major 0改成rm -f /dev/${module}[0-3] || exit 1mknod /dev/${module}0 c $major 0 || exit 1mknod /dev/${module}1 c $major 1 || exit 1mknod /dev/${module}2 c $major 2 || exit 1mknod /dev/${module}3 c $major 3 vchar_unload.sh:把rm -f /dev/$module改成rm -f /dev/${module}[0-3]這樣就會在 /dev 底下建造 vchar0~3 共4個 nodes。2. 修改vhcar.h,並新增 ioctl.h先將VIRTUAL_CHAR_DEVICE_NR_DEVS從原來的 1 改成 4 。再新增 ioctl 和 llseek 兩個函式int     vchar_ioctl(struct inode *inodep, struct 辦公室出租file *filp, unsigned int cmd, unsigned long arg);loff_t  vchar_llseek(struct file *filp, loff_t offset, int whence);最後增加 ioctl.h,內容如下:#ifndef _VCHAR_IOCTL_H_#define _VCHAR_IOCTL_H_#define MEM_CLEAR 0x1    // set memory to zero#endif內容很簡單,就是給user-space引入用的,讓它可以透過ioctl來控制driver,而這的功能就是清除memory的內容,並把offset移到0的位置。3. 修改vchar.c我們需要增加一個index的欄位給  vchar_dev 結構,這是為了讓 作業方法可以辨認此時是操作那一個設備。typedef struct _vchar_dev{    struct cdev cdev; // char device    unsigned char mem[VCHAR_MEM_SIZE];    int index;}vchar_dev;更改vchar_fops,增加指定 llseek 和 ioctl 函式。const 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,};在vchar_init裡,更變分配devp記憶體的地方和註冊字元裝置的地方成4份    vchar_devp = kmalloc(vchar_nr_devs * 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, vchar_nr_devs * sizeof(vchar_dev));    int i;    for (i=0; i    {        vchar_setup_cdev(vchar_devp, i);        TRACE("schar%d is loaded...\n", i);    }釋放的 vchar_exit也要記得取消註冊4份字元裝置    int i;    for (i=0; 節能燈具i    {        cdev_del(&vchar_devp[i].cdev);   // delete char device        TRACE("schar%d is unloaded...\n", i);    }在 vchar_setup_cdev 裡增加這一行devp->index = index;給每一個 device 設定編號。在vchar_open裡,我們有4個 vchar_devp,我們需用不同的方法來儲存多個 vchar_dev*給filp->private_data。在 inode裡有一個 i_cdev欄位,這欄位指向一個cdev結構,但我們要的不是cdev結構,而是自已定義的 vchar_dev 結構。 這時可以用 container_of 巨集來取得所需的 vchar_dev 結構。    vchar_dev *devp;    devp = container_of(inode->i_cdev, vchar_dev, cdev);    filp->private_data = devp;container_of 的說明可參考這篇 Linux Driver(5) - container_of 分析 。read  、 write 並不用修改,但可加上index,來觀察目前讀寫的設備編號:TRACE("vchar%d:read %d bytes(s) from 吳哥窟%ld\n", devp->index, count, offset);增加 ioctl函式的內容:int vchar_ioctl(struct inode *inodep, struct file *filp, unsigned  int cmd, unsigned long arg){    vchar_dev *devp = filp->private_data;    switch (cmd)    {    case MEM_CLEAR:        memset(devp->mem, 0, VCHAR_MEM_SIZE);        filp->f_pos = 0;        TRACE("vchar%d: The memory is set to zero\n", devp->index);        break;    default:        return  - EINVAL;    }    return 0;}這裡做的就是清除 devp->mem 的內容,並把檔案 offset指為 0。增加 llseek函式的內容:loff_t vchar_llseek(struct file *filp, loff_t offset, int whence){    loff_t newpos = 酒店工作0;    vchar_dev *devp = filp->private_data;    switch (whence)    {    case 0:   // SEEK_SET        TRACE("vchar%d: SEEK_SET\n", devp->index);        newpos = offset;        break;    case 1:   // SEEK_CUR        TRACE("vchar%d: SEEK_CUR\n", devp->index);        newpos = filp->f_pos + offset;        break;    case 2:      // SEEK_END        TRACE("vchar%d: SEEK_END\n", devp->index);        newpos = VCHAR_MEM_SIZE + offset;        break;    襯衫default:        return -EINVAL;      break;    }    if (newpos < 0 || newpos > VCHAR_MEM_SIZE)    {        return -EINVAL;    }    TRACE("vchar%d: newpos:%d\n", devp->index, newpos);    filp->f_pos = newpos;    return newpos;}根據 whence 的值來做 offset 的位移。實際做的就是回應 user-space 中的 lseek 函式。最後再給出應用的例子,#include <sys/types.h>#include <unistd.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <stddef.h>#include <stdio.h>#include <fcntl.h>#include <error.h>#include "ioctl.h"#define BUF_SIZE 128#define MAX_DEVS 4int main(void){    int i;    int fd[MAX_DEVS];    ssize_t 當鋪len=0;    __off_t offset=0;    const char* dev_name[MAX_DEVS] = {"/dev/vchar0","/dev/vchar1","/dev/vchar2","/dev/vchar3"};    unsigned char buf[MAX_DEVS][BUF_SIZE] = {0};    for (i=0; i<MAX_DEVS; i++)    {        fd[i] = open(dev_name[i], O_RDWR, S_IRUSR | S_IWUSR);        if (fd[i])        {            memset(buf[i], i+1, BUF_SIZE);    // set the memory to zero            len = lseek(fd[i], offset, SEEK_END);    // get the length of vchar            printf("get %d  of vchar\n", len);        酒店兼職    lseek(fd[i], offset, SEEK_SET);    // set the offset to start            len = BUF_SIZE;            len = write(fd[i], buf[i], len);            printf("vchar%d:write: %d bytes\n", i, len);        }        else        {            perror("test_vchar::write");            return -1;        }        lseek(fd[i], offset, SEEK_SET);    // set the offset to start        len = read(fd[i], buf, BUF_SIZE);        if (len > 當鋪0)        {            printf("vchar%d:read: %d bytes\n", i, len);        }        else        {            perror("test_vchar::read");            return -1;        }        if (ioctl(fd[i], MEM_CLEAR) == -1)        {            perror("test_vchar::ioctl");            return -1;        }        close(fd[i]);    }    return 0;}


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



分享

Facebook
Plurk
YAHOO!

創作者介紹

fishing

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