122 lines
2.7 KiB
C
122 lines
2.7 KiB
C
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/cdev.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
#include "bible.h"
|
|
|
|
MODULE_LICENSE("GPL"); //God's Parables and Liturgy
|
|
|
|
int init_module(void);
|
|
void cleanup_module(void);
|
|
static int device_open(struct inode *, struct file *);
|
|
static int device_release(struct inode *, struct file *);
|
|
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
|
|
static int on_dev_uevent(struct device*, struct kobj_uevent_env*);
|
|
|
|
#define DEVICE_NAME "bible"
|
|
|
|
static dev_t devt;
|
|
static struct class* device_class;
|
|
static struct device* device;
|
|
static struct cdev character_device;
|
|
|
|
static struct file_operations fops = {
|
|
.read = device_read,
|
|
.open = device_open,
|
|
.release = device_release
|
|
};
|
|
|
|
int init_module(void)
|
|
{
|
|
int result;
|
|
if((result = alloc_chrdev_region(&devt, 0, 1, DEVICE_NAME)) < 0)
|
|
{
|
|
printk(KERN_ALERT "Couldn't alloc chrdev region: %d\n", result);
|
|
|
|
return result;
|
|
}
|
|
|
|
if((device_class = class_create(THIS_MODULE, DEVICE_NAME)) == NULL)
|
|
{
|
|
printk(KERN_ALERT "Couldn't create device class\n");
|
|
|
|
unregister_chrdev_region(devt, 1);
|
|
return -1;
|
|
}
|
|
|
|
device_class->dev_uevent = on_dev_uevent;
|
|
|
|
if((device = device_create(device_class, NULL, devt, NULL, DEVICE_NAME)) == NULL)
|
|
{
|
|
printk(KERN_ALERT "Couldn't create device\n");
|
|
|
|
class_destroy(device_class);
|
|
unregister_chrdev_region(devt, 1);
|
|
return -1;
|
|
}
|
|
|
|
cdev_init(&character_device, &fops);
|
|
|
|
if((result = cdev_add(&character_device, devt, 1)) < 0)
|
|
{
|
|
printk(KERN_ALERT "Couldn't add character device\n");
|
|
|
|
device_destroy(device_class, devt);
|
|
class_destroy(device_class);
|
|
unregister_chrdev_region(devt, 1);
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cleanup_module(void)
|
|
{
|
|
device_destroy(device_class, devt);
|
|
class_destroy(device_class);
|
|
unregister_chrdev_region(devt, 1);
|
|
}
|
|
|
|
static int on_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
{
|
|
add_uevent_var(env, "DEVMODE=%#o", 0444);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int device_open(struct inode *inode, struct file *file)
|
|
{
|
|
try_module_get(THIS_MODULE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int device_release(struct inode *inode, struct file *file)
|
|
{
|
|
module_put(THIS_MODULE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset)
|
|
{
|
|
int i = 0;
|
|
|
|
if(*offset + length > bible_txt_len)
|
|
{
|
|
length = bible_txt_len - *offset;
|
|
}
|
|
|
|
for(; i < length; i++)
|
|
{
|
|
put_user(*(bible_txt + *offset + i), buffer + i);
|
|
}
|
|
|
|
*offset += length;
|
|
|
|
return i;
|
|
}
|