首页 > 代码库 > [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(七)
[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(七)
目标:
1. 完成最终的设备驱动,增加具体的watchdog设备操作的代码。
测试代码:
代码最终实现见cwd_demo.c
代码只实现了read与write. 没有实现ioctl.
因此,我们可以通过shell指令直接操作我们的watchdog.
read函数,只读取watchdog的0x01 和0x02寄存器。
write函数无论写入多少个字节,驱动实际只写第一个字节。
1. 编译
$ make
2. 装载驱动
$ sudo insmod cwd_demo.ko
3.查看设备
$ sudo ls /dev/cdw_demo -l
crw------- 1 root root 10, 171 6月 30 18:38 /dev/cdw_demo
生成一个主设备号为10, 次设备号为171的设备。
4. 读取设备信息
$ sudo cat /dev/cdw_demo
B
5. 操作设备
此操作需要使用root用户
# sudo echo ‘a‘ > /dev/cdw_demo #激活watchdog
# sudo echo ‘t‘ > /dev/cdw_demo # 喂狗
# sudo echo ‘d‘ > /dev/cdw_demo # 停止停止设备
6. 卸载驱动 $ sudo rmmod cwd_demo
7. 查看log记录
$ tail -f -n 30 /var/log/syslog
8. 使用python操作
$ su # python >>> f = open("/dev/cwd_demo", "w+") #打开 >>> f.write("a"); f.flush() #激活watchdog >>> f.write("t"); f.flush() # 喂狗 >>> f.write("d"); f.flush() # 停止watchdog >>> f.readlines(); f.seek(0, 0) # 读外设的寄存器 [‘B\x00\n‘] >>> f.close() #关闭外设 >>>
代码:
cwd_demo.c
1 #include <linux/init.h> //初始换函数 2 #include <linux/kernel.h> //内核头文件 3 #include <linux/module.h> //模块的头文件 4 #include <linux/pci.h> 5 #include <linux/miscdevice.h> 6 #include <linux/types.h> 7 #include <linux/fs.h> 8 #include <linux/mm.h> 9 #include <linux/watchdog.h> 10 #include <linux/ioport.h> 11 #include <linux/uaccess.h> 12 #include <linux/io.h> 13 14 15 16 #define CWD_MODULE_NAME "cstl watchdog" 17 18 /* We only use 1 card for cwd_demo */ 19 static int cards_found; 20 static struct pci_dev *cwd_pci; 21 22 MODULE_LICENSE("GPL"); 23 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 24 25 #define CWD_VERSION "0.1" 26 #define PCI_VENDOR_ID_REDHAT 0x1af4 27 #define PCI_DEVICE_ID_CWD 0x0101 28 29 /* Memory mapped registers */ 30 #define CWD_EXPECT_CLOSE_REG (io + 0x00) /* make no sense, read is 0x42*/ 31 #define CWD_ACTIVATE_REG (io + 0x01) 32 #define CWD_TRIGER_REG (io + 0x02) 33 34 /* internal variables */ 35 static void __iomem *BASEADDR; 36 static resource_size_t io; 37 38 /* 39 * Kernel Interfaces 40 */ 41 42 static ssize_t cwd_write(struct file *file, const char __user *data, 43 size_t len, loff_t *ppos) 44 { 45 /* See if we got the magic character ‘V‘ and reload the timer */ 46 char c; 47 char cwd_expect_close = inb(CWD_EXPECT_CLOSE_REG); 48 if (cwd_expect_close != 0x42){ 49 printk(KERN_ERR "failed to request the magic character, %d\n", cwd_expect_close); 50 return -EFAULT; 51 } 52 printk(KERN_ALERT "Hello, I‘m cwd_demo %d\n", cwd_expect_close); 53 /* only support one character one time write. ignore len */ 54 if (get_user(c, data + 0)) 55 return -EFAULT; 56 printk(KERN_ALERT "Hello, cwd_demo is writing %d\n", c); 57 if (c == ‘a‘) { // 58 printk(KERN_ALERT "cwd_demo activates watchdog\n"); 59 outb(0x03, CWD_ACTIVATE_REG); 60 } 61 if (c == ‘d‘) {// 62 printk(KERN_ALERT "cwd_demo deactivates watchdog\n"); 63 outb(0x00, CWD_ACTIVATE_REG); 64 } 65 if (c == ‘t‘) {// 66 printk(KERN_ALERT "cwd_demo feeds watchdog\n"); 67 outb(0x32, CWD_TRIGER_REG); 68 } 69 return len; 70 } 71 72 static ssize_t cwd_read(struct file *file, char __user *buffer, 73 size_t count, loff_t *ppos) 74 { 75 char data[3]; 76 int retval = 0; 77 if (*ppos >= 3) 78 goto out; 79 else if (*ppos + count > 3) 80 count = 3 - *ppos; 81 printk(KERN_ALERT "in read, ppos is %d, count is %d\n", *ppos, count); 82 data[0] = inb(CWD_EXPECT_CLOSE_REG); 83 if (data[0] != 0x42){ 84 printk(KERN_ERR "failed to request the magic character, 0x%x\n", data[0]); 85 return -EFAULT; 86 } 87 printk(KERN_ALERT "Hello, I‘m cwd_demo 0x%x\n", data[0]); 88 data[1] = inb(CWD_ACTIVATE_REG); 89 printk(KERN_ALERT "Hello, this is the second char 0x%x\n", data[1]); 90 data[2] = 10; 91 if (copy_to_user(buffer, data, count)){ 92 printk(KERN_ALERT "in read, copy to read failed\n"); 93 retval = -EFAULT; 94 goto out; 95 } 96 *ppos += count; 97 retval = count; 98 out: 99 return retval;100 }101 102 static loff_t cwd_llseek(struct file *file, loff_t offset, int whence)103 {104 file->f_pos = 0;105 return file->f_pos;106 }107 static int cwd_open(struct inode *inode, struct file *file)108 {109 // return nonseekable_open(inode, file);110 return 0;111 }112 113 static int cwd_release(struct inode *inode, struct file *file)114 {115 /* Shut off the timer. */116 char activate = 0x1;117 outb(0x00, CWD_ACTIVATE_REG);118 activate = inb(CWD_ACTIVATE_REG);119 if (activate != 0x00){120 printk(KERN_CRIT121 "Unexpected close, not stopping watchdog!\n");122 }123 return 0;124 }125 126 static const struct file_operations cwd_fops = {127 .owner = THIS_MODULE,128 .llseek = cwd_llseek,129 .write = cwd_write,130 .read = cwd_read,131 // .unlocked_ioctl = cwd_ioctl,132 .open = cwd_open,133 .release = cwd_release,134 };135 136 static struct miscdevice cwd_miscdev = {137 // .minor = WATCHDOG_MINOR,138 .minor = 171,139 .name = "cwd_demo",140 .fops = &cwd_fops,141 };142 143 144 /*145 * Data for PCI driver interface146 */147 static DEFINE_PCI_DEVICE_TABLE(cwd_pci_tbl) = {148 { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_CWD), },149 { 0, }, /* End of list */150 };151 MODULE_DEVICE_TABLE(pci, cwd_pci_tbl);152 153 154 static unsigned char cwd_getdevice(struct pci_dev *pdev)155 {156 unsigned int addr = 0;157 if (pci_enable_device(pdev)) {158 printk(KERN_ERR "failed to enable device\n");159 goto err_devput;160 }161 162 if (pci_resource_start(pdev, 0) == 0x0000) {163 printk(KERN_ERR "No I/O-Address for card detected\n");164 goto err_disable;165 }166 167 if (pci_request_region(pdev, 0, CWD_MODULE_NAME)) {168 printk(KERN_ERR "failed to request region\n");169 goto err_disable;170 }171 172 // BASEADDR = pci_ioremap_bar(pdev, 0);173 // BASEADDR = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));174 // if (BASEADDR == NULL) {175 // /* Something‘s wrong here, BASEADDR has to be set */176 // printk(KERN_ERR "failed to get BASEADDR\n");177 // goto err_release;178 // }179 180 /* here we are testing it is a io space or mem space */181 // pci_write_config_dword(pdev, 0x10, 0xc090);182 pci_read_config_dword(pdev, 0x10, &addr);183 184 io = pci_resource_start(pdev, 0);185 printk(KERN_ERR "base addr 0 is 0x%x \n", inb(io));186 printk(KERN_ERR "success to get BASEADDR: 0x%x\n", addr);187 188 /* Done */189 cwd_pci = pdev;190 return 1;191 192 err_release:193 pci_release_region(pdev, 0);194 err_disable:195 pci_disable_device(pdev);196 err_devput:197 return 0;198 }199 200 201 static int cwd_probe(struct pci_dev *pdev,202 const struct pci_device_id *ent)203 {204 int ret;205 static int major, minor;206 cards_found++;207 if (cards_found == 1)208 printk(KERN_INFO "Cstl WatchDog Timer Driver v%s\n",209 CWD_VERSION);210 211 if (cards_found > 1) {212 printk(KERN_ERR "Cstl driver only supports 1 device\n");213 return -ENODEV;214 }215 216 /* Check whether or not the hardware watchdog is there */217 if (!cwd_getdevice(pdev) || cwd_pci == NULL)218 return -ENODEV;219 /* Register the watchdog so that userspace has access to it */220 ret = misc_register(&cwd_miscdev);221 // major = MAJOR(cwd_miscdev);222 // minor = MINOR(cwd_miscdev);223 // printk(KERN_ERR "register miscdev on major=%d minor=%d\n",224 // MAJOR(cwd_miscdev), MINOR(cwd_miscdev));225 printk(KERN_ERR "register miscdev on minor=%d\n", WATCHDOG_MINOR);226 if (ret != 0) {227 printk(KERN_ERR228 "cannot register miscdev on minor=%d (err=%d)\n",229 WATCHDOG_MINOR, ret);230 goto err_unmap;231 }232 printk(KERN_INFO233 "initialized cstl watchdog (0x%x).", (unsigned int)io);234 return 0;235 err_unmap:236 iounmap(BASEADDR);237 pci_release_region(cwd_pci, 0);238 pci_disable_device(cwd_pci);239 cwd_pci = NULL;240 return ret;241 242 }243 244 static int cwd_timer_stop(void)245 {246 /* Returns 0 if the timer was disabled, non-zero otherwise */247 return 0;248 }249 250 static void cwd_remove(struct pci_dev *pdev)251 {252 /* Stop the timer before we leave */253 cwd_timer_stop();254 255 /* Deregister */256 misc_deregister(&cwd_miscdev);257 // iounmap(BASEADDR);258 pci_release_region(cwd_pci, 0);259 pci_disable_device(cwd_pci);260 cwd_pci = NULL;261 }262 263 static void cwd_shutdown(struct pci_dev *pdev)264 {265 cwd_timer_stop();266 }267 268 269 static struct pci_driver cwd_driver = {270 .name = CWD_MODULE_NAME,271 .id_table = cwd_pci_tbl,272 .probe = cwd_probe,273 .remove = cwd_remove,274 .shutdown = cwd_shutdown,275 };276 277 static int __init cwd_demo_start(void)278 {279 printk(KERN_ALERT "Loading cwd_demo module...\n");280 printk(KERN_ALERT "Hello, I‘m cwd_demo\n");281 return pci_register_driver(&cwd_driver);282 }283 284 static void __exit cwd_demo_end(void)285 {286 pci_unregister_driver(&cwd_driver);287 printk(KERN_ALERT "cwd demo Module Unloaded, Goodbye!\n");288 289 }290 291 module_init(cwd_demo_start);292 module_exit(cwd_demo_end);
Makefile
1 ifeq ($(KERNELRELEASE),) 2 KVERSION = $(shell uname -r) 3 all: 4 make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) modules 5 echo $(shell pwd) 6 clean: 7 make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) clean 8 else 9 obj-m :=cwd_demo.o10 endif
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。