首页 > 代码库 > [虚拟化/云][全栈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);
View Code

 

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
View Code