2015-05-05 27 views
6

Kit: Beagle xương Black, Hệ điều hành: Angstrom, kernel:Làm thế nào để thêm chức năng fasync vào mã mô-đun hạt nhân?

[email protected]:~# uname -a 
Linux beaglebone 3.12.9-00018-g9bdb229-dirty #67 SMP Sat Apr 18 11:45:30 CST 2015 armv7l GNU/Linux 

Tôi muốn thêm fasync chức năng để mô-đun hạt nhân của tôi, nhưng nó không hoạt động tốt. Dưới đây là mã từ internet và tôi sửa đổi nó (cố gắng thêm fasync). Nó có thể chạy trên Beagle Bone Black. Tôi đơn giản hóa các hàm write(), read() và poll(). Và đặt kill_fasync() trong trình xử lý irq.

#include <linux/poll.h> 
#include <linux/sched.h> 
#include <linux/cdev.h> 
#include <linux/proc_fs.h> 
#include <linux/string.h> 
#include <linux/vmalloc.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include <linux/pci.h> 
#include <linux/input.h> 
#include <linux/platform_device.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/gpio.h> 
#include <linux/interrupt.h> 
#include <linux/io.h> 
#include <linux/irq.h> 

MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION("Fortune Cookie Kernel Module"); 
MODULE_AUTHOR("M. Tim Jones"); 

#define MAX_BUF_LENGTH  PAGE_SIZE 

static struct proc_dir_entry *proc_entry; 
static char *fortune_buf; // Space for fortune strings 
static int write_index; // Index to write next fortune 
static int read_index; // Index to read next fortune 

static DEFINE_SPINLOCK(fortune_lock); 
static DECLARE_WAIT_QUEUE_HEAD(fortune_wait); 
static volatile unsigned long fortune_data_flag; /* our output to the world */ 
static struct fasync_struct *fortune_async_queue = NULL; 


#define GPIO2_START_ADDR 0x481ac000 
#define GPIO2_SIZE (0x481adfff - GPIO2_START_ADDR) 

#define CM_PER_START_ADDR 0x44e00000 
#define CM_PER_SIZE  0x400 
#define CM_PER_GPIO2_CLKCTRL 0xb0 // page 948 

#define GPIO_IRQSTATUS_0 0x2c 
#define GPIO_IRQSTATUS_1 0x30 
#define GPIO_DATAIN  0x138 // page 4657 
#define GPIO_OE   0x134 // page 4656 
#define GPIO_FALLINGDETECT 0x14c 
#define GPIO_DEBOUNCENABLE 0x150 // page 4663 
#define GPIO_DEBOUNCINGTIME 0x154 // page 4664 

#define PIN_A_GPIO 68 // is on BBB connector P8 pin10/TIMER6/GPIO2_4  
#define PIN_A_FLAGS GPIOF_IN 
#define PIN_A_LABEL "HI_PIN_A" // when floating, its level is high, 3.19~3.20V 

#define PIN_B_GPIO 69 // is on BBB connector P8 pin9/TIMER5/GPIO2_5 
#define PIN_B_FLAGS GPIOF_IN 
#define PIN_B_LABEL "HI_PIN_B" 

void __iomem *mem; 

static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) 
{ 
    int regval; 
    int regval_a, regval_b; 

    regval = ioread32 (mem + GPIO_DATAIN); 
    printk (KERN_DEBUG "interrupt: Hello from irq_handler_pin_a. The GPIO b read value is %x - %d \n", regval, (regval & 0x20) >> 5); 
    regval_a = (regval & 0x10) >> 4; 
    regval_b = (regval & 0x20) >> 5; 

    printk(KERN_DEBUG "irq 0: fortune_async_queue is 0x%p", fortune_async_queue); 
    if(regval_a == regval_b) { 
     printk (KERN_DEBUG "interrupt: 1 \n"); 
    } else { 
     printk (KERN_DEBUG "interrupt: 2 \n"); 
    } 

    kill_fasync(&fortune_async_queue, SIGIO, POLL_IN); 
    printk(KERN_DEBUG "irq 1: fortune_async_queue is 0x%p", fortune_async_queue); 

    return IRQ_HANDLED; 
} 

static int gpio_interrupt_init (void) 
{ 
    ... 
} 

