#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#define DEVICE_NAME "kbdozgur"
#define CLASS_NAME "kbdozgur"
MODULE_AUTHOR("Mehmet Ozgur Bayhan");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Interrupt buffering skeleton");
MODULE_VERSION("0.2");
#define BUFFER_SIZE 20
static unsigned char bfr[BUFFER_SIZE];
static int bufferCounter = 0;
static int majorNumber;
static char message[BUFFER_SIZE] = { 0 };
static short size_of_message;
static int numberOpens = 0;
static struct class* kbdozgurcharClass = NULL;
static struct device* kbdozgurcharDevice = NULL;
static int dev_release(struct inode *, struct file *);
static ssize_t dev_read(struct file *, char *, size_t, loff_t *);
static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);
static struct file_operations fops = { .open = dev_open, .read = dev_read, .write = dev_write, .release = dev_release, };
irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
static unsigned char scancode;
//Read keyboard status
scancode = inb(0x60);
if (scancode == 0x01) {
printk(KERN_INFO "MOB: Inputs are > %s\n", bfr);
bufferCounter = 0;
memset(&bfr[0], 0, sizeof(bfr));
}
else if (scancode == 0x1E) {
bfr[bufferCounter] = 'a';
bufferCounter++;
}
else if (scancode == 0x1F) {
bfr[bufferCounter] = 's';
bufferCounter++;
}
else if (scancode == 0x20) {
bfr[bufferCounter] = 'd';
bufferCounter++;
}
else if (scancode == 0x21) {
bfr[bufferCounter] = 'f';
bufferCounter++;
}
else if (scancode == 0x22) {
bfr[bufferCounter] = 'g';
bufferCounter++;
}
else if (scancode == 0x23) {
bfr[bufferCounter] = 'h';
bufferCounter++;
}
else if (scancode == 0x24) {
bfr[bufferCounter] = 'j';
bufferCounter++;
}
if (bufferCounter >= BUFFER_SIZE) {
bufferCounter = 0;
memset(&bfr[0], 0, sizeof(bfr));
}
return (irq_handler_t) IRQ_HANDLED;
}
static int init_mod(void) {
int result;
/*
*****************************
* Create Character device
*****************************
*/
// Try to dynamically allocate a major number for the device
majorNumber = register_chrdev(0, DEVICE_NAME, &fops);
if (majorNumber < 0) {
printk(KERN_ALERT "MOB: kbdozgurcharClass failed to register a major number\n");
return majorNumber;
}
printk(KERN_INFO "MOB: registered correctly with major number %d\n", majorNumber);
// Register the device class
kbdozgurcharClass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(kbdozgurcharClass)) { // Check for error and clean up if there is
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "MOB: Failed to register device class\n");
return PTR_ERR(kbdozgurcharClass); // Correct way to return an error on a pointer
}
printk(KERN_INFO "MOB: device class registered correctly\n");
// Register the device driver
kbdozgurcharDevice = device_create(kbdozgurcharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(kbdozgurcharDevice)) { // Clean up if there is an error
class_destroy(kbdozgurcharClass); // Repeated code but the alternative is goto statements
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "MOB: Failed to create the device\n");
return PTR_ERR(kbdozgurcharDevice);
}
printk(KERN_INFO "MOB: device class created correctly\n"); // Made it! device was initialized
/*
*****************************
* Bind interrupt
*****************************
*/
result = request_irq(1, (irq_handler_t) irq_handler, IRQF_SHARED, "kbdozgur", (void *) (irq_handler));
if (result) printk(KERN_INFO "MOB: can't get shared interrupt for keyboard\n");
printk(KERN_INFO "MOB: kbdozgur loaded.\n");
return result;
}
static void exit_mod(void) {
/*
* ****************************
* Destroy Character Device
* ****************************
*/
device_unregister(kbdozgurcharDevice);
device_destroy(kbdozgurcharClass, MKDEV(majorNumber, 0)); // remove the device
class_unregister(kbdozgurcharClass); // unregister the device class
class_destroy(kbdozgurcharClass); // remove the device class
unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number
printk(KERN_INFO "MOB: Goodbye from the LKM!\n");
/*
* ****************************
* Free IRQ bind
* ****************************
*/
free_irq(1, (void *) (irq_handler));
printk(KERN_INFO "MOB: kbdozgur unloaded.\n");
}
static int dev_open(struct inode *inodep, struct file *filep) {
numberOpens++;
printk(KERN_INFO "MOB: Device has been opened %d time(s)\n", numberOpens);
return 0;
}
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
int error_count = 0;
// copy_to_user has the format ( * to, *from, size) and returns 0 on success
// error_count = copy_to_user(buffer, message, size_of_message);
error_count = copy_to_user(buffer, "test", 4);
if (error_count == 0) { // if true then have success
// printk(KERN_INFO "MOB: Sent %d characters to the user >> %s\n", size_of_message, message);
printk(KERN_INFO "MOB: Sent %d characters to the user >> %s\n", 4, "test");
return (size_of_message = 0); // clear the position to the start and return 0
}
else {
printk(KERN_INFO "MOB: Failed to send %d characters to the user\n", error_count);
return -EFAULT; // Failed -- return a bad address message (i.e. -14)
}
}
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) {
sprintf(message, "%s(%d letters)", buffer, len); // appending received string with its length
size_of_message = strlen(message); // store the length of the stored message
printk(KERN_INFO "MOB: Received %d characters from the user\n", len);
return len;
}
static int dev_release(struct inode *inodep, struct file *filep) {
printk(KERN_INFO "MOB: Device successfully closed\n");
return 0;
}
module_init(init_mod);
module_exit(exit_mod);
我正在尝试构建一个用于中断缓冲和服务于用户空间的框架驱动程序。
但是我的角色设备会将空字符串返回给用户空间。我在shell中尝试了 cat ,在python中尝试了打开和读取。两者都返回空字符串。顺便说一下,它正常地从用户空间获取字符数组,并且正如我预期的那样。
相关部分&gt;&gt;
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
int error_count = 0;
// copy_to_user has the format ( * to, *from, size) and returns 0 on success
// error_count = copy_to_user(buffer, message, size_of_message);
error_count = copy_to_user(buffer, "test", 4);
if (error_count == 0) { // if true then have success
// printk(KERN_INFO "MOB: Sent %d characters to the user >> %s\n", size_of_message, message);
printk(KERN_INFO "MOB: Sent %d characters to the user >> %s\n", 4, "test");
return (size_of_message = 0); // clear the position to the start and return 0
}
else {
printk(KERN_INFO "MOB: Failed to send %d characters to the user\n", error_count);
return -EFAULT; // Failed -- return a bad address message (i.e. -14)
}
}
首先我试过了:
error_count = copy_to_user(buffer, message, size_of_message);
然后我试着检查:
error_count = copy_to_user(buffer, "test", 4);
同样的故事。两者都返回空字符串。没有错误。在dmesg中没有任何相关内容。
我以root用户身份进行试用,文件具有以下权限:
crw------- 1 root root 250, 0 Mar 30 14:43 /dev/kbdozgur
那我哪里做错了?
答案 0 :(得分:3)
read
应该返回读取的字节数。在您的情况下,您将返回0。
size_message = 0
您应该执行以下操作
size_t size_requested;
...
if (len >= size_of_message) {
size_requested = size_of_message;
} else {
size_requested = len;
}
if (copy_to_user (buf, message, size_requested)) {
retval = -EFAULT;
return retval
}
return size_requested;