打开APP
未登录
开通VIP,畅享免费电子书等14项超值服
开通VIP
首页
好书
留言交流
下载APP
联系客服
为linux内核添加FPGA字符设备驱动程序
ccg_hz
>《待分类》
2018.04.20
关注
Linux中驱动程序位于操作系统和硬件之间,是连接操作系统与硬件之间的纽带,今天我们就来向Linux中添加一个简单的FPGA字符驱动程序。
I. Linux字符驱动程序简介
在Linux中驱动程序分为字符驱动,块设备驱动,网络设备驱动三种,字符设备驱动是其中比较简单的一种。字符设备是指只能一个字节一个字节进行读写操作的设备,不能随机读取设备中的某一数据、读取数据要按照先后数据。
II.添加字符驱动程序的步骤
1. 获取字符设备号
在linux中我们通过cat /proc/devices 命令即可查看到各种设备以及其对应的设备编号。在内核中,我们通常用如下两个函数来获取设备编号
点击(
此处
)折叠或打开
int
register_chrdev_region
(
dev_t first
,
unsigned
int
count
,
char
*
name
)
;
/
*
参数:
dev_t first
-
要申请的设备号(起始)
unsigned
int
count
-
要申请的设备号数量
const char
*
name
-
设备名
返回值:
成功:0
失败:负数
需要事先知道哪个设备号没有被占用!!!
*
/
点击(
此处
)折叠或打开
int
alloc_chrdev_region
(
dev_t
*
dev
,
unsigned
int
firstminor
,
unsigned
int
count
,
char
*
name
)
;
/
*
参数:
dev_t
*
dev
-
用于保存分配到的第一个设备号(起始)
unsigned
int
firstminor
-
起始次设备号
unsigned
int
count
-
要分配设备号的数量
char
*
name
-
设备名
返回值:
成功:0
失败:负数(绝对值是错误码)
不需要事先知道哪个设备号被占用,系统会根据实际情况自行分配
*
/
2. 向cdev结构体注册文件操作
在Linux内核代码中,字符设备的描述通常是由struct cdev来完成的,其中有一个成员是一个指向file_operations的指针,我们将来想要像操作普通文件一样操作硬件设备,就需要完成file_operations中的.open, .read, .write, .release, .llseek函数,将它们映射成具体的硬件设备操作,如下代码所示
点击(
此处
)折叠或打开
static
const
struct file_operations fpga_fops
=
{
.
read
=
fpga_read
,
.
write
=
fpga_write
,
.
llseek
=
fpga_llseek
,
.
open
=
fpga_open
,
.
release
=
fpga_release
,
}
;
定义完文件操作之后,就需要将文件操作注册到cdev结构体之后就需要向内核注册设备驱动,代码如下:
点击(
此处
)折叠或打开
cdev_init
(
&
fpga_dev
,
&
fpga_fops
)
;
/
*
initialize your device settings
*
/
ret
=
cdev_add
(
&
fpga_dev
,
fpga_no
,
1
)
;
/
*
register your device
to
the kernel
*
/
III. FPGA地址映射以及读写通信
在我写的这个字符驱动程序中,我是用的ioremap()函数来实现地址映射,
这里需要注意的是:要根据自己核心板的FPGA使能引脚和地址引脚来确定实际地址切不可盲目拷贝
;copy_to_user()和copy_from_user()函数来实现FPGA的读写操作,具体见代码:
点击(
此处
)折叠或打开
#include
<
linux
/
init
.
h
>
#include
<
linux
/
fs
.
h
>
#include
<
linux
/
kernel
.
h
>
#include
<
linux
/
module
.
h
>
#include
<
linux
/
cdev
.
h
>
#include
<
linux
/
errno
.
h
>
#include
<
linux
/
device
.
h
>
#include
<
asm
/
io
.
h
>
#include
<
asm
/
uaccess
.
h
>
#define FPGA_BASE_ADDR 0xF0000000
#define FPGA_SIZE 0x4000000
#define DEV_NAME
"fpga"
struct cdev fpga_dev
;
dev_t fpga_no
;
struct
class
*
fpga_class
;
static char
*
fpga_addr
=
NULL
;
static
int
fpga_open
(
struct inode
*
ino
,
struct file
*
filp
)
;
static
int
fpga_release
(
struct inode
*
ino
,
struct file
*
filp
)
;
static loff_t fpga_llseek
(
struct file
*
,
loff_t
,
int
)
;
static ssize_t fpga_read
(
struct file
*
,
char __user
*
,
size_t
,
loff_t
*
)
;
static ssize_t fpga_write
(
struct file
*
,
const
char __user
*
,
size_t
,
loff_t
*
)
;
static
const
struct file_operations fpga_fops
=
{
.
read
=
fpga_read
,
.
write
=
fpga_write
,
.
llseek
=
fpga_llseek
,
.
open
=
fpga_open
,
.
release
=
fpga_release
,
}
;
static
int
fpga_open
(
struct inode
*
ino
,
struct file
*
filp
)
{
return 0
;
}
static
int
fpga_release
(
struct inode
*
ino
,
struct file
*
filp
)
{
return 0
;
}
static loff_t fpga_llseek
(
struct file
*
file
,
loff_t off
,
int
whence
)
{
if
(
fpga_addr
)
iounmap
(
fpga_addr
)
;
if
(
off
<
=
FPGA_SIZE
)
fpga_addr
=
ioremap
(
FPGA_BASE_ADDR
+
off
,
FPGA_SIZE
-
off
)
;
return off
;
}
static ssize_t fpga_read
(
struct file
*
file
,
char __user
*
buf
,
size_t count
,
loff_t
*
ppos
)
{
printk
(
"user data: %x"
,
buf
[
0
]
)
;
printk
(
"kern data: %x"
,
fpga_addr
[
0
]
)
;
if
(
copy_to_user
(
buf
,
fpga_addr
,
count
)
)
return
-
EFAULT
;
return count
;
}
static ssize_t fpga_write
(
struct file
*
file
,
const
char __user
*
buf
,
size_t count
,
loff_t
*
ppos
)
{
printk
(
"user data: %x"
,
buf
[
0
]
)
;
printk
(
"kern data: %x"
,
fpga_addr
[
0
]
)
;
if
(
copy_from_user
(
fpga_addr
,
buf
,
count
)
)
return
-
EFAULT
;
printk
(
"kern data: %x"
,
fpga_addr
[
0
]
)
;
return count
;
}
static
int
__init fpga_init
(
void
)
{
int
ret
;
ret
=
alloc_chrdev_region
(
&
fpga_no
,
0
,
1
,
"fpga"
)
;
/
*
device num you
get
,
from where
to
allocate
,
num of this kind of device
,
device name
*
/
if
(
ret
)
{
printk
(
"alloc_chrdev_region failed!\n"
)
;
unregister_chrdev_region
(
fpga_no
,
1
)
;
/
*
first device number
,
num of this kind of device
*
/
return ret
;
}
else
{
printk
(
"alloc_chrdev_region success!\n"
)
;
}
cdev_init
(
&
fpga_dev
,
&
fpga_fops
)
;
/
*
initialize your device settings
*
/
ret
=
cdev_add
(
&
fpga_dev
,
fpga_no
,
1
)
;
/
*
register your device
to
the kernel
*
/
if
(
ret
)
{
printk
(
"fpga dev add fail.\n"
)
;
unregister_chrdev_region
(
fpga_no
,
1
)
;
return ret
;
}
else
{
printk
(
"fpga dev add success!\n"
)
;
}
/
*
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
add module
to
/
dev
/
fpga
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
*
/
fpga_class
=
class_create
(
THIS_MODULE
,
"fpga"
)
;
device_create
(
fpga_class
,
NULL
,
fpga_no
,
NULL
,
"fpga"
)
;
/
*
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
address mapping
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
*
/
fpga_addr
=
ioremap
(
FPGA_BASE_ADDR
,
FPGA_SIZE
)
;
if
(
fpga_addr
)
{
printk
(
"ioremap success~\n"
)
;
}
else
{
unregister_chrdev_region
(
fpga_no
,
1
)
;
return
-
ENODEV
;
}
return 0
;
}
static void __exit fpga_exit
(
void
)
{
if
(
fpga_addr
)
iounmap
(
fpga_addr
)
;
cdev_del
(
&
fpga_dev
)
;
unregister_chrdev_region
(
fpga_no
,
1
)
;
printk
(
"fpga dev exit success!\n"
)
;
}
module_init
(
fpga_init
)
;
将上述代码编入内核,便可使用cat /proc/devices 来看到fpga设备以及其设备号,并且可以在/dev/目录下查看到fpga啦~~~
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报
。
打开APP,阅读全文并永久保存
查看更多类似文章
猜你喜欢
类似文章
【热】
打开小程序,算一算2024你的财运
创建字符设备 生成设备节点,linux,系统
CSDN技术中心 Linux 2.6 驱动设计快速入门!
6410ADC驱动
中断底半部&顶半部tasklet 与 workqueue
按键中断驱动
通过一个LED驱动程序开始学写Linux字符设备驱动
更多类似文章 >>
生活服务
热点新闻
留言交流
回顶部
联系我们
分享
收藏
点击这里,查看已保存的文章
导长图
关注
一键复制
下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!
联系客服
微信登录中...
请勿关闭此页面
先别划走!
送你5元优惠券,购买VIP限时立减!
5
元
优惠券
优惠券还有
10:00
过期
马上使用
×