X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=hellochar.c;h=628f53cd32c208fcc4c3b6f9a5478acc75ff59f0;hb=0ac89f0fe059f1985e9ad39c15794938b5eda7fd;hp=c2eecefc0477cbd9063b9ef84ea4ba363090c8bc;hpb=0c53df020c7b9a4bade2010a3eb260c4318e48f8;p=cascardo%2Fkernel%2Fsamples%2Fchar2%2F.git diff --git a/hellochar.c b/hellochar.c index c2eecef..628f53c 100644 --- a/hellochar.c +++ b/hellochar.c @@ -20,29 +20,99 @@ #include #include #include +#include +#include MODULE_LICENSE("GPL"); +#define MAXLEN 4000 static dev_t devnum; static struct cdev *dev; +static const char default_greeting[] = "Hello, World!\n"; + +struct hello_buffer { + size_t len; + char buffer[0]; +}; +static struct hello_buffer *hello; +static DECLARE_MUTEX(hello_mtx); static int hello_open(struct inode *ino, struct file *fp) { - printk(KERN_DEBUG "Hello, World!\n"); + if (down_interruptible(&hello_mtx)) + return -ERESTARTSYS; + if (fp->f_flags & O_TRUNC) { + memset(hello->buffer, 0, MAXLEN); + hello->len = 0; + } + if (fp->f_flags & O_APPEND) + fp->f_pos = hello->len; + up(&hello_mtx); + return 0; +} + +static ssize_t hello_read(struct file *fp, char __user *buf, size_t sz, + loff_t *pos) +{ + int r; + if (down_interruptible(&hello_mtx)) + return -ERESTARTSYS; + if (sz + *pos > hello->len) + sz = hello->len - *pos; + r = copy_to_user(buf, hello->buffer + *pos, sz); + up(&hello_mtx); + if (r) + return -EFAULT; + *pos += sz; + return sz; +} + +static ssize_t hello_write(struct file *fp, const char __user *buf, size_t sz, + loff_t *pos) +{ + int r; + if (down_interruptible(&hello_mtx)) + return -ERESTARTSYS; + if (sz + *pos > MAXLEN) + sz = MAXLEN - *pos; + r = copy_from_user(hello->buffer + *pos, buf, sz); + if (r) { + up(&hello_mtx); + return -EFAULT; + } + *pos += sz; + if (hello->len < *pos) + hello->len = *pos; + up(&hello_mtx); + return sz; +} + +static int hello_release(struct inode *ino, struct file *fp) +{ return 0; } static const struct file_operations hello_fops = { .owner = THIS_MODULE, .open = hello_open, + .release = hello_release, + .read = hello_read, + .write = hello_write, }; static int __init ch_init(void) { int r = 0; + hello = kzalloc(sizeof(*hello) + MAXLEN, GFP_KERNEL); + if (!hello) { + r = -ENOMEM; + goto out; + } + memcpy(hello->buffer, default_greeting, sizeof(default_greeting)); + hello->len = sizeof(default_greeting); r = alloc_chrdev_region(&devnum, 0, 256, "hello"); if (r) - goto out; + goto reg_out; dev = cdev_alloc(); if (!dev) { r = -ENOMEM; @@ -58,6 +128,8 @@ add_out: kfree(dev); cdev_out: unregister_chrdev_region(devnum, 256); +reg_out: + kfree(hello); out: return r; } @@ -65,8 +137,8 @@ out: static void __exit ch_exit(void) { cdev_del(dev); - kfree(dev); unregister_chrdev_region(devnum, 256); + kfree(hello); } module_init(ch_init);