2010-08-11 05:03:39 +04:00
/*
* Sample fifo dma implementation
*
* Copyright ( C ) 2010 Stefani Seibold < stefani @ seibold . net >
*
* Released under the GPL version 2 only .
*
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/kfifo.h>
/*
* This module shows how to handle fifo dma operations .
*/
/* fifo size in elements (bytes) */
# define FIFO_SIZE 32
static struct kfifo fifo ;
static int __init example_init ( void )
{
int i ;
unsigned int ret ;
2010-10-01 02:15:27 +04:00
unsigned int nents ;
2010-08-11 05:03:39 +04:00
struct scatterlist sg [ 10 ] ;
printk ( KERN_INFO " DMA fifo test start \n " ) ;
if ( kfifo_alloc ( & fifo , FIFO_SIZE , GFP_KERNEL ) ) {
2010-08-20 01:13:30 +04:00
printk ( KERN_WARNING " error kfifo_alloc \n " ) ;
return - ENOMEM ;
2010-08-11 05:03:39 +04:00
}
printk ( KERN_INFO " queue size: %u \n " , kfifo_size ( & fifo ) ) ;
kfifo_in ( & fifo , " test " , 4 ) ;
for ( i = 0 ; i ! = 9 ; i + + )
2013-11-15 02:32:17 +04:00
kfifo_put ( & fifo , i ) ;
2010-08-11 05:03:39 +04:00
/* kick away first byte */
2010-08-20 01:13:30 +04:00
kfifo_skip ( & fifo ) ;
2010-08-11 05:03:39 +04:00
printk ( KERN_INFO " queue len: %u \n " , kfifo_len ( & fifo ) ) ;
2010-08-20 01:13:30 +04:00
/*
* Configure the kfifo buffer to receive data from DMA input .
*
* . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
* | 0 | 1 | 2 | . . . | 12 | 13 | . . . | 31 |
* | - - - | - - - - - - - - - - - - - - - - - - | - - - - - - - - - - - - - - - |
* \ _ / \ ________________ / \ _____________ /
* \ \ \
* \ \ _allocated data \
* \ _ * free space * \ _ * free space *
*
* We need two different SG entries : one for the free space area at the
* end of the kfifo buffer ( 19 bytes ) and another for the first free
* byte at the beginning , after the kfifo_skip ( ) .
*/
2010-08-20 01:13:29 +04:00
sg_init_table ( sg , ARRAY_SIZE ( sg ) ) ;
2010-10-01 02:15:27 +04:00
nents = kfifo_dma_in_prepare ( & fifo , sg , ARRAY_SIZE ( sg ) , FIFO_SIZE ) ;
printk ( KERN_INFO " DMA sgl entries: %d \n " , nents ) ;
if ( ! nents ) {
2010-08-20 01:13:30 +04:00
/* fifo is full and no sgl was created */
printk ( KERN_WARNING " error kfifo_dma_in_prepare \n " ) ;
return - EIO ;
}
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* receive data */
printk ( KERN_INFO " scatterlist for receive: \n " ) ;
2010-10-01 02:15:27 +04:00
for ( i = 0 ; i < nents ; i + + ) {
2010-08-20 01:13:30 +04:00
printk ( KERN_INFO
" sg[%d] -> "
2017-07-13 00:34:22 +03:00
" page %p offset 0x%.8x length 0x%.8x \n " ,
i , sg_page ( & sg [ i ] ) , sg [ i ] . offset , sg [ i ] . length ) ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
if ( sg_is_last ( & sg [ i ] ) )
break ;
}
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* put here your code to setup and exectute the dma operation */
/* ... */
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* example: zero bytes received */
ret = 0 ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* finish the dma operation and update the received data */
kfifo_dma_in_finish ( & fifo , ret ) ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* Prepare to transmit data, example: 8 bytes */
2010-10-01 02:15:27 +04:00
nents = kfifo_dma_out_prepare ( & fifo , sg , ARRAY_SIZE ( sg ) , 8 ) ;
printk ( KERN_INFO " DMA sgl entries: %d \n " , nents ) ;
if ( ! nents ) {
2010-08-20 01:13:30 +04:00
/* no data was available and no sgl was created */
printk ( KERN_WARNING " error kfifo_dma_out_prepare \n " ) ;
return - EIO ;
}
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
printk ( KERN_INFO " scatterlist for transmit: \n " ) ;
2010-10-01 02:15:27 +04:00
for ( i = 0 ; i < nents ; i + + ) {
2010-08-20 01:13:30 +04:00
printk ( KERN_INFO
" sg[%d] -> "
2017-07-13 00:34:22 +03:00
" page %p offset 0x%.8x length 0x%.8x \n " ,
i , sg_page ( & sg [ i ] ) , sg [ i ] . offset , sg [ i ] . length ) ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
if ( sg_is_last ( & sg [ i ] ) )
break ;
}
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* put here your code to setup and exectute the dma operation */
/* ... */
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* example: 5 bytes transmitted */
ret = 5 ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
/* finish the dma operation and update the transmitted data */
kfifo_dma_out_finish ( & fifo , ret ) ;
2010-08-11 05:03:39 +04:00
2010-08-20 01:13:30 +04:00
ret = kfifo_len ( & fifo ) ;
2010-08-11 05:03:39 +04:00
printk ( KERN_INFO " queue len: %u \n " , kfifo_len ( & fifo ) ) ;
2010-08-20 01:13:30 +04:00
if ( ret ! = 7 ) {
printk ( KERN_WARNING " size mismatch: test failed " ) ;
return - EIO ;
}
printk ( KERN_INFO " test passed \n " ) ;
2010-08-11 05:03:39 +04:00
return 0 ;
}
static void __exit example_exit ( void )
{
2010-08-20 01:13:30 +04:00
kfifo_free ( & fifo ) ;
2010-08-11 05:03:39 +04:00
}
module_init ( example_init ) ;
module_exit ( example_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Stefani Seibold <stefani@seibold.net> " ) ;