[虚拟化/云][全栈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

 

你可能感兴趣的:(demo)