张帅依的博客

积累点滴.

Linux驱动

交叉编译

编译ko文件

Makefile:
PWD=$(shell pwd)
KDIR=/xx/xx/linux-3.4

obj-m+=scr.o
scr-objs := file1.o file2.o test-scr.o

build:
    $(MAKE) -C $(KDIR) M=$(PWD)

clean:
    @rm -rf *.o *.ko *.cmd *.mod.c *.order *.symvers *.tmp_versions *~

执行编译:

make ARCH=arm CROSS_COMPILE=/xx/xx/arm-linux-gnueabi-

创建设备

class_create和device_create函数,在/dev下创建设备节点

int my_device_major = register_chrdev(0, "myDevice", &my_device_fops);
struct class* my_device_class = class_create(THIS_MODULE, "myDevice");
//在/sys/class下创建了myDevice目录
if (IS_ERR(my_device_class))
    return -1;
device_create(my_device_class, NULL, MKDEV(my_device_major, 0), NULL, "myDevice");
//在/dev下创建myDevice设备

自旋锁spinlock_t

spin_lock_irqsave会关闭中断

spinlock_t rx_slock;
spin_lock_init(&rx_slock);  //初始化
/* 使用 */
unsigned long flags;
spin_lock_irqsave(&rx_slock, flags);
...
//处理
...
spin_unlock_irqrestpre(&rx_slock, flags);

poll

驱动poll_wait

wait_queue_head_t rd_wq;
init_waitqueue_head(&rd_wq);

unsigned int test_poll(struct file *filp, struct poll_table_struct *wait){
    unsigned int ret = 0;
    poll_wait(filp, &rd_wq, wait);
    ...//处理
    if (hasData) ret |= POLLIN|POLLRDNORM;
    return ret;
}

当收到数后:wake_up_interruptible(&rd_wq);

应用poll

int fd = open("/dev/xxx", O_RDWR);
uint32_t timeout = xxxxx;
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
ret = poll(&pfd, 1, timeout);
if (ret!=1)
    return -1;
ret = read(fd, (void*)data, *size);

workqueue工作队列在中断中使用

使用:在有大量的中断处理中,需要紧急处理的中断直接在中断处理函数中进行,可以延迟处理的中断放到了workqueue中做,(不知这样对不对,我看网上还有一种tasklet)。workqueue的使用:

struct work_struct device_work;
struct workqueue_struct *device_wq;

void device_work_func(struct work_struct *work) {
    ...//处理中断的函数
}
//中断回调函数
irqreturn_t device_irq_service(int irqno, void *dev_id) {
    unsigned int temp;
    unsinged long flags;
    //加锁
    spin_lock_irqsave(&rx_slock, flags);
    temp = my_get_device_interrupt_status();//一般都可以从寄存器中读到中断状态
    if (temp&MY_DEVICE_IMMEDIATE) { //需要立即处理的紧急中断
        ...//中断处理
    } else {
        queue_work(device_wq, &device_work);
    }
    spin_unlock_irqrestpre(&rx_slock, flags);
}

//初始化
device_wq = create_singlethread_workqueue("device_wq");//只创建一个内核线程
INIT_WORK(&device_work, device_work_func);
request_irq(my_irq_no, device_irq_service, 0, "my_device", NULL);//注册中断服务

补充: 1. 中断处理中尽量不要加打印; 2. 在硬中断处理函数device_irq_service中不能使用mutex_lock,如果必须加锁可使用自旋锁spinlock_t; 在软中断 函数device_work_func中可以加mutex_lock