2006-12-19 19:58:27 -05:00
/* -*- c-basic-offset: 8 -*-
*
* fw - iso . c - Isochronous IO
* Copyright ( C ) 2006 Kristian Hoegsberg < krh @ bitplanet . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/dma-mapping.h>
# include <linux/vmalloc.h>
# include <linux/mm.h>
# include "fw-transaction.h"
# include "fw-topology.h"
2006-12-19 19:58:31 -05:00
# include "fw-device.h"
2006-12-19 19:58:27 -05:00
static int
setup_iso_buffer ( struct fw_iso_context * ctx , size_t size ,
enum dma_data_direction direction )
{
struct page * page ;
2007-02-06 14:49:40 -05:00
int i , j ;
2006-12-19 19:58:27 -05:00
void * p ;
ctx - > buffer_size = PAGE_ALIGN ( size ) ;
if ( size = = 0 )
return 0 ;
ctx - > buffer = vmalloc_32_user ( ctx - > buffer_size ) ;
if ( ctx - > buffer = = NULL )
2007-02-06 14:49:40 -05:00
goto fail_buffer_alloc ;
2006-12-19 19:58:27 -05:00
ctx - > page_count = ctx - > buffer_size > > PAGE_SHIFT ;
ctx - > pages =
kzalloc ( ctx - > page_count * sizeof ( ctx - > pages [ 0 ] ) , GFP_KERNEL ) ;
2007-02-06 14:49:40 -05:00
if ( ctx - > pages = = NULL )
goto fail_pages_alloc ;
2006-12-19 19:58:27 -05:00
p = ctx - > buffer ;
for ( i = 0 ; i < ctx - > page_count ; i + + , p + = PAGE_SIZE ) {
page = vmalloc_to_page ( p ) ;
ctx - > pages [ i ] = dma_map_page ( ctx - > card - > device ,
page , 0 , PAGE_SIZE , direction ) ;
2007-02-06 14:49:40 -05:00
if ( dma_mapping_error ( ctx - > pages [ i ] ) )
goto fail_mapping ;
2006-12-19 19:58:27 -05:00
}
return 0 ;
2007-02-06 14:49:40 -05:00
fail_mapping :
for ( j = 0 ; j < i ; j + + )
dma_unmap_page ( ctx - > card - > device , ctx - > pages [ j ] ,
PAGE_SIZE , DMA_TO_DEVICE ) ;
fail_pages_alloc :
vfree ( ctx - > buffer ) ;
fail_buffer_alloc :
return - ENOMEM ;
2006-12-19 19:58:27 -05:00
}
static void destroy_iso_buffer ( struct fw_iso_context * ctx )
{
int i ;
for ( i = 0 ; i < ctx - > page_count ; i + + )
dma_unmap_page ( ctx - > card - > device , ctx - > pages [ i ] ,
PAGE_SIZE , DMA_TO_DEVICE ) ;
kfree ( ctx - > pages ) ;
vfree ( ctx - > buffer ) ;
}
struct fw_iso_context * fw_iso_context_create ( struct fw_card * card , int type ,
size_t buffer_size ,
fw_iso_callback_t callback ,
void * callback_data )
{
struct fw_iso_context * ctx ;
int retval ;
ctx = card - > driver - > allocate_iso_context ( card , type ) ;
if ( IS_ERR ( ctx ) )
return ctx ;
ctx - > card = card ;
ctx - > type = type ;
ctx - > callback = callback ;
ctx - > callback_data = callback_data ;
retval = setup_iso_buffer ( ctx , buffer_size , DMA_TO_DEVICE ) ;
if ( retval < 0 ) {
card - > driver - > free_iso_context ( ctx ) ;
return ERR_PTR ( retval ) ;
}
return ctx ;
}
EXPORT_SYMBOL ( fw_iso_context_create ) ;
void fw_iso_context_destroy ( struct fw_iso_context * ctx )
{
struct fw_card * card = ctx - > card ;
destroy_iso_buffer ( ctx ) ;
card - > driver - > free_iso_context ( ctx ) ;
}
EXPORT_SYMBOL ( fw_iso_context_destroy ) ;
int
fw_iso_context_send ( struct fw_iso_context * ctx ,
int channel , int speed , int cycle )
{
ctx - > channel = channel ;
ctx - > speed = speed ;
return ctx - > card - > driver - > send_iso ( ctx , cycle ) ;
}
EXPORT_SYMBOL ( fw_iso_context_send ) ;
int
fw_iso_context_queue ( struct fw_iso_context * ctx ,
struct fw_iso_packet * packet , void * payload )
{
struct fw_card * card = ctx - > card ;
return card - > driver - > queue_iso ( ctx , packet , payload ) ;
}
EXPORT_SYMBOL ( fw_iso_context_queue ) ;