X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=hellochar.c;h=85510f793f657d06e828ea5aa1474a3aee38aa58;hb=76680d10903416190497df7dc25d4469401c53bb;hp=c2eecefc0477cbd9063b9ef84ea4ba363090c8bc;hpb=0c53df020c7b9a4bade2010a3eb260c4318e48f8;p=cascardo%2Fkernel%2Fsamples%2Fchar2%2F.git diff --git a/hellochar.c b/hellochar.c index c2eecef..85510f7 100644 --- a/hellochar.c +++ b/hellochar.c @@ -20,29 +20,96 @@ #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"); + down(&hello_mtx); + 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; + down(&hello_mtx); + 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; + down(&hello_mtx); + 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 +125,8 @@ add_out: kfree(dev); cdev_out: unregister_chrdev_region(devnum, 256); +reg_out: + kfree(hello); out: return r; } @@ -65,8 +134,8 @@ out: static void __exit ch_exit(void) { cdev_del(dev); - kfree(dev); unregister_chrdev_region(devnum, 256); + kfree(hello); } module_init(ch_init);