close
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!
.msgcontent .wsharing ul li { 票貼text-indent: 0; }
分享
Plurk
YAHOO!
全站熱搜
留言列表