blob: cfe40addda764f9a1353cb29eb6a11b551a1eec9 [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,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200151 .llseek = noop_llseek,
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700152};
153
154static int __init example_init(void)
155{
156#ifdef DYNAMIC
157 int ret;
158
159 ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
160 if (ret) {
161 printk(KERN_ERR "error kfifo_alloc\n");
162 return ret;
163 }
164#else
165 INIT_KFIFO(test);
166#endif
Andrea Righi2aaf2092010-08-19 14:13:29 -0700167 if (testfunc() < 0) {
168#ifdef DYNAMIC
169 kfifo_free(&test);
170#endif
171 return -EIO;
172 }
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700173
174 if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) {
175#ifdef DYNAMIC
176 kfifo_free(&test);
177#endif
178 return -ENOMEM;
179 }
180 return 0;
181}
182
183static void __exit example_exit(void)
184{
185 remove_proc_entry(PROC_FIFO, NULL);
186#ifdef DYNAMIC
187 kfifo_free(&test);
188#endif
189}
190
191module_init(example_init);
192module_exit(example_exit);
193MODULE_LICENSE("GPL");
194MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");