X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=hellochar.c;h=de99828ade010e78ce3e1cccb7a789db82addbd8;hb=91e474b7d6c004d5c0d3c5c1ff94721ad64d442d;hp=e49565c25182c5a4add644a172b666be8937c39f;hpb=37ece574b686c8c3631c49bc4068520984a6d949;p=cascardo%2Fkernel%2Fsamples%2Fchar2%2F.git diff --git a/hellochar.c b/hellochar.c index e49565c..de99828 100644 --- a/hellochar.c +++ b/hellochar.c @@ -20,20 +20,78 @@ #include #include #include +#include +#include +#include MODULE_LICENSE("GPL"); +#define MAXLEN 4096 static dev_t devnum; static struct cdev *dev; +static const char default_greeting[] = "Hello, World!\n"; + +static struct circ_buf *hello; +static struct circ_buf hello_instance; +static DEFINE_MUTEX(hello_mtx); static int hello_open(struct inode *ino, struct file *fp) { - printk(KERN_DEBUG "Hello, World!\n"); return 0; } static ssize_t hello_read(struct file *fp, char __user *buf, size_t sz, loff_t *pos) +{ + int r; + size_t fsz; + size_t ssz; + size_t len; + if (mutex_lock_interruptible(&hello_mtx)) + return -ERESTARTSYS; + len = CIRC_CNT(hello->head, hello->tail, MAXLEN); + if (sz > len) + sz = len; + /* First, copy at most until the limit of the buffer */ + fsz = min(sz, CIRC_CNT_TO_END(hello->head, hello->tail, MAXLEN)); + r = copy_to_user(buf, hello->buf + hello->tail, fsz); + ssz = sz - fsz; + if (!r && !ssz) + r = copy_to_user(buf + fsz, hello->buf, ssz); + if (!r) + hello->tail = (hello->tail + sz) & ~MAXLEN; + mutex_unlock(&hello_mtx); + if (r) + return -EFAULT; + return sz; +} + +static ssize_t hello_write(struct file *fp, const char __user *buf, size_t sz, + loff_t *pos) +{ + int r; + size_t fsz; + size_t ssz; + size_t len; + if (mutex_lock_interruptible(&hello_mtx)) + return -ERESTARTSYS; + len = CIRC_SPACE(hello->head, hello->tail, MAXLEN); + if (sz > len) + sz = len; + fsz = min(sz, CIRC_SPACE_TO_END(hello->head, hello->tail, MAXLEN)); + r = copy_from_user(hello->buf + hello->head, buf, fsz); + ssz = sz - fsz; + if (!r && !ssz) + r = copy_from_user(hello->buf, buf + fsz, ssz); + if (!r) + hello->head = (hello->head + sz) & ~MAXLEN; + mutex_unlock(&hello_mtx); + if (r) + return -EFAULT; + return sz; +} + +static int hello_release(struct inode *ino, struct file *fp) { return 0; } @@ -41,15 +99,25 @@ static ssize_t hello_read(struct file *fp, char __user *buf, size_t sz, 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 = &hello_instance; + hello->buf = kzalloc(sizeof(*hello) + MAXLEN, GFP_KERNEL); + if (!hello) { + r = -ENOMEM; + goto out; + } + memcpy(hello->buf, default_greeting, sizeof(default_greeting)); + hello->head = 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; @@ -59,12 +127,13 @@ static int __init ch_init(void) r = cdev_add(dev, devnum, 256); if (r) goto add_out; - printk(KERN_DEBUG "Allocate major %d\n", MAJOR(devnum)); return 0; add_out: kfree(dev); cdev_out: unregister_chrdev_region(devnum, 256); +reg_out: + kfree(hello); out: return r; } @@ -73,6 +142,7 @@ static void __exit ch_exit(void) { cdev_del(dev); unregister_chrdev_region(devnum, 256); + kfree(hello); } module_init(ch_init);