目标:

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

     #include <linux/init.h>  //初始换函数
#include <linux/kernel.h> //内核头文件
#include <linux/module.h> //模块的头文件
#include <linux/pci.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/uaccess.h>
#include <linux/io.h> #define CWD_MODULE_NAME "cstl watchdog" /* We only use 1 card for cwd_demo */
static int cards_found;
static struct pci_dev *cwd_pci; MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); #define CWD_VERSION "0.1"
#define PCI_VENDOR_ID_REDHAT 0x1af4
#define PCI_DEVICE_ID_CWD 0x0101 /* Memory mapped registers */
#define CWD_EXPECT_CLOSE_REG (io + 0x00) /* make no sense, read is 0x42*/
#define CWD_ACTIVATE_REG (io + 0x01)
#define CWD_TRIGER_REG (io + 0x02) /* internal variables */
static void __iomem *BASEADDR;
static resource_size_t io; /*
* Kernel Interfaces
*/ static ssize_t cwd_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* See if we got the magic character 'V' and reload the timer */
char c;
char cwd_expect_close = inb(CWD_EXPECT_CLOSE_REG);
if (cwd_expect_close != 0x42){
printk(KERN_ERR "failed to request the magic character, %d\n", cwd_expect_close);
return -EFAULT;
}
printk(KERN_ALERT "Hello, I'm cwd_demo %d\n", cwd_expect_close);
/* only support one character one time write. ignore len */
if (get_user(c, data + ))
return -EFAULT;
printk(KERN_ALERT "Hello, cwd_demo is writing %d\n", c);
if (c == 'a') { //
printk(KERN_ALERT "cwd_demo activates watchdog\n");
outb(0x03, CWD_ACTIVATE_REG);
}
if (c == 'd') {//
printk(KERN_ALERT "cwd_demo deactivates watchdog\n");
outb(0x00, CWD_ACTIVATE_REG);
}
if (c == 't') {//
printk(KERN_ALERT "cwd_demo feeds watchdog\n");
outb(0x32, CWD_TRIGER_REG);
}
return len;
} static ssize_t cwd_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
char data[];
int retval = ;
if (*ppos >= )
goto out;
else if (*ppos + count > )
count = - *ppos;
printk(KERN_ALERT "in read, ppos is %d, count is %d\n", *ppos, count);
data[] = inb(CWD_EXPECT_CLOSE_REG);
if (data[] != 0x42){
printk(KERN_ERR "failed to request the magic character, 0x%x\n", data[]);
return -EFAULT;
}
printk(KERN_ALERT "Hello, I'm cwd_demo 0x%x\n", data[]);
data[] = inb(CWD_ACTIVATE_REG);
printk(KERN_ALERT "Hello, this is the second char 0x%x\n", data[]);
data[] = ;
if (copy_to_user(buffer, data, count)){
printk(KERN_ALERT "in read, copy to read failed\n");
retval = -EFAULT;
goto out;
}
*ppos += count;
retval = count;
out:
return retval;
} static loff_t cwd_llseek(struct file *file, loff_t offset, int whence)
{
file->f_pos = ;
return file->f_pos;
}
static int cwd_open(struct inode *inode, struct file *file)
{
// return nonseekable_open(inode, file);
return ;
} static int cwd_release(struct inode *inode, struct file *file)
{
/* Shut off the timer. */
char activate = 0x1;
outb(0x00, CWD_ACTIVATE_REG);
activate = inb(CWD_ACTIVATE_REG);
if (activate != 0x00){
printk(KERN_CRIT
"Unexpected close, not stopping watchdog!\n");
}
return ;
} static const struct file_operations cwd_fops = {
.owner = THIS_MODULE,
.llseek = cwd_llseek,
.write = cwd_write,
.read = cwd_read,
// .unlocked_ioctl = cwd_ioctl,
.open = cwd_open,
.release = cwd_release,
}; static struct miscdevice cwd_miscdev = {
// .minor = WATCHDOG_MINOR,
.minor = ,
.name = "cwd_demo",
.fops = &cwd_fops,
}; /*
* Data for PCI driver interface
*/
static DEFINE_PCI_DEVICE_TABLE(cwd_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_CWD), },
{ , }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, cwd_pci_tbl); static unsigned char cwd_getdevice(struct pci_dev *pdev)
{
unsigned int addr = ;
if (pci_enable_device(pdev)) {
printk(KERN_ERR "failed to enable device\n");
goto err_devput;
} if (pci_resource_start(pdev, ) == 0x0000) {
printk(KERN_ERR "No I/O-Address for card detected\n");
goto err_disable;
} if (pci_request_region(pdev, , CWD_MODULE_NAME)) {
printk(KERN_ERR "failed to request region\n");
goto err_disable;
} // BASEADDR = pci_ioremap_bar(pdev, 0);
// BASEADDR = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
// if (BASEADDR == NULL) {
// /* Something's wrong here, BASEADDR has to be set */
// printk(KERN_ERR "failed to get BASEADDR\n");
// goto err_release;
// } /* here we are testing it is a io space or mem space */
// pci_write_config_dword(pdev, 0x10, 0xc090);
pci_read_config_dword(pdev, 0x10, &addr); io = pci_resource_start(pdev, );
printk(KERN_ERR "base addr 0 is 0x%x \n", inb(io));
printk(KERN_ERR "success to get BASEADDR: 0x%x\n", addr); /* Done */
cwd_pci = pdev;
return ; err_release:
pci_release_region(pdev, );
err_disable:
pci_disable_device(pdev);
err_devput:
return ;
} static int cwd_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int ret;
static int major, minor;
cards_found++;
if (cards_found == )
printk(KERN_INFO "Cstl WatchDog Timer Driver v%s\n",
CWD_VERSION); if (cards_found > ) {
printk(KERN_ERR "Cstl driver only supports 1 device\n");
return -ENODEV;
} /* Check whether or not the hardware watchdog is there */
if (!cwd_getdevice(pdev) || cwd_pci == NULL)
return -ENODEV;
/* Register the watchdog so that userspace has access to it */
ret = misc_register(&cwd_miscdev);
// major = MAJOR(cwd_miscdev);
// minor = MINOR(cwd_miscdev);
// printk(KERN_ERR "register miscdev on major=%d minor=%d\n",
// MAJOR(cwd_miscdev), MINOR(cwd_miscdev));
printk(KERN_ERR "register miscdev on minor=%d\n", WATCHDOG_MINOR);
if (ret != ) {
printk(KERN_ERR
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_unmap;
}
printk(KERN_INFO
"initialized cstl watchdog (0x%x).", (unsigned int)io);
return ;
err_unmap:
iounmap(BASEADDR);
pci_release_region(cwd_pci, );
pci_disable_device(cwd_pci);
cwd_pci = NULL;
return ret; } static int cwd_timer_stop(void)
{
/* Returns 0 if the timer was disabled, non-zero otherwise */
return ;
} static void cwd_remove(struct pci_dev *pdev)
{
/* Stop the timer before we leave */
cwd_timer_stop(); /* Deregister */
misc_deregister(&cwd_miscdev);
// iounmap(BASEADDR);
pci_release_region(cwd_pci, );
pci_disable_device(cwd_pci);
cwd_pci = NULL;
} static void cwd_shutdown(struct pci_dev *pdev)
{
cwd_timer_stop();
} static struct pci_driver cwd_driver = {
.name = CWD_MODULE_NAME,
.id_table = cwd_pci_tbl,
.probe = cwd_probe,
.remove = cwd_remove,
.shutdown = cwd_shutdown,
}; static int __init cwd_demo_start(void)
{
printk(KERN_ALERT "Loading cwd_demo module...\n");
printk(KERN_ALERT "Hello, I'm cwd_demo\n");
return pci_register_driver(&cwd_driver);
} static void __exit cwd_demo_end(void)
{
pci_unregister_driver(&cwd_driver);
printk(KERN_ALERT "cwd demo Module Unloaded, Goodbye!\n"); } module_init(cwd_demo_start);
module_exit(cwd_demo_end);

