1912d0f0bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25bf2b193SStefani Seibold /*
35bf2b193SStefani Seibold * Sample kfifo byte stream implementation
45bf2b193SStefani Seibold *
55bf2b193SStefani Seibold * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
65bf2b193SStefani Seibold */
75bf2b193SStefani Seibold
85bf2b193SStefani Seibold #include <linux/init.h>
95bf2b193SStefani Seibold #include <linux/module.h>
105bf2b193SStefani Seibold #include <linux/proc_fs.h>
115bf2b193SStefani Seibold #include <linux/mutex.h>
125bf2b193SStefani Seibold #include <linux/kfifo.h>
135bf2b193SStefani Seibold
145bf2b193SStefani Seibold /*
155bf2b193SStefani Seibold * This module shows how to create a byte stream fifo.
165bf2b193SStefani Seibold */
175bf2b193SStefani Seibold
185bf2b193SStefani Seibold /* fifo size in elements (bytes) */
195bf2b193SStefani Seibold #define FIFO_SIZE 32
205bf2b193SStefani Seibold
215bf2b193SStefani Seibold /* name of the proc entry */
225bf2b193SStefani Seibold #define PROC_FIFO "bytestream-fifo"
235bf2b193SStefani Seibold
245bf2b193SStefani Seibold /* lock for procfs read access */
25*880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(read_access);
265bf2b193SStefani Seibold
275bf2b193SStefani Seibold /* lock for procfs write access */
28*880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(write_access);
295bf2b193SStefani Seibold
305bf2b193SStefani Seibold /*
315bf2b193SStefani Seibold * define DYNAMIC in this example for a dynamically allocated fifo.
325bf2b193SStefani Seibold *
335bf2b193SStefani Seibold * Otherwise the fifo storage will be a part of the fifo structure.
345bf2b193SStefani Seibold */
355bf2b193SStefani Seibold #if 0
365bf2b193SStefani Seibold #define DYNAMIC
375bf2b193SStefani Seibold #endif
385bf2b193SStefani Seibold
395bf2b193SStefani Seibold #ifdef DYNAMIC
405bf2b193SStefani Seibold static struct kfifo test;
415bf2b193SStefani Seibold #else
425bf2b193SStefani Seibold static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE);
435bf2b193SStefani Seibold #endif
445bf2b193SStefani Seibold
45a25effa4SAndrea Righi static const unsigned char expected_result[FIFO_SIZE] = {
462aaf2092SAndrea Righi 3, 4, 5, 6, 7, 8, 9, 0,
472aaf2092SAndrea Righi 1, 20, 21, 22, 23, 24, 25, 26,
482aaf2092SAndrea Righi 27, 28, 29, 30, 31, 32, 33, 34,
492aaf2092SAndrea Righi 35, 36, 37, 38, 39, 40, 41, 42,
502aaf2092SAndrea Righi };
512aaf2092SAndrea Righi
testfunc(void)525bf2b193SStefani Seibold static int __init testfunc(void)
535bf2b193SStefani Seibold {
545bf2b193SStefani Seibold unsigned char buf[6];
552aaf2092SAndrea Righi unsigned char i, j;
565bf2b193SStefani Seibold unsigned int ret;
575bf2b193SStefani Seibold
585bf2b193SStefani Seibold printk(KERN_INFO "byte stream fifo test start\n");
595bf2b193SStefani Seibold
605bf2b193SStefani Seibold /* put string into the fifo */
615bf2b193SStefani Seibold kfifo_in(&test, "hello", 5);
625bf2b193SStefani Seibold
635bf2b193SStefani Seibold /* put values into the fifo */
645bf2b193SStefani Seibold for (i = 0; i != 10; i++)
65498d319bSStefani Seibold kfifo_put(&test, i);
665bf2b193SStefani Seibold
675bf2b193SStefani Seibold /* show the number of used elements */
685bf2b193SStefani Seibold printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
695bf2b193SStefani Seibold
705bf2b193SStefani Seibold /* get max of 5 bytes from the fifo */
715bf2b193SStefani Seibold i = kfifo_out(&test, buf, 5);
725bf2b193SStefani Seibold printk(KERN_INFO "buf: %.*s\n", i, buf);
735bf2b193SStefani Seibold
745bf2b193SStefani Seibold /* get max of 2 elements from the fifo */
755bf2b193SStefani Seibold ret = kfifo_out(&test, buf, 2);
765bf2b193SStefani Seibold printk(KERN_INFO "ret: %d\n", ret);
775bf2b193SStefani Seibold /* and put it back to the end of the fifo */
785bf2b193SStefani Seibold ret = kfifo_in(&test, buf, ret);
795bf2b193SStefani Seibold printk(KERN_INFO "ret: %d\n", ret);
805bf2b193SStefani Seibold
815ddf8391SAndrea Righi /* skip first element of the fifo */
825ddf8391SAndrea Righi printk(KERN_INFO "skip 1st element\n");
835ddf8391SAndrea Righi kfifo_skip(&test);
845ddf8391SAndrea Righi
855bf2b193SStefani Seibold /* put values into the fifo until is full */
86498d319bSStefani Seibold for (i = 20; kfifo_put(&test, i); i++)
875bf2b193SStefani Seibold ;
885bf2b193SStefani Seibold
895bf2b193SStefani Seibold printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));
905bf2b193SStefani Seibold
91a25effa4SAndrea Righi /* show the first value without removing from the fifo */
92a25effa4SAndrea Righi if (kfifo_peek(&test, &i))
93a25effa4SAndrea Righi printk(KERN_INFO "%d\n", i);
94a25effa4SAndrea Righi
952aaf2092SAndrea Righi /* check the correctness of all values in the fifo */
962aaf2092SAndrea Righi j = 0;
972aaf2092SAndrea Righi while (kfifo_get(&test, &i)) {
98a25effa4SAndrea Righi printk(KERN_INFO "item = %d\n", i);
992aaf2092SAndrea Righi if (i != expected_result[j++]) {
1002aaf2092SAndrea Righi printk(KERN_WARNING "value mismatch: test failed\n");
1012aaf2092SAndrea Righi return -EIO;
1022aaf2092SAndrea Righi }
1032aaf2092SAndrea Righi }
1042aaf2092SAndrea Righi if (j != ARRAY_SIZE(expected_result)) {
1052aaf2092SAndrea Righi printk(KERN_WARNING "size mismatch: test failed\n");
1062aaf2092SAndrea Righi return -EIO;
1072aaf2092SAndrea Righi }
1082aaf2092SAndrea Righi printk(KERN_INFO "test passed\n");
1095bf2b193SStefani Seibold
1105bf2b193SStefani Seibold return 0;
1115bf2b193SStefani Seibold }
1125bf2b193SStefani Seibold
fifo_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1135bf2b193SStefani Seibold static ssize_t fifo_write(struct file *file, const char __user *buf,
1145bf2b193SStefani Seibold size_t count, loff_t *ppos)
1155bf2b193SStefani Seibold {
1165bf2b193SStefani Seibold int ret;
1175bf2b193SStefani Seibold unsigned int copied;
1185bf2b193SStefani Seibold
119*880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&write_access))
1205bf2b193SStefani Seibold return -ERESTARTSYS;
1215bf2b193SStefani Seibold
1225bf2b193SStefani Seibold ret = kfifo_from_user(&test, buf, count, &copied);
1235bf2b193SStefani Seibold
124*880732aeSSebastian Andrzej Siewior mutex_unlock(&write_access);
125926ee00eSDan Carpenter if (ret)
126926ee00eSDan Carpenter return ret;
1275bf2b193SStefani Seibold
128926ee00eSDan Carpenter return copied;
1295bf2b193SStefani Seibold }
1305bf2b193SStefani Seibold
fifo_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)1315bf2b193SStefani Seibold static ssize_t fifo_read(struct file *file, char __user *buf,
1325bf2b193SStefani Seibold size_t count, loff_t *ppos)
1335bf2b193SStefani Seibold {
1345bf2b193SStefani Seibold int ret;
1355bf2b193SStefani Seibold unsigned int copied;
1365bf2b193SStefani Seibold
137*880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&read_access))
1385bf2b193SStefani Seibold return -ERESTARTSYS;
1395bf2b193SStefani Seibold
1405bf2b193SStefani Seibold ret = kfifo_to_user(&test, buf, count, &copied);
1415bf2b193SStefani Seibold
142*880732aeSSebastian Andrzej Siewior mutex_unlock(&read_access);
143926ee00eSDan Carpenter if (ret)
144926ee00eSDan Carpenter return ret;
1455bf2b193SStefani Seibold
146926ee00eSDan Carpenter return copied;
1475bf2b193SStefani Seibold }
1485bf2b193SStefani Seibold
14997a32539SAlexey Dobriyan static const struct proc_ops fifo_proc_ops = {
15097a32539SAlexey Dobriyan .proc_read = fifo_read,
15197a32539SAlexey Dobriyan .proc_write = fifo_write,
15297a32539SAlexey Dobriyan .proc_lseek = noop_llseek,
1535bf2b193SStefani Seibold };
1545bf2b193SStefani Seibold
example_init(void)1555bf2b193SStefani Seibold static int __init example_init(void)
1565bf2b193SStefani Seibold {
1575bf2b193SStefani Seibold #ifdef DYNAMIC
1585bf2b193SStefani Seibold int ret;
1595bf2b193SStefani Seibold
1605bf2b193SStefani Seibold ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
1615bf2b193SStefani Seibold if (ret) {
1625bf2b193SStefani Seibold printk(KERN_ERR "error kfifo_alloc\n");
1635bf2b193SStefani Seibold return ret;
1645bf2b193SStefani Seibold }
1655bf2b193SStefani Seibold #else
1665bf2b193SStefani Seibold INIT_KFIFO(test);
1675bf2b193SStefani Seibold #endif
1682aaf2092SAndrea Righi if (testfunc() < 0) {
1692aaf2092SAndrea Righi #ifdef DYNAMIC
1702aaf2092SAndrea Righi kfifo_free(&test);
1712aaf2092SAndrea Righi #endif
1722aaf2092SAndrea Righi return -EIO;
1732aaf2092SAndrea Righi }
1745bf2b193SStefani Seibold
17597a32539SAlexey Dobriyan if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
1765bf2b193SStefani Seibold #ifdef DYNAMIC
1775bf2b193SStefani Seibold kfifo_free(&test);
1785bf2b193SStefani Seibold #endif
1795bf2b193SStefani Seibold return -ENOMEM;
1805bf2b193SStefani Seibold }
1815bf2b193SStefani Seibold return 0;
1825bf2b193SStefani Seibold }
1835bf2b193SStefani Seibold
example_exit(void)1845bf2b193SStefani Seibold static void __exit example_exit(void)
1855bf2b193SStefani Seibold {
1865bf2b193SStefani Seibold remove_proc_entry(PROC_FIFO, NULL);
1875bf2b193SStefani Seibold #ifdef DYNAMIC
1885bf2b193SStefani Seibold kfifo_free(&test);
1895bf2b193SStefani Seibold #endif
1905bf2b193SStefani Seibold }
1915bf2b193SStefani Seibold
1925bf2b193SStefani Seibold module_init(example_init);
1935bf2b193SStefani Seibold module_exit(example_exit);
1945bf2b193SStefani Seibold MODULE_LICENSE("GPL");
1955bf2b193SStefani Seibold MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");
196