● 字符设备。
● 块设备。
● 网络设备。
● 编写 Linux 设备驱动要求工程师有非常好的硬件基础,懂得 SRAM、 Flash、 SDRAM、磁盘的读写方式,UART、 I2C、 USB 等设备的接口以及轮询、中断、 DMA 的原理,PCI 总线的工作方式以及 CPU 的内存管理单元(MMU)等。
● 编写 Linux 设备驱动要求工程师有非常好的 C 语言基础,能灵活地运用 C 语言的结构体、指针、函数指针及内存动态申请和释放等。
● 编写 Linux 设备驱动要求工程师有一定的 Linux 内核基础,虽然并不要求工程师对内核各个部分有深入的研究,但至少要明白驱动与内核的接口。尤其是对于块设备、网络设备、 Flash 设备、串口设备等复杂设备,内核定义的驱动体系结构本身就非常复杂。
● 编写 Linux 设备驱动要求工程师有非常好的多任务并发控制和同步的基础,因为在驱动中会大量使用自旋锁、互斥、信号量、等待队列等并发与同步机制。
串口 、 I2C I 2 C 、SPI 、USB、以太网 、PCI 和 PCI-E 、SD 和 SDIO
版 本 | 时 间 | 特 点 |
---|---|---|
Linux 0.1 | 1991 年 10 月 | 最初的原型 |
Linux 1.0 | 1994 年 3 月 | 包含了 386 的官方支持,仅支持单 CPU 系统 |
Linux 1.2 | 1995 年 3 月 | 第一个包含多平台(Alpha、 Sparc、 MIPS 等)支持的官方版本 |
Linux 2.0 | 1996 年 6 月 | 包含很多新的平台支持,最重要的是,它是第一个支持 SMP(对称多处理器)体系的内核版本 |
Linux 2.2 | 1999 年 1 月 | 极大提升 SMP 系统上 Linux 的性能,并支持更多的硬件 |
Linux 2.4 | 2001 年 1 月 | 进一步提升了 SMP 系统的扩展性,同时也集成了很多用于支持桌面系统的特性: USB、 PC 卡(PCMCIA)的支持,内置的即插即用等 |
Linux 2.6.0 ~ 2.6.39 | 2003 年 12 月~2011 年 5 月 | 无论是对于企业服务器还是对于嵌入式系统, Linux 2.6 都是一个巨大的进步。对高端机器来说,新特性针对的是性能改进、可扩展性、吞吐率,以及对 SMP 机器 NUMA 的支持。对于嵌入式领域,添加了新的体系结构和处理器类型。包括对那些没有硬件控制的内存管理方案的无MMU 系统的支持。同样,为了满足桌面用户群的需要,添加了一整套新的音频和多媒体驱动程序 |
Linux 3.0 ~ 3.19、Linux 4.0-rc1 至今 | 2011 年 7 月至今 | 性能优化等 开发热点聚焦于虚拟化、新文件系统、 Android、新体系结构支持以及 |
insmod ./hello.ko
rmmod hello
lsmod
/proc/modules
/sys/module
static int __init hello_init(void)
{
...
return 0;
}
module_init(hello_init);
static void __exit hello_exit(void)
{
...
}
module_exit(hello_exit);
MODULE_AUTHOR("lin");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple param Module");
MODULE_ALIAS("a simplest module");
module_param(var, int, S_IRUGO);
EXPORT_SYMBOL_GPL(func);
(proc/kallsyms)//生成dev
MKDEV(int major, int minor); //major:0-19 minor:20-31
//获取设备号
MAJOR(dev_t dev)
MINOR(dev_t dev)
//cdev操作
void cdev_init(struct cdev *, struct file_operations *);
struct cdev* cdev_alloc(void);
void cdev_put(struct cdev *);
int cdev_add(struct cdev *, dev_t, unsigned);
void cdev_del(struct cdev *);
int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
int unregister_chrdev_region(dev_t from, unsigned count);
指令名 | 功能描述 |
---|---|
DMB | 数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作都执行完毕后,才提交(commit)在它后面的存储器访问操作。 |
DSB | 数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注) |
ISB | 指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。 |
local_irq_disable() local_irq_enable() //与自旋锁联合使用
local_irq_save(flags) local_irq_restore(flags)
local_bh_disable() local_bh_enable()
设置
void atomic_set(atomic_t *v, int i);
atomic_t ATOMIC_INIT(int i);
获取
int atomic_read(atomic_t *v);
加减
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
操作后测试(为0返回true,非0返回false)
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
操作后返回新值
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
spinlock_t lock;
spin_lock_init(lock);
spin_lock(lock);
spin_trylock(lock);
spin_unlock(lock);
spin_lock_irq(lock); spin_unlock_irq(lock);
spin_lock__irqsave(lock); spin_unlock_irqrestore(lock);
spin_lock_bh(lock); spin_unlock_bh(lock);
fd= open("/dev/ttyS1", O_RDWR | O_NONBLOCK);
fcntl(fd, F_SETFL, O_NONBLOCK);
//定义
wait_queue_head_t queue_head;
//初始化
init_waitqueue_head(&queue_head);
//定义及初始化
DECLARE_WAIT_QUEUE_HEAD(name)
//队列等待元素
DECLARE_WAITQUEUE(name, tsk)
//操作
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
//等待事件
wait_event(queue, condition)
wait_event_interruptible(queue, condition)
wait_event_timeout(queue, condition, timeout)
wait_event_interruptible_timeout(queue, condition, timeout)
//唤醒队列
void wake_up(wait_queue_head_t *q);
void wake_up_interruptible(wait_queue_head_t *q);
//睡眠
sleep_on(wait_queue_head_t *q);
interruptible_sleep_on(wait_queue_head_t *q);
static ssize_t xxx_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
...
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&xxx_wait, &wait);
/*等待设备缓冲区可写*/
do {
avail = device_writable();
if (avail < 0) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
ret = -ERESTARTSYS;
goto out;
}
}
} while (avail < 0);
device_write();
out:
remove_wait_queue(&xxx_wait, &wait);
set_current_state(TASK_RUNNING);
reutrn ret;
}
异步通知结构体
struct xxx_dev{
struct cdev cdev;
...
struct fasync_struct *async_queue;
}
static int xxx_fasync(int fd, struct file *filp, int mode)
{
struct xxx_dev *dev=file->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
//xxx_write
if(dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
//xxx_release
xxx_fasync(-1, filp, 0);
struct aiocb {
int aio_fildes; // File Descriptor
int aio_lio_opcode; // Valid only for lio_listio (r/w/nop)
volatile void *aio_buf; // Data Buffer
size_t aio_nbytes; // Number of Bytes in Data Buffer
struct sigevent aio_sigevent; // Notification Structure
/* Internal fields */
...
};
API 函数 | 说明 |
---|---|
aio_read |
int aio_read( struct aiocb *aiocbp ); 请求异步读操作 |
aio_error |
int aio_error( struct aiocb *aiocbp ); 检查异步请求的状态 |
aio_return |
ssize_t aio_return( struct aiocb *aiocbp ); 获得完成的异步请求的返回状态 |
aio_write |
int aio_write( struct aiocb *aiocbp ); 请求异步写操作 |
aio_suspend |
int aio_suspend( const struct aiocb *const cblist[], int n, const struct timespec *timeout ); 挂起调用进程,直到一个或多个异步请求已经完成(或失败) |
aio_cancel |
int aio_cancel( int fd, struct aiocb *aiocbp ); 取消异步 I/O 请求 |
lio_listio |
int lio_listio( int mode, struct aiocb *list[], int nent, struct sigevent *sig ); 发起一系列 I/O 操作 |
.dts:device tree source
1.1 Soc共用部分:.dtsi (/include/ “s3c24440.dtsi”)
1.2 模板
/* root节点 */
/ {
node1 {
a-string-property = "A string";
a-string-list-property = "first string", "second string";
a-byte-data-property = [0x01 0x23 0x34 0x56];
child-node1 {
first-child-property;
second-child-property = <1>;
a-string-property = "Hello, world";
};
child-node2 {
};
};
node2 {
an-empty-property;
a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
child-node1 {
};
};
};
.dtc:device tree compiler
.dtb:Device Tree Blob