blob: 178061e87ffe47d39ac97a247071d896ff080e8a [file] [log] [blame]
Stefani Seibold5bf2b192010-08-10 18:03:39 -07001/*
2 * Sample kfifo byte stream implementation
3 *
4 * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
5 *
6 * Released under the GPL version 2 only.
7 *
8 */
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/proc_fs.h>
13#include <linux/mutex.h>
14#include <linux/kfifo.h>
15
16/*
17 * This module shows how to create a byte stream fifo.
18 */
19
20/* fifo size in elements (bytes) */
21#define FIFO_SIZE 32
22
23/* name of the proc entry */
24#define PROC_FIFO "bytestream-fifo"
25
26/* lock for procfs read access */
27static DEFINE_MUTEX(read_lock);
28
29/* lock for procfs write access */
30static DEFINE_MUTEX(write_lock);
31
32/*
33 * define DYNAMIC in this example for a dynamically allocated fifo.
34 *
35 * Otherwise the fifo storage will be a part of the fifo structure.
36 */
37#if 0
38#define DYNAMIC
39#endif
40
41#ifdef DYNAMIC
42static struct kfifo test;
43#else
44static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE);
45#endif
46
Andrea Righia25effa2010-08-19 14:13:30 -070047static const unsigned char expected_result[FIFO_SIZE] = {
Andrea Righi2aaf2092010-08-19 14:13:29 -070048 3, 4, 5, 6, 7, 8, 9, 0,
49 1, 20, 21, 22, 23, 24, 25, 26,
50 27, 28, 29, 30, 31, 32, 33, 34,
51 35, 36, 37, 38, 39, 40, 41, 42,
52};
53
Stefani Seibold5bf2b192010-08-10 18:03:39 -070054static int __init testfunc(void)
55{
56 unsigned char buf[6];
Andrea Righi2aaf2092010-08-19 14:13:29 -070057 unsigned char i, j;
Stefani Seibold5bf2b192010-08-10 18:03:39 -070058 unsigned int ret;
59
60 printk(KERN_INFO "byte stream fifo test start\n");
61
62 /* put string into the fifo */
63 kfifo_in(&test, "hello", 5);
64
65 /* put values into the fifo */
66 for (i = 0; i != 10; i++)
67 kfifo_put(&test, &i);
68
69 /* show the number of used elements */
70 printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
71
72 /* get max of 5 bytes from the fifo */
73 i = kfifo_out(&test, buf, 5);
74 printk(KERN_INFO "buf: %.*s\n", i, buf);
75
76 /* get max of 2 elements from the fifo */
77 ret = kfifo_out(&test, buf, 2);
78 printk(KERN_INFO "ret: %d\n", ret);
79 /* and put it back to the end of the fifo */
80 ret = kfifo_in(&test, buf, ret);
81 printk(KERN_INFO "ret: %d\n", ret);
82
Andrea Righi5ddf8392010-08-19 14:13:28 -070083 /* skip first element of the fifo */
84 printk(KERN_INFO "skip 1st element\n");
85 kfifo_skip(&test);
86
Stefani Seibold5bf2b192010-08-10 18:03:39 -070087 /* put values into the fifo until is full */
88 for (i = 20; kfifo_put(&test, &i); i++)
89 ;
90
91 printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));
92
Andrea Righia25effa2010-08-19 14:13:30 -070093 /* show the first value without removing from the fifo */
94 if (kfifo_peek(&test, &i))
95 printk(KERN_INFO "%d\n", i);
96
Andrea Righi2aaf2092010-08-19 14:13:29 -070097 /* check the correctness of all values in the fifo */
98 j = 0;
99 while (kfifo_get(&test, &i)) {
Andrea Righia25effa2010-08-19 14:13:30 -0700100 printk(KERN_INFO "item = %d\n", i);
Andrea Righi2aaf2092010-08-19 14:13:29 -0700101 if (i != expected_result[j++]) {
102 printk(KERN_WARNING "value mismatch: test failed\n");
103 return -EIO;
104 }
105 }
106 if (j != ARRAY_SIZE(expected_result)) {
107 printk(KERN_WARNING "size mismatch: test failed\n");
108 return -EIO;
109 }
110 printk(KERN_INFO "test passed\n");
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700111
112 return 0;
113}
114
115static ssize_t fifo_write(struct file *file, const char __user *buf,
116 size_t count, loff_t *ppos)
117{
118 int ret;
119 unsigned int copied;
120
121 if (mutex_lock_interruptible(&write_lock))
122 return -ERESTARTSYS;
123
124 ret = kfifo_from_user(&test, buf, count, &copied);
125
126 mutex_unlock(&write_lock);
127
128 return ret ? ret : copied;
129}
130
131static ssize_t fifo_read(struct file *file, char __user *buf,
132 size_t count, loff_t *ppos)
133{
134 int ret;
135 unsigned int copied;
136
137 if (mutex_lock_interruptible(&read_lock))
138 return -ERESTARTSYS;
139
140 ret = kfifo_to_user(&test, buf, count, &copied);
141
142 mutex_unlock(&read_lock);
143
144 return ret ? ret : copied;
145}
146
147static const struct file_operations fifo_fops = {
148 .owner = THIS_MODULE,
149 .read = fifo_read,
150 .write = fifo_write,
151};
152
153static int __init example_init(void)
154{
155#ifdef DYNAMIC
156 int ret;
157
158 ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
159 if (ret) {
160 printk(KERN_ERR "error kfifo_alloc\n");
161 return ret;
162 }
163#else
164 INIT_KFIFO(test);
165#endif
Andrea Righi2aaf2092010-08-19 14:13:29 -0700166 if (testfunc() < 0) {
167#ifdef DYNAMIC
168 kfifo_free(&test);
169#endif
170 return -EIO;
171 }
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700172
173 if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) {
174#ifdef DYNAMIC
175 kfifo_free(&test);
176#endif
177 return -ENOMEM;
178 }
179 return 0;
180}
181
182static void __exit example_exit(void)
183{
184 remove_proc_entry(PROC_FIFO, NULL);
185#ifdef DYNAMIC
186 kfifo_free(&test);
187#endif
188}
189
190module_init(example_init);
191module_exit(example_exit);
192MODULE_LICENSE("GPL");
193MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");