[虚拟化/云][全栈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_CRIT
121                                     "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 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\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_ERR
228                             "cannot register miscdev on minor=%d (err=%d)\n",
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...\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.o
10 endif
View Code

 

posted @ 2014-07-07 21:22  lvmxh  阅读(1424)  评论(0编辑  收藏  举报