2008-05-22 18:05:26 -03:00
/*
2008-05-22 18:29:20 -03:00
* Siano core API module
*
* This file contains implementation for the interface to sms core component
*
* author : Anatoly Greenblat
2008-05-22 18:05:26 -03:00
*
2008-05-22 18:29:20 -03:00
* Copyright ( c ) , 2005 - 2008 Siano Mobile Silicon , Inc .
2008-05-22 18:05:26 -03:00
*
* This program is free software ; you can redistribute it and / or modify
2008-05-22 18:29:20 -03:00
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation ;
2008-05-22 18:05:26 -03:00
*
2008-05-22 18:29:20 -03:00
* Software distributed under the License is distributed on an " AS IS "
* basis , WITHOUT WARRANTY OF ANY KIND , either express or implied .
2008-05-22 18:05:26 -03:00
*
2008-05-22 18:29:20 -03:00
* See the GNU General Public License for more details .
2008-05-22 18:05:26 -03:00
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2008-05-19 18:56:13 -03:00
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/dma-mapping.h>
# include <linux/delay.h>
# include <asm/io.h>
# include <linux/firmware.h>
# include "smscoreapi.h"
2008-06-15 15:14:13 -03:00
# define PERROR(fmt, args...)\
printk ( KERN_ERR " smscore error: line %d- %s(): " fmt , \
__LINE__ , __func__ , # # args )
2008-06-14 00:43:26 -03:00
# ifdef SMSCORE_DEBUG
# undef PWARNING
2008-06-15 15:14:13 -03:00
# define PWARNING(fmt, args...) printk(KERN_INFO "smscore warning: " \
" line %d- %s(): " fmt , \
__LINE__ , __func__ , # # args )
2008-06-14 00:43:26 -03:00
# undef PDEBUG /* undef it, just in case */
2008-06-15 15:14:13 -03:00
# define PDEBUG(fmt, args...) printk(KERN_INFO "smscore - %s(): " fmt, \
__func__ , # # args )
2008-06-14 00:43:26 -03:00
# else /*SMSCORE_DEBUG*/
# define PDEBUG(fmt, args...)
# define PWARNING(fmt, args...)
# endif
2008-06-15 17:52:24 -03:00
struct smscore_device_notifyee_t {
2008-05-19 18:56:13 -03:00
struct list_head entry ;
hotplug_t hotplug ;
2008-06-15 17:52:24 -03:00
} ;
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
struct smscore_idlist_t {
2008-06-14 00:43:26 -03:00
struct list_head entry ;
int id ;
int data_type ;
2008-06-15 17:52:24 -03:00
} ;
2008-06-14 00:43:26 -03:00
2008-06-15 17:52:24 -03:00
struct smscore_client_t {
2008-05-19 18:56:13 -03:00
struct list_head entry ;
2008-06-15 17:52:24 -03:00
struct smscore_device_t * coredev ;
2008-05-19 18:56:13 -03:00
void * context ;
2008-06-14 00:43:26 -03:00
struct list_head idlist ;
2008-05-19 18:56:13 -03:00
onresponse_t onresponse_handler ;
onremove_t onremove_handler ;
2008-06-15 17:52:24 -03:00
} ;
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
struct smscore_device_t {
2008-05-19 18:56:13 -03:00
struct list_head entry ;
struct list_head clients ;
struct list_head subclients ;
spinlock_t clientslock ;
struct list_head buffers ;
spinlock_t bufferslock ;
int num_buffers ;
void * common_buffer ;
int common_buffer_size ;
dma_addr_t common_buffer_phys ;
void * context ;
struct device * device ;
char devpath [ 32 ] ;
unsigned long device_flags ;
setmode_t setmode_handler ;
detectmode_t detectmode_handler ;
sendrequest_t sendrequest_handler ;
preload_t preload_handler ;
postload_t postload_handler ;
int mode , modes_supported ;
struct completion version_ex_done , data_download_done , trigger_done ;
struct completion init_device_done , reload_start_done , resume_done ;
2008-06-15 17:52:24 -03:00
} ;
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t {
2008-05-19 18:56:13 -03:00
struct list_head entry ;
char devpath [ 32 ] ;
int mode ;
2008-06-15 17:52:24 -03:00
enum sms_device_type_st type ;
} ;
2008-05-19 18:56:13 -03:00
struct list_head g_smscore_notifyees ;
struct list_head g_smscore_devices ;
kmutex_t g_smscore_deviceslock ;
struct list_head g_smscore_registry ;
kmutex_t g_smscore_registrylock ;
2008-06-18 20:25:25 -03:00
static int default_mode = 4 ;
2008-06-14 00:43:26 -03:00
2008-05-19 18:56:13 -03:00
module_param ( default_mode , int , 0644 ) ;
MODULE_PARM_DESC ( default_mode , " default firmware id (device mode) " ) ;
2008-06-15 17:52:24 -03:00
static struct smscore_registry_entry_t * smscore_find_registry ( char * devpath )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry ;
2008-05-19 18:56:13 -03:00
struct list_head * next ;
kmutex_lock ( & g_smscore_registrylock ) ;
2008-06-15 15:14:13 -03:00
for ( next = g_smscore_registry . next ;
next ! = & g_smscore_registry ;
next = next - > next ) {
2008-06-15 17:52:24 -03:00
entry = ( struct smscore_registry_entry_t * ) next ;
2008-06-15 15:14:13 -03:00
if ( ! strcmp ( entry - > devpath , devpath ) ) {
2008-05-19 18:56:13 -03:00
kmutex_unlock ( & g_smscore_registrylock ) ;
2008-06-14 00:43:26 -03:00
return entry ;
2008-05-19 18:56:13 -03:00
}
}
2008-06-15 17:52:24 -03:00
entry = ( struct smscore_registry_entry_t * )
kmalloc ( sizeof ( struct smscore_registry_entry_t ) ,
GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( entry ) {
2008-05-19 18:56:13 -03:00
entry - > mode = default_mode ;
strcpy ( entry - > devpath , devpath ) ;
list_add ( & entry - > entry , & g_smscore_registry ) ;
2008-06-15 15:14:13 -03:00
} else
printk ( KERN_ERR " %s failed to create smscore_registry. \n " ,
__func__ ) ;
2008-05-19 18:56:13 -03:00
kmutex_unlock ( & g_smscore_registrylock ) ;
2008-06-14 00:43:26 -03:00
return entry ;
}
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
int smscore_registry_getmode ( char * devpath )
2008-06-14 00:43:26 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry ;
2008-06-14 00:43:26 -03:00
2008-06-15 15:14:13 -03:00
entry = smscore_find_registry ( devpath ) ;
if ( entry )
2008-06-14 00:43:26 -03:00
return entry - > mode ;
else
2008-06-15 15:14:13 -03:00
printk ( KERN_ERR " %s No registry found. \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
return default_mode ;
}
2008-06-15 17:52:24 -03:00
enum sms_device_type_st smscore_registry_gettype ( char * devpath )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
entry = smscore_find_registry ( devpath ) ;
if ( entry )
2008-06-14 00:43:26 -03:00
return entry - > type ;
else
2008-06-15 15:14:13 -03:00
printk ( KERN_ERR " %s No registry found. \n " , __func__ ) ;
2008-06-14 00:43:26 -03:00
return - 1 ;
}
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
void smscore_registry_setmode ( char * devpath , int mode )
{
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
entry = smscore_find_registry ( devpath ) ;
if ( entry )
entry - > mode = mode ;
2008-06-14 00:43:26 -03:00
else
2008-06-15 15:14:13 -03:00
printk ( KERN_ERR " %s No registry found. \n " , __func__ ) ;
}
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
void smscore_registry_settype ( char * devpath , enum sms_device_type_st type )
2008-06-14 00:43:26 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry ;
2008-06-14 00:43:26 -03:00
2008-06-15 15:14:13 -03:00
entry = smscore_find_registry ( devpath ) ;
if ( entry )
2008-06-14 00:43:26 -03:00
entry - > type = type ;
else
2008-06-15 15:14:13 -03:00
printk ( KERN_ERR " %s No registry found. \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
}
2008-05-06 03:11:51 -03:00
void list_add_locked ( struct list_head * new , struct list_head * head ,
2008-06-15 15:14:13 -03:00
spinlock_t * lock )
2008-05-19 18:56:13 -03:00
{
unsigned long flags ;
spin_lock_irqsave ( lock , flags ) ;
list_add ( new , head ) ;
spin_unlock_irqrestore ( lock , flags ) ;
}
/**
* register a client callback that called when device plugged in / unplugged
* NOTE : if devices exist callback is called immediately for each device
*
* @ param hotplug callback
*
* @ return 0 on success , < 0 on error .
*/
int smscore_register_hotplug ( hotplug_t hotplug )
{
2008-06-15 17:52:24 -03:00
struct smscore_device_notifyee_t * notifyee ;
2008-05-19 18:56:13 -03:00
struct list_head * next , * first ;
int rc = 0 ;
kmutex_lock ( & g_smscore_deviceslock ) ;
2008-06-15 17:52:24 -03:00
notifyee = kmalloc ( sizeof ( struct smscore_device_notifyee_t ) ,
GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( notifyee ) {
/* now notify callback about existing devices */
2008-05-19 18:56:13 -03:00
first = & g_smscore_devices ;
2008-06-15 15:14:13 -03:00
for ( next = first - > next ;
next ! = first & & ! rc ;
next = next - > next ) {
2008-06-15 17:52:24 -03:00
struct smscore_device_t * coredev =
( struct smscore_device_t * ) next ;
2008-05-19 18:56:13 -03:00
rc = hotplug ( coredev , coredev - > device , 1 ) ;
}
2008-06-15 15:14:13 -03:00
if ( rc > = 0 ) {
2008-05-19 18:56:13 -03:00
notifyee - > hotplug = hotplug ;
list_add ( & notifyee - > entry , & g_smscore_notifyees ) ;
2008-06-15 15:14:13 -03:00
} else
2008-05-19 18:56:13 -03:00
kfree ( notifyee ) ;
2008-06-15 15:14:13 -03:00
} else
2008-05-19 18:56:13 -03:00
rc = - ENOMEM ;
kmutex_unlock ( & g_smscore_deviceslock ) ;
return rc ;
}
/**
* unregister a client callback that called when device plugged in / unplugged
*
* @ param hotplug callback
*
*/
void smscore_unregister_hotplug ( hotplug_t hotplug )
{
struct list_head * next , * first ;
kmutex_lock ( & g_smscore_deviceslock ) ;
first = & g_smscore_notifyees ;
2008-06-15 15:14:13 -03:00
for ( next = first - > next ; next ! = first ; ) {
2008-06-15 17:52:24 -03:00
struct smscore_device_notifyee_t * notifyee =
( struct smscore_device_notifyee_t * ) next ;
2008-05-19 18:56:13 -03:00
next = next - > next ;
2008-06-15 15:14:13 -03:00
if ( notifyee - > hotplug = = hotplug ) {
2008-05-19 18:56:13 -03:00
list_del ( & notifyee - > entry ) ;
kfree ( notifyee ) ;
}
}
kmutex_unlock ( & g_smscore_deviceslock ) ;
}
2008-06-15 17:52:24 -03:00
void smscore_notify_clients ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_client_t * client ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
/* the client must call smscore_unregister_client from remove handler */
while ( ! list_empty ( & coredev - > clients ) ) {
2008-06-15 17:52:24 -03:00
client = ( struct smscore_client_t * ) coredev - > clients . next ;
2008-05-19 18:56:13 -03:00
client - > onremove_handler ( client - > context ) ;
}
}
2008-06-15 17:52:24 -03:00
int smscore_notify_callbacks ( struct smscore_device_t * coredev ,
struct device * device , int arrival )
2008-05-19 18:56:13 -03:00
{
struct list_head * next , * first ;
int rc = 0 ;
2008-06-15 15:14:13 -03:00
/* note: must be called under g_deviceslock */
2008-05-19 18:56:13 -03:00
first = & g_smscore_notifyees ;
2008-06-15 15:14:13 -03:00
for ( next = first - > next ; next ! = first ; next = next - > next ) {
2008-06-15 17:52:24 -03:00
rc = ( ( struct smscore_device_notifyee_t * ) next ) - >
2008-06-15 16:50:11 -03:00
hotplug ( coredev , device , arrival ) ;
2008-05-19 18:56:13 -03:00
if ( rc < 0 )
break ;
}
return rc ;
}
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * smscore_createbuffer ( u8 * buffer , void * common_buffer ,
2008-05-06 03:11:51 -03:00
dma_addr_t common_buffer_phys )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * cb =
kmalloc ( sizeof ( struct smscore_buffer_t ) , GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( ! cb ) {
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s kmalloc(...) failed \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
return NULL ;
}
cb - > p = buffer ;
2008-06-14 07:40:41 -03:00
cb - > offset_in_common = buffer - ( u8 * ) common_buffer ;
2008-05-19 18:56:13 -03:00
cb - > phys = common_buffer_phys + cb - > offset_in_common ;
return cb ;
}
/**
2008-06-15 15:14:13 -03:00
* creates coredev object for a device , prepares buffers ,
* creates buffer mappings , notifies registered hotplugs about new device .
2008-05-19 18:56:13 -03:00
*
2008-06-15 16:50:11 -03:00
* @ param params device pointer to struct with device specific parameters
* and handlers
2008-05-19 18:56:13 -03:00
* @ param coredev pointer to a value that receives created coredev object
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_register_device ( struct smsdevice_params_t * params ,
struct smscore_device_t * * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_device_t * dev ;
2008-05-19 18:56:13 -03:00
u8 * buffer ;
2008-06-15 17:52:24 -03:00
dev = kzalloc ( sizeof ( struct smscore_device_t ) , GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( ! dev ) {
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s kzalloc(...) failed \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
return - ENOMEM ;
}
2008-06-15 15:14:13 -03:00
/* init list entry so it could be safe in smscore_unregister_device */
2008-05-19 18:56:13 -03:00
INIT_LIST_HEAD ( & dev - > entry ) ;
2008-06-15 15:14:13 -03:00
/* init queues */
2008-05-19 18:56:13 -03:00
INIT_LIST_HEAD ( & dev - > clients ) ;
INIT_LIST_HEAD ( & dev - > buffers ) ;
2008-06-15 15:14:13 -03:00
/* init locks */
2008-05-19 18:56:13 -03:00
spin_lock_init ( & dev - > clientslock ) ;
spin_lock_init ( & dev - > bufferslock ) ;
2008-06-15 15:14:13 -03:00
/* init completion events */
2008-05-19 18:56:13 -03:00
init_completion ( & dev - > version_ex_done ) ;
init_completion ( & dev - > data_download_done ) ;
init_completion ( & dev - > trigger_done ) ;
init_completion ( & dev - > init_device_done ) ;
init_completion ( & dev - > reload_start_done ) ;
init_completion ( & dev - > resume_done ) ;
2008-06-15 15:14:13 -03:00
/* alloc common buffer */
2008-05-19 18:56:13 -03:00
dev - > common_buffer_size = params - > buffer_size * params - > num_buffers ;
2008-06-15 15:14:13 -03:00
dev - > common_buffer = dma_alloc_coherent ( NULL , dev - > common_buffer_size ,
& dev - > common_buffer_phys ,
GFP_KERNEL | GFP_DMA ) ;
if ( ! dev - > common_buffer ) {
2008-05-19 18:56:13 -03:00
smscore_unregister_device ( dev ) ;
return - ENOMEM ;
}
2008-06-15 15:14:13 -03:00
/* prepare dma buffers */
for ( buffer = dev - > common_buffer ;
dev - > num_buffers < params - > num_buffers ;
2008-06-15 15:52:43 -03:00
dev - > num_buffers + + , buffer + = params - > buffer_size ) {
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * cb =
2008-06-15 16:50:11 -03:00
smscore_createbuffer ( buffer , dev - > common_buffer ,
dev - > common_buffer_phys ) ;
2008-06-15 15:14:13 -03:00
if ( ! cb ) {
2008-05-19 18:56:13 -03:00
smscore_unregister_device ( dev ) ;
return - ENOMEM ;
}
smscore_putbuffer ( dev , cb ) ;
}
2008-06-15 15:14:13 -03:00
printk ( KERN_INFO " %s allocated %d buffers \n " ,
__func__ , dev - > num_buffers ) ;
2008-05-19 18:56:13 -03:00
dev - > mode = DEVICE_MODE_NONE ;
dev - > context = params - > context ;
dev - > device = params - > device ;
dev - > setmode_handler = params - > setmode_handler ;
dev - > detectmode_handler = params - > detectmode_handler ;
dev - > sendrequest_handler = params - > sendrequest_handler ;
dev - > preload_handler = params - > preload_handler ;
dev - > postload_handler = params - > postload_handler ;
dev - > device_flags = params - > flags ;
strcpy ( dev - > devpath , params - > devpath ) ;
2008-06-15 15:14:13 -03:00
smscore_registry_settype ( dev - > devpath , params - > device_type ) ;
2008-06-14 00:43:26 -03:00
2008-06-15 15:14:13 -03:00
/* add device to devices list */
2008-05-19 18:56:13 -03:00
kmutex_lock ( & g_smscore_deviceslock ) ;
list_add ( & dev - > entry , & g_smscore_devices ) ;
kmutex_unlock ( & g_smscore_deviceslock ) ;
* coredev = dev ;
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s device %p created \n " , __func__ , dev ) ;
2008-05-19 18:56:13 -03:00
return 0 ;
}
/**
* sets initial device mode and notifies client hotplugs that device is ready
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_start_device ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 16:50:11 -03:00
int rc = smscore_set_device_mode (
coredev , smscore_registry_getmode ( coredev - > devpath ) ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
2008-06-15 16:50:11 -03:00
printk ( KERN_INFO " %s set device mode faile , rc %d \n " ,
__func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
2008-06-14 00:43:26 -03:00
}
2008-05-19 18:56:13 -03:00
kmutex_lock ( & g_smscore_deviceslock ) ;
rc = smscore_notify_callbacks ( coredev , coredev - > device , 1 ) ;
2008-06-15 15:14:13 -03:00
printk ( KERN_INFO " %s device %p started, rc %d \n " ,
__func__ , coredev , rc ) ;
2008-05-19 18:56:13 -03:00
kmutex_unlock ( & g_smscore_deviceslock ) ;
return rc ;
}
2008-06-15 17:52:24 -03:00
int smscore_sendrequest_and_wait ( struct smscore_device_t * coredev , void * buffer ,
2008-06-15 15:14:13 -03:00
size_t size , struct completion * completion )
2008-05-19 18:56:13 -03:00
{
int rc = coredev - > sendrequest_handler ( coredev - > context , buffer , size ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
printk ( KERN_INFO " %s sendrequest returned error %d \n " ,
__func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
2008-06-14 00:43:26 -03:00
}
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
return wait_for_completion_timeout ( completion ,
msecs_to_jiffies ( 10000 ) ) ?
0 : - ETIME ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 17:52:24 -03:00
int smscore_load_firmware_family2 ( struct smscore_device_t * coredev ,
void * buffer , size_t size )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct SmsFirmware_ST * firmware = ( struct SmsFirmware_ST * ) buffer ;
struct SmsMsgHdr_ST * msg ;
2008-06-15 15:32:00 -03:00
u32 mem_address = firmware - > StartAddress ;
2008-05-06 03:11:51 -03:00
u8 * payload = firmware - > Payload ;
2008-05-19 18:56:13 -03:00
int rc = 0 ;
2008-06-15 15:14:13 -03:00
printk ( KERN_INFO " %s loading FW to addr 0x%x size %d \n " ,
__func__ , mem_address , firmware - > Length ) ;
if ( coredev - > preload_handler ) {
2008-05-19 18:56:13 -03:00
rc = coredev - > preload_handler ( coredev - > context ) ;
if ( rc < 0 )
return rc ;
}
2008-06-15 15:14:13 -03:00
/* PAGE_SIZE buffer shall be enough and dma aligned */
2008-06-15 19:11:37 -03:00
msg = kmalloc ( PAGE_SIZE , GFP_KERNEL | GFP_DMA ) ;
2008-05-19 18:56:13 -03:00
if ( ! msg )
return - ENOMEM ;
2008-06-15 15:14:13 -03:00
if ( coredev - > mode ! = DEVICE_MODE_NONE ) {
2008-06-14 00:43:26 -03:00
PDEBUG ( " Sending reload command \n " ) ;
2008-06-15 15:14:13 -03:00
SMS_INIT_MSG ( msg , MSG_SW_RELOAD_START_REQ ,
2008-06-15 17:52:24 -03:00
sizeof ( struct SmsMsgHdr_ST ) ) ;
2008-06-15 15:14:13 -03:00
rc = smscore_sendrequest_and_wait ( coredev , msg ,
msg - > msgLength ,
& coredev - > reload_start_done ) ;
2008-06-15 15:32:00 -03:00
mem_address = * ( u32 * ) & payload [ 20 ] ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 15:52:43 -03:00
while ( size & & rc > = 0 ) {
2008-06-15 17:52:24 -03:00
struct SmsDataDownload_ST * DataMsg =
( struct SmsDataDownload_ST * ) msg ;
2008-05-19 18:56:13 -03:00
int payload_size = min ( ( int ) size , SMS_MAX_PAYLOAD_SIZE ) ;
2008-06-15 15:14:13 -03:00
SMS_INIT_MSG ( msg , MSG_SMS_DATA_DOWNLOAD_REQ ,
2008-06-15 17:52:24 -03:00
( u16 ) ( sizeof ( struct SmsMsgHdr_ST ) +
2008-06-15 15:32:00 -03:00
sizeof ( u32 ) + payload_size ) ) ;
2008-05-19 18:56:13 -03:00
DataMsg - > MemAddr = mem_address ;
memcpy ( DataMsg - > Payload , payload , payload_size ) ;
2008-06-15 15:14:13 -03:00
if ( ( coredev - > device_flags & SMS_ROM_NO_RESPONSE ) & &
( coredev - > mode = = DEVICE_MODE_NONE ) )
2008-06-15 16:50:11 -03:00
rc = coredev - > sendrequest_handler (
coredev - > context , DataMsg ,
DataMsg - > xMsgHeader . msgLength ) ;
2008-05-19 18:56:13 -03:00
else
2008-06-15 16:50:11 -03:00
rc = smscore_sendrequest_and_wait (
coredev , DataMsg ,
DataMsg - > xMsgHeader . msgLength ,
& coredev - > data_download_done ) ;
2008-05-19 18:56:13 -03:00
payload + = payload_size ;
size - = payload_size ;
mem_address + = payload_size ;
}
2008-06-15 15:14:13 -03:00
if ( rc > = 0 ) {
if ( coredev - > mode = = DEVICE_MODE_NONE ) {
2008-06-15 17:52:24 -03:00
struct SmsMsgData_ST * TriggerMsg =
( struct SmsMsgData_ST * ) msg ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
SMS_INIT_MSG ( msg , MSG_SMS_SWDOWNLOAD_TRIGGER_REQ ,
2008-06-15 17:52:24 -03:00
sizeof ( struct SmsMsgHdr_ST ) +
2008-06-15 15:32:00 -03:00
sizeof ( u32 ) * 5 ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 16:50:11 -03:00
TriggerMsg - > msgData [ 0 ] = firmware - > StartAddress ;
/* Entry point */
2008-06-15 15:52:43 -03:00
TriggerMsg - > msgData [ 1 ] = 5 ; /* Priority */
TriggerMsg - > msgData [ 2 ] = 0x200 ; /* Stack size */
TriggerMsg - > msgData [ 3 ] = 0 ; /* Parameter */
TriggerMsg - > msgData [ 4 ] = 4 ; /* Task ID */
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( coredev - > device_flags & SMS_ROM_NO_RESPONSE ) {
2008-06-15 16:50:11 -03:00
rc = coredev - > sendrequest_handler (
coredev - > context , TriggerMsg ,
TriggerMsg - > xMsgHeader . msgLength ) ;
2008-05-19 18:56:13 -03:00
msleep ( 100 ) ;
2008-06-15 15:14:13 -03:00
} else
2008-06-15 16:50:11 -03:00
rc = smscore_sendrequest_and_wait (
coredev , TriggerMsg ,
TriggerMsg - > xMsgHeader . msgLength ,
& coredev - > trigger_done ) ;
2008-06-15 15:14:13 -03:00
} else {
SMS_INIT_MSG ( msg , MSG_SW_RELOAD_EXEC_REQ ,
2008-06-15 17:52:24 -03:00
sizeof ( struct SmsMsgHdr_ST ) ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
rc = coredev - > sendrequest_handler ( coredev - > context ,
msg , msg - > msgLength ) ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 15:14:13 -03:00
msleep ( 500 ) ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " %s rc=%d, postload=%p \n " , __func__ , rc ,
2008-06-15 15:14:13 -03:00
coredev - > postload_handler ) ;
2008-05-19 18:56:13 -03:00
kfree ( msg ) ;
2008-06-14 00:43:26 -03:00
return ( ( rc > = 0 ) & & coredev - > postload_handler ) ?
2008-05-19 18:56:13 -03:00
coredev - > postload_handler ( coredev - > context ) :
rc ;
}
/**
* loads specified firmware into a buffer and calls device loadfirmware_handler
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
* @ param filename null - terminated string specifies firmware file name
* @ param loadfirmware_handler device handler that loads firmware
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_load_firmware_from_file ( struct smscore_device_t * coredev ,
char * filename ,
2008-06-15 15:14:13 -03:00
loadfirmware_t loadfirmware_handler )
2008-05-19 18:56:13 -03:00
{
int rc = - ENOENT ;
const struct firmware * fw ;
2008-05-06 03:11:51 -03:00
u8 * fw_buffer ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( loadfirmware_handler = = NULL & & ! ( coredev - > device_flags &
SMS_DEVICE_FAMILY2 ) )
2008-05-19 18:56:13 -03:00
return - EINVAL ;
rc = request_firmware ( & fw , filename , coredev - > device ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
printk ( KERN_INFO " %s failed to open \" %s \" \n " ,
__func__ , filename ) ;
2008-05-19 18:56:13 -03:00
return rc ;
}
2008-06-15 15:14:13 -03:00
printk ( KERN_INFO " %s read FW %s, size=%d \" \n " , __func__ ,
filename , fw - > size ) ;
fw_buffer = kmalloc ( ALIGN ( fw - > size , SMS_ALLOC_ALIGNMENT ) ,
GFP_KERNEL | GFP_DMA ) ;
if ( fw_buffer ) {
2008-05-19 18:56:13 -03:00
memcpy ( fw_buffer , fw - > data , fw - > size ) ;
rc = ( coredev - > device_flags & SMS_DEVICE_FAMILY2 ) ?
2008-06-15 16:50:11 -03:00
smscore_load_firmware_family2 ( coredev ,
fw_buffer ,
fw - > size ) :
loadfirmware_handler ( coredev - > context ,
fw_buffer , fw - > size ) ;
2008-05-19 18:56:13 -03:00
kfree ( fw_buffer ) ;
2008-06-15 15:14:13 -03:00
} else {
printk ( KERN_INFO " %s failed to allocate firmware buffer \n " ,
__func__ ) ;
2008-05-19 18:56:13 -03:00
rc = - ENOMEM ;
}
release_firmware ( fw ) ;
return rc ;
}
2008-06-15 17:52:24 -03:00
int smscore_load_firmware_from_buffer ( struct smscore_device_t * coredev ,
u8 * buffer , int size , int new_mode )
2008-06-14 00:43:26 -03:00
{
PERROR ( " Feature not implemented yet \n " ) ;
return - EFAULT ;
}
2008-05-19 18:56:13 -03:00
/**
2008-06-15 16:50:11 -03:00
* notifies all clients registered with the device , notifies hotplugs ,
* frees all buffers and coredev object
2008-05-19 18:56:13 -03:00
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
void smscore_unregister_device ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * cb ;
2008-05-19 18:56:13 -03:00
int num_buffers = 0 ;
2008-06-14 00:43:26 -03:00
int retry = 0 ;
2008-05-19 18:56:13 -03:00
kmutex_lock ( & g_smscore_deviceslock ) ;
smscore_notify_clients ( coredev ) ;
smscore_notify_callbacks ( coredev , NULL , 0 ) ;
2008-06-15 15:14:13 -03:00
/* at this point all buffers should be back
* onresponse must no longer be called */
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
while ( 1 ) {
while ( ( cb = smscore_getbuffer ( coredev ) ) ) {
2008-05-19 18:56:13 -03:00
kfree ( cb ) ;
2008-06-15 15:52:43 -03:00
num_buffers + + ;
2008-05-19 18:56:13 -03:00
}
if ( num_buffers = = coredev - > num_buffers )
break ;
2008-06-15 15:14:13 -03:00
if ( + + retry > 10 ) {
printk ( KERN_INFO " %s exiting although "
" not all buffers released. \n " , __func__ ) ;
2008-06-14 00:43:26 -03:00
break ;
}
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
printk ( KERN_INFO " %s waiting for %d buffer(s) \n " , __func__ ,
coredev - > num_buffers - num_buffers ) ;
2008-05-19 18:56:13 -03:00
msleep ( 100 ) ;
}
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s freed %d buffers \n " , __func__ , num_buffers ) ;
2008-05-19 18:56:13 -03:00
if ( coredev - > common_buffer )
2008-06-15 15:14:13 -03:00
dma_free_coherent ( NULL , coredev - > common_buffer_size ,
coredev - > common_buffer ,
coredev - > common_buffer_phys ) ;
2008-05-19 18:56:13 -03:00
list_del ( & coredev - > entry ) ;
kfree ( coredev ) ;
kmutex_unlock ( & g_smscore_deviceslock ) ;
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s device %p destroyed \n " , __func__ , coredev ) ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 17:52:24 -03:00
int smscore_detect_mode ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
void * buffer = kmalloc ( sizeof ( struct SmsMsgHdr_ST ) + SMS_DMA_ALIGNMENT ,
2008-06-15 15:14:13 -03:00
GFP_KERNEL | GFP_DMA ) ;
2008-06-15 17:52:24 -03:00
struct SmsMsgHdr_ST * msg =
( struct SmsMsgHdr_ST * ) SMS_ALIGN_ADDRESS ( buffer ) ;
2008-05-19 18:56:13 -03:00
int rc ;
if ( ! buffer )
return - ENOMEM ;
2008-06-15 17:52:24 -03:00
SMS_INIT_MSG ( msg , MSG_SMS_GET_VERSION_EX_REQ ,
sizeof ( struct SmsMsgHdr_ST ) ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
rc = smscore_sendrequest_and_wait ( coredev , msg , msg - > msgLength ,
& coredev - > version_ex_done ) ;
if ( rc = = - ETIME ) {
2008-06-15 17:26:42 -03:00
printk ( KERN_ERR " %s: MSG_SMS_GET_VERSION_EX_REQ "
" failed first try \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( wait_for_completion_timeout ( & coredev - > resume_done ,
msecs_to_jiffies ( 5000 ) ) ) {
2008-06-15 16:50:11 -03:00
rc = smscore_sendrequest_and_wait (
coredev , msg , msg - > msgLength ,
& coredev - > version_ex_done ) ;
2008-05-19 18:56:13 -03:00
if ( rc < 0 )
2008-06-15 17:26:42 -03:00
printk ( KERN_ERR " %s: "
" MSG_SMS_GET_VERSION_EX_REQ failed "
2008-06-15 16:50:11 -03:00
" second try, rc %d \n " , __func__ , rc ) ;
2008-06-15 15:14:13 -03:00
} else
2008-05-19 18:56:13 -03:00
rc = - ETIME ;
}
kfree ( buffer ) ;
return rc ;
}
2008-06-15 15:14:13 -03:00
char * smscore_fw_lkup [ ] [ SMS_NUM_OF_DEVICE_TYPES ] = {
2008-06-15 19:27:35 -03:00
/*Stellar NOVA A0 Nova B0 VEGA*/
/*DVBT*/
{ " none " , " dvb_nova_12mhz.inp " , " dvb_nova_12mhz_b0.inp " , " none " } ,
/*DVBH*/
{ " none " , " dvb_nova_12mhz.inp " , " dvb_nova_12mhz_b0.inp " , " none " } ,
/*TDMB*/
{ " none " , " tdmb_nova_12mhz.inp " , " none " , " none " } ,
/*DABIP*/
{ " none " , " none " , " none " , " none " } ,
/*BDA*/
{ " none " , " dvb_nova_12mhz.inp " , " dvb_nova_12mhz_b0.inp " , " none " } ,
/*ISDBT*/
{ " none " , " isdbt_nova_12mhz.inp " , " dvb_nova_12mhz.inp " , " none " } ,
/*ISDBTBDA*/
{ " none " , " isdbt_nova_12mhz.inp " , " isdbt_nova_12mhz_b0.inp " , " none " } ,
/*CMMB*/
{ " none " , " none " , " none " , " cmmb_vega_12mhz.inp " }
2008-05-19 18:56:13 -03:00
} ;
2008-06-14 00:43:26 -03:00
2008-05-19 18:56:13 -03:00
/**
* calls device handler to change mode of operation
* NOTE : stellar / usb may disconnect when changing mode
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
* @ param mode requested mode of operation
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_set_device_mode ( struct smscore_device_t * coredev , int mode )
2008-05-19 18:56:13 -03:00
{
void * buffer ;
int rc = 0 ;
2008-06-15 17:52:24 -03:00
enum sms_device_type_st type ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
PDEBUG ( " set device mode to %d \n " , mode ) ;
if ( coredev - > device_flags & SMS_DEVICE_FAMILY2 ) {
if ( mode < DEVICE_MODE_DVBT | | mode > DEVICE_MODE_RAW_TUNER ) {
printk ( KERN_INFO " %s invalid mode specified %d \n " ,
__func__ , mode ) ;
2008-05-19 18:56:13 -03:00
return - EINVAL ;
}
2008-06-14 00:43:26 -03:00
smscore_registry_setmode ( coredev - > devpath , mode ) ;
2008-06-15 15:14:13 -03:00
if ( ! ( coredev - > device_flags & SMS_DEVICE_NOT_READY ) ) {
2008-05-19 18:56:13 -03:00
rc = smscore_detect_mode ( coredev ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
printk ( KERN_INFO " %s mode detect failed %d \n " ,
__func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
2008-06-15 15:14:13 -03:00
}
2008-06-14 00:43:26 -03:00
}
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( coredev - > mode = = mode ) {
printk ( KERN_INFO " %s device mode %d already set \n " ,
__func__ , mode ) ;
2008-05-19 18:56:13 -03:00
return 0 ;
}
2008-06-15 15:14:13 -03:00
if ( ! ( coredev - > modes_supported & ( 1 < < mode ) ) ) {
type = smscore_registry_gettype ( coredev - > devpath ) ;
2008-06-15 16:50:11 -03:00
rc = smscore_load_firmware_from_file (
coredev , smscore_fw_lkup [ mode ] [ type ] , NULL ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
2008-06-15 16:50:11 -03:00
printk ( KERN_INFO " %s load firmware "
" failed %d \n " , __func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
2008-06-15 15:14:13 -03:00
}
} else
2008-06-15 16:50:11 -03:00
printk ( KERN_INFO " %s mode %d supported by running "
" firmware \n " , __func__ , mode ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
buffer = kmalloc ( sizeof ( struct SmsMsgData_ST ) +
SMS_DMA_ALIGNMENT , GFP_KERNEL | GFP_DMA ) ;
2008-06-15 15:14:13 -03:00
if ( buffer ) {
2008-06-15 17:52:24 -03:00
struct SmsMsgData_ST * msg =
( struct SmsMsgData_ST * )
SMS_ALIGN_ADDRESS ( buffer ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 16:50:11 -03:00
SMS_INIT_MSG ( & msg - > xMsgHeader , MSG_SMS_INIT_DEVICE_REQ ,
2008-06-15 17:52:24 -03:00
sizeof ( struct SmsMsgData_ST ) ) ;
2008-05-19 18:56:13 -03:00
msg - > msgData [ 0 ] = mode ;
2008-06-15 16:50:11 -03:00
rc = smscore_sendrequest_and_wait (
coredev , msg , msg - > xMsgHeader . msgLength ,
& coredev - > init_device_done ) ;
2008-05-19 18:56:13 -03:00
kfree ( buffer ) ;
2008-06-15 15:14:13 -03:00
} else {
2008-06-15 16:50:11 -03:00
printk ( KERN_INFO " %s Could not allocate buffer for "
" init device message. \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
rc = - ENOMEM ;
2008-06-15 15:14:13 -03:00
}
} else {
if ( mode < DEVICE_MODE_DVBT | | mode > DEVICE_MODE_DVBT_BDA ) {
printk ( KERN_INFO " %s invalid mode specified %d \n " ,
__func__ , mode ) ;
2008-06-14 00:43:26 -03:00
return - EINVAL ;
}
smscore_registry_setmode ( coredev - > devpath , mode ) ;
2008-05-19 18:56:13 -03:00
if ( coredev - > detectmode_handler )
2008-06-15 15:14:13 -03:00
coredev - > detectmode_handler ( coredev - > context ,
& coredev - > mode ) ;
2008-05-19 18:56:13 -03:00
if ( coredev - > mode ! = mode & & coredev - > setmode_handler )
rc = coredev - > setmode_handler ( coredev - > context , mode ) ;
}
2008-06-15 15:14:13 -03:00
if ( rc > = 0 ) {
2008-05-19 18:56:13 -03:00
coredev - > mode = mode ;
coredev - > device_flags & = ~ SMS_DEVICE_NOT_READY ;
}
2008-06-14 00:43:26 -03:00
if ( rc ! = 0 )
printk ( KERN_INFO " %s return error code %d. \n " , __func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
}
/**
* calls device handler to get current mode of operation
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
*
* @ return current mode
*/
2008-06-15 17:52:24 -03:00
int smscore_get_device_mode ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
return coredev - > mode ;
}
2008-06-14 00:43:26 -03:00
/**
* find client by response id & type within the clients list .
* return client handle or NULL .
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-06-14 00:43:26 -03:00
* @ param data_type client data type ( SMS_DONT_CARE for all types )
2008-06-15 15:14:13 -03:00
* @ param id client id ( SMS_DONT_CARE for all id )
2008-06-14 00:43:26 -03:00
*
*/
2008-06-15 17:52:24 -03:00
struct smscore_client_t * smscore_find_client ( struct smscore_device_t * coredev ,
2008-06-15 16:50:11 -03:00
int data_type , int id )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_client_t * client = NULL ;
2008-05-19 18:56:13 -03:00
struct list_head * next , * first ;
unsigned long flags ;
2008-06-14 00:43:26 -03:00
struct list_head * firstid , * nextid ;
2008-05-19 18:56:13 -03:00
spin_lock_irqsave ( & coredev - > clientslock , flags ) ;
first = & coredev - > clients ;
2008-06-15 15:14:13 -03:00
for ( next = first - > next ;
( next ! = first ) & & ! client ;
next = next - > next ) {
2008-06-15 17:52:24 -03:00
firstid = & ( ( struct smscore_client_t * ) next ) - > idlist ;
2008-06-15 15:14:13 -03:00
for ( nextid = firstid - > next ;
nextid ! = firstid ;
nextid = nextid - > next ) {
2008-06-15 17:52:24 -03:00
if ( ( ( ( struct smscore_idlist_t * ) nextid ) - > id = = id ) & &
( ( ( struct smscore_idlist_t * ) nextid ) - > data_type = = data_type | |
( ( ( struct smscore_idlist_t * ) nextid ) - > data_type = = 0 ) ) ) {
client = ( struct smscore_client_t * ) next ;
2008-06-15 15:14:13 -03:00
break ;
}
2008-05-19 18:56:13 -03:00
}
}
spin_unlock_irqrestore ( & coredev - > clientslock , flags ) ;
return client ;
}
/**
* find client by response id / type , call clients onresponse handler
* return buffer to pool on error
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
* @ param cb pointer to response buffer descriptor
*
*/
2008-06-15 17:52:24 -03:00
void smscore_onresponse ( struct smscore_device_t * coredev ,
struct smscore_buffer_t * cb )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct SmsMsgHdr_ST * phdr =
( struct SmsMsgHdr_ST * ) ( ( u8 * ) cb - > p + cb - > offset ) ;
struct smscore_client_t * client =
2008-06-15 16:50:11 -03:00
smscore_find_client ( coredev , phdr - > msgType , phdr - > msgDstId ) ;
2008-05-19 18:56:13 -03:00
int rc = - EBUSY ;
2008-06-15 19:27:35 -03:00
static unsigned long last_sample_time ; /* = 0; */
static int data_total ; /* = 0; */
2008-05-19 18:56:13 -03:00
unsigned long time_now = jiffies_to_msecs ( jiffies ) ;
if ( ! last_sample_time )
last_sample_time = time_now ;
2008-06-15 15:52:43 -03:00
if ( time_now - last_sample_time > 10000 ) {
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " \n %s data rate %d bytes/secs \n " , __func__ ,
2008-06-15 15:14:13 -03:00
( int ) ( ( data_total * 1000 ) /
( time_now - last_sample_time ) ) ) ;
2008-05-19 18:56:13 -03:00
last_sample_time = time_now ;
data_total = 0 ;
}
data_total + = cb - > size ;
2008-06-15 15:14:13 -03:00
/* If no client registered for type & id,
* check for control client where type is not registered */
2008-05-19 18:56:13 -03:00
if ( client )
rc = client - > onresponse_handler ( client - > context , cb ) ;
2008-06-15 15:14:13 -03:00
if ( rc < 0 ) {
switch ( phdr - > msgType ) {
case MSG_SMS_GET_VERSION_EX_RES :
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct SmsVersionRes_ST * ver =
( struct SmsVersionRes_ST * ) phdr ;
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " %s: MSG_SMS_GET_VERSION_EX_RES "
" id %d prots 0x%x ver %d.%d \n " , __func__ ,
2008-06-15 15:14:13 -03:00
ver - > FirmwareId , ver - > SupportedProtocols ,
ver - > RomVersionMajor , ver - > RomVersionMinor ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
coredev - > mode = ver - > FirmwareId = = 255 ?
DEVICE_MODE_NONE : ver - > FirmwareId ;
coredev - > modes_supported = ver - > SupportedProtocols ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
complete ( & coredev - > version_ex_done ) ;
break ;
}
case MSG_SMS_INIT_DEVICE_RES :
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " %s: MSG_SMS_INIT_DEVICE_RES \n " ,
__func__ ) ;
2008-06-15 15:14:13 -03:00
complete ( & coredev - > init_device_done ) ;
break ;
case MSG_SW_RELOAD_START_RES :
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " %s: MSG_SW_RELOAD_START_RES \n " ,
__func__ ) ;
2008-06-15 15:14:13 -03:00
complete ( & coredev - > reload_start_done ) ;
break ;
case MSG_SMS_DATA_DOWNLOAD_RES :
complete ( & coredev - > data_download_done ) ;
break ;
case MSG_SW_RELOAD_EXEC_RES :
2008-06-15 17:26:42 -03:00
printk ( KERN_DEBUG " %s: MSG_SW_RELOAD_EXEC_RES \n " ,
__func__ ) ;
2008-06-15 15:14:13 -03:00
break ;
case MSG_SMS_SWDOWNLOAD_TRIGGER_RES :
2008-06-15 17:36:00 -03:00
printk ( KERN_DEBUG
" %s: MSG_SMS_SWDOWNLOAD_TRIGGER_RES \n " ,
2008-06-15 15:14:13 -03:00
__func__ ) ;
complete ( & coredev - > trigger_done ) ;
break ;
case MSG_SMS_SLEEP_RESUME_COMP_IND :
complete ( & coredev - > resume_done ) ;
break ;
default :
break ;
2008-05-19 18:56:13 -03:00
}
smscore_putbuffer ( coredev , cb ) ;
}
}
/**
* return pointer to next free buffer descriptor from core pool
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
*
* @ return pointer to descriptor on success , NULL on error .
*/
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * smscore_getbuffer ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_buffer_t * cb = NULL ;
2008-05-19 18:56:13 -03:00
unsigned long flags ;
spin_lock_irqsave ( & coredev - > bufferslock , flags ) ;
2008-06-15 15:14:13 -03:00
if ( ! list_empty ( & coredev - > buffers ) ) {
2008-06-15 17:52:24 -03:00
cb = ( struct smscore_buffer_t * ) coredev - > buffers . next ;
2008-05-19 18:56:13 -03:00
list_del ( & cb - > entry ) ;
}
spin_unlock_irqrestore ( & coredev - > bufferslock , flags ) ;
return cb ;
}
/**
* return buffer descriptor to a pool
*
2008-06-15 16:50:11 -03:00
* @ param coredev pointer to a coredev object returned by
* smscore_register_device
2008-05-19 18:56:13 -03:00
* @ param cb pointer buffer descriptor
*
*/
2008-06-15 17:52:24 -03:00
void smscore_putbuffer ( struct smscore_device_t * coredev ,
struct smscore_buffer_t * cb )
2008-05-19 18:56:13 -03:00
{
list_add_locked ( & cb - > entry , & coredev - > buffers , & coredev - > bufferslock ) ;
}
2008-06-15 17:52:24 -03:00
int smscore_validate_client ( struct smscore_device_t * coredev ,
struct smscore_client_t * client ,
int data_type , int id )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_idlist_t * listentry ;
struct smscore_client_t * registered_client ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( ! client ) {
2008-06-14 00:43:26 -03:00
PERROR ( " bad parameter. \n " ) ;
return - EFAULT ;
}
registered_client = smscore_find_client ( coredev , data_type , id ) ;
2008-06-15 15:52:43 -03:00
if ( registered_client = = client )
2008-05-19 18:56:13 -03:00
return 0 ;
2008-06-15 15:52:43 -03:00
2008-06-15 15:14:13 -03:00
if ( registered_client ) {
2008-06-14 00:43:26 -03:00
PERROR ( " The msg ID already registered to another client. \n " ) ;
return - EEXIST ;
}
2008-06-15 17:52:24 -03:00
listentry = kzalloc ( sizeof ( struct smscore_idlist_t ) , GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( ! listentry ) {
2008-06-14 00:43:26 -03:00
PERROR ( " Can't allocate memory for client id. \n " ) ;
2008-05-19 18:56:13 -03:00
return - ENOMEM ;
2008-06-14 00:43:26 -03:00
}
listentry - > id = id ;
listentry - > data_type = data_type ;
2008-06-15 15:14:13 -03:00
list_add_locked ( & listentry - > entry , & client - > idlist ,
& coredev - > clientslock ) ;
2008-05-19 18:56:13 -03:00
return 0 ;
}
/**
* creates smsclient object , check that id is taken by another client
*
* @ param coredev pointer to a coredev object from clients hotplug
* @ param initial_id all messages with this id would be sent to this client
* @ param data_type all messages of this type would be sent to this client
2008-06-15 17:36:00 -03:00
* @ param onresponse_handler client handler that is called to
* process incoming messages
2008-05-19 18:56:13 -03:00
* @ param onremove_handler client handler that is called when device is removed
* @ param context client - specific context
* @ param client pointer to a value that receives created smsclient object
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_register_client ( struct smscore_device_t * coredev ,
struct smsclient_params_t * params ,
struct smscore_client_t * * client )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_client_t * newclient ;
2008-06-15 15:14:13 -03:00
/* check that no other channel with same parameters exists */
if ( smscore_find_client ( coredev , params - > data_type ,
params - > initial_id ) ) {
2008-06-14 00:43:26 -03:00
PERROR ( " Client already exist. \n " ) ;
2008-05-19 18:56:13 -03:00
return - EEXIST ;
2008-06-14 00:43:26 -03:00
}
2008-05-19 18:56:13 -03:00
2008-06-15 17:52:24 -03:00
newclient = kzalloc ( sizeof ( struct smscore_client_t ) , GFP_KERNEL ) ;
2008-06-15 15:14:13 -03:00
if ( ! newclient ) {
2008-06-14 00:43:26 -03:00
PERROR ( " Failed to allocate memory for client. \n " ) ;
return - ENOMEM ;
2008-05-19 18:56:13 -03:00
}
2008-06-15 15:14:13 -03:00
INIT_LIST_HEAD ( & newclient - > idlist ) ;
2008-05-19 18:56:13 -03:00
newclient - > coredev = coredev ;
newclient - > onresponse_handler = params - > onresponse_handler ;
newclient - > onremove_handler = params - > onremove_handler ;
newclient - > context = params - > context ;
2008-06-15 15:14:13 -03:00
list_add_locked ( & newclient - > entry , & coredev - > clients ,
& coredev - > clientslock ) ;
smscore_validate_client ( coredev , newclient , params - > data_type ,
params - > initial_id ) ;
2008-05-19 18:56:13 -03:00
* client = newclient ;
2008-06-15 15:14:13 -03:00
PDEBUG ( " %p %d %d \n " , params - > context , params - > data_type ,
params - > initial_id ) ;
2008-05-19 18:56:13 -03:00
return 0 ;
}
/**
* frees smsclient object and all subclients associated with it
*
2008-06-15 16:50:11 -03:00
* @ param client pointer to smsclient object returned by
* smscore_register_client
2008-05-19 18:56:13 -03:00
*
*/
2008-06-15 17:52:24 -03:00
void smscore_unregister_client ( struct smscore_client_t * client )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_device_t * coredev = client - > coredev ;
2008-05-19 18:56:13 -03:00
unsigned long flags ;
spin_lock_irqsave ( & coredev - > clientslock , flags ) ;
2008-06-15 15:14:13 -03:00
while ( ! list_empty ( & client - > idlist ) ) {
2008-06-15 17:52:24 -03:00
struct smscore_idlist_t * identry =
( struct smscore_idlist_t * ) client - > idlist . next ;
2008-06-15 15:14:13 -03:00
list_del ( & identry - > entry ) ;
kfree ( identry ) ;
2008-05-19 18:56:13 -03:00
}
2008-06-14 00:43:26 -03:00
printk ( KERN_INFO " %s %p \n " , __func__ , client - > context ) ;
2008-05-19 18:56:13 -03:00
list_del ( & client - > entry ) ;
kfree ( client ) ;
spin_unlock_irqrestore ( & coredev - > clientslock , flags ) ;
}
/**
* verifies that source id is not taken by another client ,
* calls device handler to send requests to the device
*
2008-06-15 16:50:11 -03:00
* @ param client pointer to smsclient object returned by
* smscore_register_client
2008-05-19 18:56:13 -03:00
* @ param buffer pointer to a request buffer
* @ param size size ( in bytes ) of request buffer
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smsclient_sendrequest ( struct smscore_client_t * client ,
void * buffer , size_t size )
2008-05-19 18:56:13 -03:00
{
2008-06-15 17:52:24 -03:00
struct smscore_device_t * coredev ;
struct SmsMsgHdr_ST * phdr = ( struct SmsMsgHdr_ST * ) buffer ;
2008-06-14 00:43:26 -03:00
int rc ;
2008-06-15 15:14:13 -03:00
if ( client = = NULL ) {
printk ( KERN_ERR " %s Got NULL client \n " , __func__ ) ;
2008-06-14 00:43:26 -03:00
return - EINVAL ;
}
coredev = client - > coredev ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
/* check that no other channel with same id exists */
if ( coredev = = NULL ) {
printk ( KERN_ERR " %s Got NULL coredev \n " , __func__ ) ;
2008-06-14 00:43:26 -03:00
return - EINVAL ;
}
2008-06-15 15:14:13 -03:00
rc = smscore_validate_client ( client - > coredev , client , 0 ,
phdr - > msgSrcId ) ;
2008-05-19 18:56:13 -03:00
if ( rc < 0 )
return rc ;
return coredev - > sendrequest_handler ( coredev - > context , buffer , size ) ;
}
/**
* return the size of large ( common ) buffer
*
* @ param coredev pointer to a coredev object from clients hotplug
*
* @ return size ( in bytes ) of the buffer
*/
2008-06-15 17:52:24 -03:00
int smscore_get_common_buffer_size ( struct smscore_device_t * coredev )
2008-05-19 18:56:13 -03:00
{
return coredev - > common_buffer_size ;
}
/**
* maps common buffer ( if supported by platform )
*
* @ param coredev pointer to a coredev object from clients hotplug
* @ param vma pointer to vma struct from mmap handler
*
* @ return 0 on success , < 0 on error .
*/
2008-06-15 17:52:24 -03:00
int smscore_map_common_buffer ( struct smscore_device_t * coredev ,
2008-05-06 03:11:51 -03:00
struct vm_area_struct * vma )
2008-05-19 18:56:13 -03:00
{
2008-06-15 15:14:13 -03:00
unsigned long end = vma - > vm_end ,
start = vma - > vm_start ,
size = PAGE_ALIGN ( coredev - > common_buffer_size ) ;
2008-05-19 18:56:13 -03:00
2008-06-15 15:14:13 -03:00
if ( ! ( vma - > vm_flags & ( VM_READ | VM_SHARED ) ) | |
( vma - > vm_flags & VM_WRITE ) ) {
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s invalid vm flags \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
return - EINVAL ;
}
2008-06-15 15:14:13 -03:00
if ( ( end - start ) ! = size ) {
printk ( KERN_INFO " %s invalid size %d expected %d \n " ,
__func__ , ( int ) ( end - start ) , ( int ) size ) ;
2008-05-19 18:56:13 -03:00
return - EINVAL ;
}
2008-06-15 15:14:13 -03:00
if ( remap_pfn_range ( vma , start ,
coredev - > common_buffer_phys > > PAGE_SHIFT ,
2008-06-15 19:39:55 -03:00
size , pgprot_noncached ( vma - > vm_page_prot ) ) ) {
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s remap_page_range failed \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
return - EAGAIN ;
}
return 0 ;
}
int smscore_module_init ( void )
{
2008-05-19 19:09:21 -03:00
int rc = 0 ;
2008-05-19 18:56:13 -03:00
INIT_LIST_HEAD ( & g_smscore_notifyees ) ;
INIT_LIST_HEAD ( & g_smscore_devices ) ;
kmutex_init ( & g_smscore_deviceslock ) ;
INIT_LIST_HEAD ( & g_smscore_registry ) ;
kmutex_init ( & g_smscore_registrylock ) ;
2008-05-22 18:04:36 -03:00
/* USB Register */
rc = smsusb_register ( ) ;
/* DVB Register */
rc = smsdvb_register ( ) ;
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s, rc %d \n " , __func__ , rc ) ;
2008-05-19 18:56:13 -03:00
return rc ;
}
void smscore_module_exit ( void )
{
2008-05-22 18:04:36 -03:00
2008-05-19 18:56:13 -03:00
kmutex_lock ( & g_smscore_deviceslock ) ;
2008-06-15 15:14:13 -03:00
while ( ! list_empty ( & g_smscore_notifyees ) ) {
2008-06-15 17:52:24 -03:00
struct smscore_device_notifyee_t * notifyee =
( struct smscore_device_notifyee_t * )
g_smscore_notifyees . next ;
2008-05-19 18:56:13 -03:00
list_del ( & notifyee - > entry ) ;
kfree ( notifyee ) ;
}
kmutex_unlock ( & g_smscore_deviceslock ) ;
kmutex_lock ( & g_smscore_registrylock ) ;
2008-06-15 15:14:13 -03:00
while ( ! list_empty ( & g_smscore_registry ) ) {
2008-06-15 17:52:24 -03:00
struct smscore_registry_entry_t * entry =
( struct smscore_registry_entry_t * )
g_smscore_registry . next ;
2008-05-19 18:56:13 -03:00
list_del ( & entry - > entry ) ;
kfree ( entry ) ;
}
kmutex_unlock ( & g_smscore_registrylock ) ;
2008-05-22 18:04:36 -03:00
/* DVB UnRegister */
smsdvb_unregister ( ) ;
/* Unregister USB */
smsusb_unregister ( ) ;
2008-05-22 18:30:17 -03:00
printk ( KERN_INFO " %s \n " , __func__ ) ;
2008-05-19 18:56:13 -03:00
}
module_init ( smscore_module_init ) ;
module_exit ( smscore_module_exit ) ;
MODULE_DESCRIPTION ( " smscore " ) ;
2008-06-15 15:14:13 -03:00
MODULE_AUTHOR ( " Siano Mobile Silicon,,, (doronc@siano-ms.com) " ) ;
2008-05-19 18:56:13 -03:00
MODULE_LICENSE ( " GPL " ) ;