• [虚拟化/云][全栈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)              # 读外设的寄存器
        ['Bx00
    ']
        >>> 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
    ", cwd_expect_close);
     50                 return -EFAULT;
     51             }
     52             printk(KERN_ALERT "Hello, I'm cwd_demo %d
    ", 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
    ", c);
     57             if (c == 'a') { //
     58                     printk(KERN_ALERT "cwd_demo activates watchdog
    ");
     59                     outb(0x03, CWD_ACTIVATE_REG);
     60             }
     61             if (c == 'd') {//
     62                     printk(KERN_ALERT "cwd_demo deactivates watchdog
    ");
     63                     outb(0x00, CWD_ACTIVATE_REG);
     64             }
     65             if (c == 't') {//
     66                     printk(KERN_ALERT "cwd_demo feeds watchdog
    ");
     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
    ", *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
    ", data[0]);
     85                 return -EFAULT;
     86             }
     87             printk(KERN_ALERT "Hello, I'm cwd_demo 0x%x
    ", data[0]);
     88             data[1] = inb(CWD_ACTIVATE_REG);
     89             printk(KERN_ALERT "Hello, this is the second char 0x%x
    ", data[1]);
     90             data[2] = 10;
     91             if (copy_to_user(buffer, data, count)){
     92                     printk(KERN_ALERT "in read, copy to read failed
    ");
     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_CRIT
    121                                     "Unexpected close, not stopping watchdog!
    ");
    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 interface
    146      */
    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
    ");
    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
    ");
    164                     goto err_disable;
    165             }
    166      
    167             if (pci_request_region(pdev, 0, CWD_MODULE_NAME)) {
    168                     printk(KERN_ERR "failed to request region
    ");
    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
    ");
    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 
    ", inb(io));
    186             printk(KERN_ERR "success to get BASEADDR: 0x%x
    ", 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
    ",
    209                             CWD_VERSION);
    210      
    211             if (cards_found > 1) {
    212                     printk(KERN_ERR "Cstl driver only supports 1 device
    ");
    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
    ",
    224             //                  MAJOR(cwd_miscdev), MINOR(cwd_miscdev));
    225             printk(KERN_ERR "register miscdev on minor=%d
    ", WATCHDOG_MINOR);
    226             if (ret != 0) {
    227                     printk(KERN_ERR
    228                             "cannot register miscdev on minor=%d (err=%d)
    ",
    229                                                             WATCHDOG_MINOR, ret);
    230                     goto err_unmap;
    231             }
    232             printk(KERN_INFO
    233                     "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...
    ");
    280         printk(KERN_ALERT "Hello, I'm cwd_demo
    ");
    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!
    ");
    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.o
    10 endif
    View Code
  • 相关阅读:
    spring学习之模拟spring(spring原理解析)-01.xml文件的解析
    存储过程学习
    对象的深浅拷贝
    JavaScript 面向对象编程思想(二)
    深层剖析JavaScript 一
    深入剖析 css
    Vuex 总结
    h5 微信授权
    LeetCode
    echarts-liquidfill
  • 原文地址:https://www.cnblogs.com/shaohef/p/3816795.html
Copyright © 2020-2023  润新知