static void gpio_interrupt_exit(void) 
{ 
    printk ("HI: Releasing IRQ resources...\n"); 

    iounmap (mem); 
    free_irq (gpio_to_irq (PIN_A_GPIO), NULL); 
    gpio_free (PIN_A_GPIO); 
    gpio_free (PIN_B_GPIO); 

    printk (KERN_DEBUG "Goodbye gpio_interrupt!\n"); 
} 


ssize_t fortune_write(struct file *filp, const char __user *buff, 
         unsigned long len, void *data) 
{ 
    printk(KERN_INFO "fortune_write() executes\n"); 

    return len; 
} 

ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos) 
{ 
    int len; 
    printk(KERN_INFO "fortune_read() executes\n"); 

    return len; 
} 

static unsigned int fortune_poll(struct file *file, poll_table *wait) 
{ 
    printk(KERN_INFO "fortune_poll() executes\n"); 
    return 0; 
} 

static int fortune_fasync(int fd, struct file *file, int on) 
{ 
    printk("fortune_fasync() executes\n"); 
    if(!fortune_async_queue) 
    { 
     if (fasync_helper(fd, file, 1, &fortune_async_queue) >= 0) 
     { 
      printk(KERN_DEBUG "fasync 0: fasync_helper works. fortune_async_queue is 0x%p", fortune_async_queue); 
      return 0; 
     } 
     else 
     { 
      printk(KERN_DEBUG "fasync 1: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue); 
      return -EIO; 
     } 
    } 
    else 
    { 
     printk(KERN_DEBUG "fasync 2: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue); 
    } 

} 

static int fortune_release(struct inode *inode, struct file *file) 
{ 
    struct fortune_dev *devp; 

    devp = file->private_data; 
    fortune_fasync(-1, file, 0); 

    file->private_data = NULL; 
    return 0; 
} 
static int fortune_open(struct inode *inode, struct file *file) 
{ 
    return 0; 
} 

static const struct file_operations proc_test_fops = { 
    .owner  = THIS_MODULE, 
    .open   = fortune_open, 
    .read   = fortune_read, 
    .write  = fortune_write, 
    .poll   = fortune_poll, 
    .release  = fortune_release, 
    .fasync  = fortune_fasync, 
}; 

int __init init_fortune_module(void) 
{ 
    int ret = 0; 

    gpio_interrupt_init(); 

    fortune_buf = (char *)vmalloc(MAX_BUF_LENGTH); 
    if (!fortune_buf) { 
     ret = -ENOMEM; 
    } else { 
     memset(fortune_buf, 0, MAX_BUF_LENGTH); 
     proc_entry = proc_create("fortune", 0644, NULL, &proc_test_fops); 

     if (proc_entry == NULL) { 
      ret = -ENOMEM; 
      vfree(fortune_buf); 
      printk(KERN_INFO "fortune: Couldn't create proc entry\n"); 
     } else 
      write_index = 0; 
      read_index = 0; 
      printk(KERN_INFO "fortune: Module loaded.\n"); 
     } 

    return ret; 
} 

void __exit exit_fortune_module(void) 
{ 
    gpio_interrupt_exit(); 
    proc_remove(proc_entry); 
    vfree(fortune_buf); 
    printk(KERN_INFO "fortune: Module unloaded.\n"); 
} 

module_init(init_fortune_module); 
module_exit(exit_fortune_module); 

Tôi cũng tìm thấy mã không gian người dùng này, nó được biên dịch để a.out:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <poll.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <fcntl.h> 


int fd; 

void my_signal_io_fun(int signum) 
{ 
    printf("SIGIO occurs!\n"); 
} 

void my_signal_int_fun(int signum) 
{ 
    printf("signum: 0x%x\n", signum); 
    close(fd); 
    exit(signum); 
} 

int main(int argc, char **argv) 
{ 
    unsigned char key_val; 
    int ret; 
    int Oflags; 

    signal(SIGIO, my_signal_io_fun); 
    signal(SIGINT, my_signal_int_fun); 

    fd = open("/proc/fortune", O_RDWR); 
    if (fd < 0) 
    { 
     printf("can't open!\n"); 
    } 
    printf("open OK, fd = 0x%x\n", fd); 
    fcntl(fd, F_SETOWN, getpid()); 
    Oflags = fcntl(fd, F_GETFL); 
    fcntl(fd, F_SETFL, Oflags | FASYNC); 

    while (1) 
    { 
     sleep(1000); 
    } 

    return 0; 
} 

Và sau đó tôi tải lên các module để Beagle xương đen của tôi, làm như dưới đây:

[email protected]:~# insmod fasync_kernel.ko 
[email protected]:~# cat /proc/fortune 
[email protected]:~# ./a.out 
open OK, fd = 0x3 
SIGIO occurs! 
SIGIO occurs! 
SIGIO occurs! 
SIGIO occurs! 
^Csignum: 0x2 

Tôi thực hiện một số ngắt trên GPIO tương ứng và sau đó nó hiển thị SIGIO occurs!. Nhưng vấn đề là tôi phải thực hiện cat /proc/fortune trước khi chạy mã vùng người dùng (a.out). Và nó không phải lúc nào cũng hoạt động như trên. Thông thường tôi cần phải rmmod - insmod - cat - a.out cho hai lần và sau đó mã fasync có thể hoạt động. Các dmesg là dưới đây:

[ 5512.325893] fortune: Module loaded. 
[ 5514.950859] fortune_read() executes 
[ 5514.950932] fortune_fasync() executes 
[ 5518.915844] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1 
[ 5514.950961] fasync 0: fasync_helper works. fortune_async_queue is 0xdf63eb18 
[ 5518.915881] irq 0: fortune_async_queue is 0xdf63eb18 
[ 5518.915895] interrupt: 2 
[ 5518.915950] irq 1: fortune_async_queue is 0xdf63eb18 
[ 5519.610571] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1 
[ 5519.610601] irq 0: fortune_async_queue is 0xdf63eb18 
[ 5519.610612] interrupt: 2 
[ 5519.610666] irq 1: fortune_async_queue is 0xdf63eb18 
[ 5520.260265] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0 
[ 5520.260295] irq 0: fortune_async_queue is 0xdf63eb18 
[ 5520.260306] interrupt: 1 
[ 5520.260357] irq 1: fortune_async_queue is 0xdf63eb18 
[ 5521.185887] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0 
[ 5521.185916] irq 0: fortune_async_queue is 0xdf63eb18 
[ 5521.185926] interrupt: 1 
[ 5522.777769] fortune_fasync() executes 
[ 5521.185976] irq 1: fortune_async_queue is 0xdf63eb18 
[ 5522.777812] fasync 2: fasync_helper doesn't work. fortune_async_queue is 0xdf63eb18 

Câu hỏi của tôi là lý do tại sao tôi phải thực hiện cat /proc/fortune trước khi mã không gian người dùng thực hiện? Có cách nào tốt hơn không? Làm thế nào để làm cho nó chạy ổn định? Làm thế nào để tránh chạy vòng lặp (rmmod - insmod - cat - a.out) trong hai lần?

tôi thêm một số if-else xung quanh fortune_async_queue, bởi vì nếu tôi chỉ đơn giản sử dụng fasync_helper()kill_fasync(), fortune_async_queue sẽ luôn null. Và đối với func này: static int fortune_fasync(int fd, struct file *file, int on), tôi thấy rằng thông số cuối cùng của nó on luôn là 0, tại sao? Tôi phải đặt thủ công thành 1, như mã ở trên: fasync_helper(fd, file, 1, &fortune_async_queue)

Trả lời

2

Bạn đang sử dụng "insmod" chấp nhận đường dẫn để gửi nhưng phụ thuộc không được tải tự động. Do đó, bạn phải thực thi cat/proc/fortune trước khi mã không gian người dùng thực thi để tải các phụ thuộc.

Bạn có thể thử "modprobe" thay cho "insmod". Nó sẽ tải phụ thuộc theo mặc định.

Theo mặc định thông báo không đồng bộ cho bộ mô tả tệp bị tắt. Do đó, luôn bật = 0.

+1

Đối với câu cuối cùng của bạn, tôi không hiểu. Sau đó, trong điều kiện "trên" sẽ là 1? –

+0

Chúng ta có thể vượt qua = 1. –

Các vấn đề liên quan