Makefile

 ifeq ($(KERNELRELEASE),)
KVERSION = $(shell uname -r)
all:
make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) modules
echo $(shell pwd)
clean:
make -C /lib/modules/$(KVERSION)/build M=$(shell pwd) clean
else
obj-m :=cwd_demo.o
endif

[虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(七)的更多相关文章

  1. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(九)

    目的 1. 使用verilog/vhdl设计一个PCI的watchdog设备. 2. 通过systemverilog 写testbench. 很久之前研究过AC97的verilog代码.但是很久没用v ...

  2. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(四)

    通过前面的操作,我们已经可以创建一个带有我们自己的PCI的watchdog外设qemu 虚拟机了. 目的: 1. 了解我们的外设情况. 2. 为在guest中开发我们自己的linux PCI驱动程序做 ...

  3. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(一)

    目的: 结合现在比较流行的技术,通过一个demo 展示一个全栈式设计的各种技能. 一个全栈式的工程师,应该能设计通过verilog/VHDL做logical设计.能写内核驱动,能架站. 要熟悉veri ...

  4. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(六)

    目的: 1. 为我们自己的watchdog写一个驱动 步骤: 通过之前的介绍,我们很容易猜想到写我们基于PCI的watchdog驱动,可以分2个步骤. 1. 探测加载PCI设备 这部分代码跟我们的设备 ...

  5. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(二)

    这篇文章的理解,需要一些专业知识了. 我们可以创建模拟自己的外设吗? 我们已经知道什么是qemu了,我们可以通过qmeu的提供的外设,DIY一个计算机了. 但是我们可能还不满足,我们可以自己制造一个外 ...

  6. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(八)

    目的: 1. 通过网页读取watchdog的信息 2. 通过网页设置watchdog 准备工作: 1. 选择一个web框架,选用 cherrypy $ sudo apt-get install pyt ...

  7. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(五)

    目的: 1. 了解PCI的基本知识,为完成watchdog的设备做准备. 准备知识: 简单的说,PCI 设备分3个空间. 配置空间,IO空间,内存地址空间. PCI设备厂家决定了外设是使用IO空间还是 ...

  8. [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(三)

    我们已经设计了一个基于qemu的watchdog了.下一步工作就是创建一个含有我们的watchdog的虚拟计算机器了. 准备工作: 1. 使用virt-manager或者virsh创建一个虚拟机器. ...

  9. 从零开始的全栈工程师——利用CSS3画一个正方体 ( css3 )

    transform属性 CSS3的变形(transform)属性让元素在一个坐标系统中变形.transform属性的基本语法如下: transform:none | <transform-fun ...

随机推荐

  1. SQL语句执行效率及分析

    查询效率分析:子查询为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询.在这种情况下可以考虑用联接查询来取代.如果要用子查询,那就用EXISTS替代IN.用NOT EXISTS替代NOT IN. ...

  2. 在PHP代码中处理JSON 格式的字符串的两种方法:

    总结: 在PHP代码中处理JSON 格式的字符串的两种方法: 方法一: $json= '[{"id":"1","name":"\u ...

  3. Python : 熟悉又陌生的字符编码(转自Python 开发者)

    Python : 熟悉又陌生的字符编码 字符编码是计算机编程中不可回避的问题,不管你用 Python2 还是 Python3,亦或是 C++, Java 等,我都觉得非常有必要厘清计算机中的字符编码概 ...

  4. [LeetCode]题解(python):004-Median of Two Sorted Arrays

    题目来源: https://leetcode.com/problems/median-of-two-sorted-arrays/ 题意分析: 这道题目是输入两个已经排好序的数组(长度为m,n),将这两 ...

  5. python中实现多线程的几种方式

    python实现多线程的方式大概有 1.threading 2._thread #!/usr/bin/python #!coding:utf-8 import threading def action ...

  6. Struts2的Stack Context和ValueStack

    1.提到Struts2的传值功能时,经常会见到Stack Context和ValueStack等概念,那么它们到底是什么,有什么作用呢. ValueStack(值栈):Struts2将OGNL上下文设 ...

  7. unigui数据库连接池

    UNIGUI for delphi,是一款WEB RIA开发框架.开发WEB程式如传统C/S般简单,众多DELPHIER趋之若鹜. 虽然上手非常容易,但要真正使用好,有些地方还是值得考究的. 网上有同 ...

  8. istream类的公有成员函数

    1 eatwhite 2 get 3 getline 4 gcount 5 ignore 6 operator>> 7 peek 8 read 9 seekg 10 tellg 1 eat ...

  9. arcgis for javascript之ArcGISDynamicMapServiceLayer图层控制的实现

    图层控制是非常多GIS系统里面必须的一个小功能,本文就说说arcgis for javascript下ArcGISDynamicMapServiceLayer图层控制的实现方式.首先看图: 实现效果 ...

  10. 自学XML DOM的几个例子

    XML DOM定义了如何获取.修改.添加和删除XML文件中结点的接口,极大方便了开发者对XML文件的使用.XML DOM教程和手册请转:http://www.w3school.com.cn/xmldo ...