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