2008-09-17 19:34:07 +04:00
/*
* WUSB Wire Adapter : Radio Control Interface ( WUSB [ 8 ] )
* Notification and Event Handling
*
* Copyright ( C ) 2005 - 2006 Intel Corporation
* Inaky Perez - Gonzalez < inaky . perez - gonzalez @ intel . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation .
*
* 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 . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA .
*
*
* The RC interface of the Host Wire Adapter ( USB dongle ) or WHCI PCI
* card delivers a stream of notifications and events to the
* notification end event endpoint or area . This code takes care of
* getting a buffer with that data , breaking it up in separate
* notifications and events and then deliver those .
*
* Events are answers to commands and they carry a context ID that
* associates them to the command . Notifications are that ,
* notifications , they come out of the blue and have a context ID of
* zero . Think of the context ID kind of like a handler . The
* uwb_rc_neh_ * code deals with managing context IDs .
*
* This is why you require a handle to operate on a UWB host . When you
* open a handle a context ID is assigned to you .
*
* So , as it is done is :
*
* 1. Add an event handler [ uwb_rc_neh_add ( ) ] ( assigns a ctx id )
* 2. Issue command [ rc - > cmd ( rc , . . . ) ]
* 3. Arm the timeout timer [ uwb_rc_neh_arm ( ) ]
* 4 , Release the reference to the neh [ uwb_rc_neh_put ( ) ]
* 5. Wait for the callback
* 6. Command result ( RCEB ) is passed to the callback
*
* If ( 2 ) fails , you should remove the handle [ uwb_rc_neh_rm ( ) ]
* instead of arming the timer .
*
* Handles are for using in * serialized * code , single thread .
*
* When the notification / event comes , the IRQ handler / endpoint
* callback passes the data read to uwb_rc_neh_grok ( ) which will break
* it up in a discrete series of events , look up who is listening for
* them and execute the pertinent callbacks .
*
* If the reader detects an error while reading the data stream , call
* uwb_rc_neh_error ( ) .
*
* CONSTRAINTS / ASSUMPTIONS :
*
* - Most notifications / events are small ( less thank .5 k ) , copying
* around is ok .
*
* - Notifications / events are ALWAYS smaller than PAGE_SIZE
*
* - Notifications / events always come in a single piece ( ie : a buffer
* will always contain entire notifications / events ) .
*
* - we cannot know in advance how long each event is ( because they
* lack a length field in their header - - smart move by the standards
* body , btw ) . So we need a facility to get the event size given the
* header . This is what the EST code does ( notif / Event Size
* Tables ) , check nest . c - - as well , you can associate the size to
* the handle [ w / neh - > extra_size ( ) ] .
*
* - Most notifications / events are fixed size ; only a few are variable
* size ( NEST takes care of that ) .
*
* - Listeners of events expect them , so they usually provide a
* buffer , as they know the size . Listeners to notifications don ' t ,
* so we allocate their buffers dynamically .
*/
# include <linux/kernel.h>
# include <linux/timer.h>
# include <linux/err.h>
# include "uwb-internal.h"
/*
* UWB Radio Controller Notification / Event Handle
*
* Represents an entity waiting for an event coming from the UWB Radio
* Controller with a given context id ( context ) and type ( evt_type and
* evt ) . On reception of the notification / event , the callback ( cb ) is
* called with the event .
*
* If the timer expires before the event is received , the callback is
* called with - ETIMEDOUT as the event size .
*/
struct uwb_rc_neh {
struct kref kref ;
struct uwb_rc * rc ;
u8 evt_type ;
__le16 evt ;
u8 context ;
uwb_rc_cmd_cb_f cb ;
void * arg ;
struct timer_list timer ;
struct list_head list_node ;
} ;
static void uwb_rc_neh_timer ( unsigned long arg ) ;
static void uwb_rc_neh_release ( struct kref * kref )
{
struct uwb_rc_neh * neh = container_of ( kref , struct uwb_rc_neh , kref ) ;
kfree ( neh ) ;
}
static void uwb_rc_neh_get ( struct uwb_rc_neh * neh )
{
kref_get ( & neh - > kref ) ;
}
/**
* uwb_rc_neh_put - release reference to a neh
* @ neh : the neh
*/
void uwb_rc_neh_put ( struct uwb_rc_neh * neh )
{
kref_put ( & neh - > kref , uwb_rc_neh_release ) ;
}
/**
* Assigns @ neh a context id from @ rc ' s pool
*
* @ rc : UWB Radio Controller descriptor ; @ rc - > neh_lock taken
* @ neh : Notification / Event Handle
* @ returns 0 if context id was assigned ok ; < 0 errno on error ( if
* all the context IDs are taken ) .
*
* ( assumes @ wa is locked ) .
*
* NOTE : WUSB spec reserves context ids 0x00 for notifications and
* 0xff is invalid , so they must not be used . Initialization
* fills up those two in the bitmap so they are not allocated .
*
2009-09-29 05:43:57 +04:00
* We spread the allocation around to reduce the possibility of two
2008-09-17 19:34:07 +04:00
* consecutive opened @ neh ' s getting the same context ID assigned ( to
* avoid surprises with late events that timed out long time ago ) . So
* first we search from where @ rc - > ctx_roll is , if not found , we
* search from zero .
*/
static
int __uwb_rc_ctx_get ( struct uwb_rc * rc , struct uwb_rc_neh * neh )
{
int result ;
result = find_next_zero_bit ( rc - > ctx_bm , UWB_RC_CTX_MAX ,
rc - > ctx_roll + + ) ;
if ( result < UWB_RC_CTX_MAX )
goto found ;
result = find_first_zero_bit ( rc - > ctx_bm , UWB_RC_CTX_MAX ) ;
if ( result < UWB_RC_CTX_MAX )
goto found ;
return - ENFILE ;
found :
set_bit ( result , rc - > ctx_bm ) ;
neh - > context = result ;
return 0 ;
}
/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
static
void __uwb_rc_ctx_put ( struct uwb_rc * rc , struct uwb_rc_neh * neh )
{
struct device * dev = & rc - > uwb_dev . dev ;
if ( neh - > context = = 0 )
return ;
if ( test_bit ( neh - > context , rc - > ctx_bm ) = = 0 ) {
dev_err ( dev , " context %u not set in bitmap \n " ,
neh - > context ) ;
WARN_ON ( 1 ) ;
}
clear_bit ( neh - > context , rc - > ctx_bm ) ;
neh - > context = 0 ;
}
/**
* uwb_rc_neh_add - add a neh for a radio controller command
* @ rc : the radio controller
* @ cmd : the radio controller command
* @ expected_type : the type of the expected response event
* @ expected_event : the expected event ID
* @ cb : callback for when the event is received
* @ arg : argument for the callback
*
* Creates a neh and adds it to the list of those waiting for an
* event . A context ID will be assigned to the command .
*/
struct uwb_rc_neh * uwb_rc_neh_add ( struct uwb_rc * rc , struct uwb_rccb * cmd ,
u8 expected_type , u16 expected_event ,
uwb_rc_cmd_cb_f cb , void * arg )
{
int result ;
unsigned long flags ;
struct device * dev = & rc - > uwb_dev . dev ;
struct uwb_rc_neh * neh ;
neh = kzalloc ( sizeof ( * neh ) , GFP_KERNEL ) ;
if ( neh = = NULL ) {
result = - ENOMEM ;
goto error_kzalloc ;
}
kref_init ( & neh - > kref ) ;
INIT_LIST_HEAD ( & neh - > list_node ) ;
init_timer ( & neh - > timer ) ;
neh - > timer . function = uwb_rc_neh_timer ;
neh - > timer . data = ( unsigned long ) neh ;
neh - > rc = rc ;
neh - > evt_type = expected_type ;
neh - > evt = cpu_to_le16 ( expected_event ) ;
neh - > cb = cb ;
neh - > arg = arg ;
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
result = __uwb_rc_ctx_get ( rc , neh ) ;
if ( result > = 0 ) {
cmd - > bCommandContext = neh - > context ;
list_add_tail ( & neh - > list_node , & rc - > neh_list ) ;
uwb_rc_neh_get ( neh ) ;
}
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
if ( result < 0 )
goto error_ctx_get ;
return neh ;
error_ctx_get :
kfree ( neh ) ;
error_kzalloc :
dev_err ( dev , " cannot open handle to radio controller: %d \n " , result ) ;
return ERR_PTR ( result ) ;
}
static void __uwb_rc_neh_rm ( struct uwb_rc * rc , struct uwb_rc_neh * neh )
{
__uwb_rc_ctx_put ( rc , neh ) ;
list_del ( & neh - > list_node ) ;
}
/**
* uwb_rc_neh_rm - remove a neh .
* @ rc : the radio controller
* @ neh : the neh to remove
*
* Remove an active neh immediately instead of waiting for the event
* ( or a time out ) .
*/
void uwb_rc_neh_rm ( struct uwb_rc * rc , struct uwb_rc_neh * neh )
{
unsigned long flags ;
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
__uwb_rc_neh_rm ( rc , neh ) ;
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
2008-11-07 21:19:19 +03:00
del_timer_sync ( & neh - > timer ) ;
2008-09-17 19:34:07 +04:00
uwb_rc_neh_put ( neh ) ;
}
/**
* uwb_rc_neh_arm - arm an event handler timeout timer
*
* @ rc : UWB Radio Controller
* @ neh : Notification / event handler for @ rc
*
* The timer is only armed if the neh is active .
*/
void uwb_rc_neh_arm ( struct uwb_rc * rc , struct uwb_rc_neh * neh )
{
unsigned long flags ;
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
if ( neh - > context )
mod_timer ( & neh - > timer ,
jiffies + msecs_to_jiffies ( UWB_RC_CMD_TIMEOUT_MS ) ) ;
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
}
static void uwb_rc_neh_cb ( struct uwb_rc_neh * neh , struct uwb_rceb * rceb , size_t size )
{
( * neh - > cb ) ( neh - > rc , neh - > arg , rceb , size ) ;
uwb_rc_neh_put ( neh ) ;
}
static bool uwb_rc_neh_match ( struct uwb_rc_neh * neh , const struct uwb_rceb * rceb )
{
return neh - > evt_type = = rceb - > bEventType
& & neh - > evt = = rceb - > wEvent
& & neh - > context = = rceb - > bEventContext ;
}
/**
* Find the handle waiting for a RC Radio Control Event
*
* @ rc : UWB Radio Controller
* @ rceb : Pointer to the RCEB buffer
* @ event_size : Pointer to the size of the RCEB buffer . Might be
* adjusted to take into account the @ neh - > extra_size
* settings .
*
* If the listener has no buffer ( NULL buffer ) , one is allocated for
* the right size ( the amount of data received ) . @ neh - > ptr will point
* to the event payload , which always starts with a ' struct
* uwb_rceb ' . kfree ( ) it when done .
*/
static
struct uwb_rc_neh * uwb_rc_neh_lookup ( struct uwb_rc * rc ,
const struct uwb_rceb * rceb )
{
struct uwb_rc_neh * neh = NULL , * h ;
unsigned long flags ;
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
list_for_each_entry ( h , & rc - > neh_list , list_node ) {
if ( uwb_rc_neh_match ( h , rceb ) ) {
neh = h ;
break ;
}
}
if ( neh )
__uwb_rc_neh_rm ( rc , neh ) ;
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
return neh ;
}
2008-12-12 16:28:48 +03:00
/*
2008-09-17 19:34:07 +04:00
* Process notifications coming from the radio control interface
*
* @ rc : UWB Radio Control Interface descriptor
* @ neh : Notification / Event Handler @ neh - > ptr points to
* @ uwb_evt - > buffer .
*
* This function is called by the event / notif handling subsystem when
* notifications arrive ( hwarc_probe ( ) arms a notification / event handle
* that calls back this function for every received notification ; this
* function then will rearm itself ) .
*
* Notification data buffers are dynamically allocated by the NEH
* handling code in neh . c [ uwb_rc_neh_lookup ( ) ] . What is actually
* allocated is space to contain the notification data .
*
* Buffers are prefixed with a Radio Control Event Block ( RCEB ) as
* defined by the WUSB Wired - Adapter Radio Control interface . We
* just use it for the notification code .
*
* On each case statement we just transcode endianess of the different
* fields . We declare a pointer to a RCI definition of an event , and
* then to a UWB definition of the same event ( which are the same ,
* remember ) . Event if we use different pointers
*/
static
void uwb_rc_notif ( struct uwb_rc * rc , struct uwb_rceb * rceb , ssize_t size )
{
struct device * dev = & rc - > uwb_dev . dev ;
struct uwb_event * uwb_evt ;
if ( size = = - ESHUTDOWN )
return ;
if ( size < 0 ) {
dev_err ( dev , " ignoring event with error code %zu \n " ,
size ) ;
return ;
}
uwb_evt = kzalloc ( sizeof ( * uwb_evt ) , GFP_ATOMIC ) ;
if ( unlikely ( uwb_evt = = NULL ) ) {
dev_err ( dev , " no memory to queue event 0x%02x/%04x/%02x \n " ,
rceb - > bEventType , le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext ) ;
return ;
}
uwb_evt - > rc = __uwb_rc_get ( rc ) ; /* will be put by uwbd's uwbd_event_handle() */
uwb_evt - > ts_jiffies = jiffies ;
uwb_evt - > type = UWB_EVT_TYPE_NOTIF ;
uwb_evt - > notif . size = size ;
uwb_evt - > notif . rceb = rceb ;
uwbd_event_queue ( uwb_evt ) ;
}
static void uwb_rc_neh_grok_event ( struct uwb_rc * rc , struct uwb_rceb * rceb , size_t size )
{
struct device * dev = & rc - > uwb_dev . dev ;
struct uwb_rc_neh * neh ;
struct uwb_rceb * notif ;
if ( rceb - > bEventContext = = 0 ) {
notif = kmalloc ( size , GFP_ATOMIC ) ;
if ( notif ) {
memcpy ( notif , rceb , size ) ;
uwb_rc_notif ( rc , notif , size ) ;
} else
dev_err ( dev , " event 0x%02x/%04x/%02x (%zu bytes): no memory \n " ,
rceb - > bEventType , le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext , size ) ;
} else {
neh = uwb_rc_neh_lookup ( rc , rceb ) ;
2008-11-07 21:19:19 +03:00
if ( neh ) {
del_timer_sync ( & neh - > timer ) ;
2008-09-17 19:34:07 +04:00
uwb_rc_neh_cb ( neh , rceb , size ) ;
2008-11-07 21:19:19 +03:00
} else
2008-09-17 19:34:07 +04:00
dev_warn ( dev , " event 0x%02x/%04x/%02x (%zu bytes): nobody cared \n " ,
rceb - > bEventType , le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext , size ) ;
}
}
/**
* Given a buffer with one or more UWB RC events / notifications , break
* them up and dispatch them .
*
* @ rc : UWB Radio Controller
* @ buf : Buffer with the stream of notifications / events
* @ buf_size : Amount of data in the buffer
*
* Note each notification / event starts always with a ' struct
* uwb_rceb ' , so the minimum size if 4 bytes .
*
* The device may pass us events formatted differently than expected .
* These are first filtered , potentially creating a new event in a new
* memory location . If a new event is created by the filter it is also
* freed here .
*
* For each notif / event , tries to guess the size looking at the EST
* tables , then looks for a neh that is waiting for that event and if
* found , copies the payload to the neh ' s buffer and calls it back . If
* not , the data is ignored .
*
* Note that if we can ' t find a size description in the EST tables , we
* still might find a size in the ' neh ' handle in uwb_rc_neh_lookup ( ) .
*
* Assumptions :
*
* @ rc - > neh_lock is NOT taken
*
* We keep track of various sizes here :
* size : contains the size of the buffer that is processed for the
* incoming event . this buffer may contain events that are not
* formatted as WHCI .
* real_size : the actual space taken by this event in the buffer .
* We need to keep track of the real size of an event to be able to
* advance the buffer correctly .
* event_size : the size of the event as expected by the core layer
* [ OR ] the size of the event after filtering . if the filtering
* created a new event in a new memory location then this is
* effectively the size of a new event buffer
*/
void uwb_rc_neh_grok ( struct uwb_rc * rc , void * buf , size_t buf_size )
{
struct device * dev = & rc - > uwb_dev . dev ;
void * itr ;
struct uwb_rceb * rceb ;
size_t size , real_size , event_size ;
int needtofree ;
itr = buf ;
size = buf_size ;
while ( size > 0 ) {
if ( size < sizeof ( * rceb ) ) {
dev_err ( dev , " not enough data in event buffer to "
" process incoming events (%zu left, minimum is "
" %zu) \n " , size , sizeof ( * rceb ) ) ;
break ;
}
rceb = itr ;
if ( rc - > filter_event ) {
needtofree = rc - > filter_event ( rc , & rceb , size ,
& real_size , & event_size ) ;
if ( needtofree < 0 & & needtofree ! = - ENOANO ) {
dev_err ( dev , " BUG: Unable to filter event "
" (0x%02x/%04x/%02x) from "
" device. \n " , rceb - > bEventType ,
le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext ) ;
break ;
}
} else
needtofree = - ENOANO ;
/* do real processing if there was no filtering or the
* filtering didn ' t act */
if ( needtofree = = - ENOANO ) {
ssize_t ret = uwb_est_find_size ( rc , rceb , size ) ;
if ( ret < 0 )
break ;
if ( ret > size ) {
dev_err ( dev , " BUG: hw sent incomplete event "
" 0x%02x/%04x/%02x (%zd bytes), only got "
" %zu bytes. We don't handle that. \n " ,
rceb - > bEventType , le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext , ret , size ) ;
break ;
}
real_size = event_size = ret ;
}
uwb_rc_neh_grok_event ( rc , rceb , event_size ) ;
if ( needtofree = = 1 )
kfree ( rceb ) ;
itr + = real_size ;
size - = real_size ;
}
}
EXPORT_SYMBOL_GPL ( uwb_rc_neh_grok ) ;
/**
* The entity that reads from the device notification / event channel has
* detected an error .
*
* @ rc : UWB Radio Controller
* @ error : Errno error code
*
*/
void uwb_rc_neh_error ( struct uwb_rc * rc , int error )
{
2008-11-07 21:19:19 +03:00
struct uwb_rc_neh * neh ;
2008-09-17 19:34:07 +04:00
unsigned long flags ;
2008-11-07 21:19:19 +03:00
for ( ; ; ) {
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
if ( list_empty ( & rc - > neh_list ) ) {
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
break ;
}
neh = list_first_entry ( & rc - > neh_list , struct uwb_rc_neh , list_node ) ;
2008-09-17 19:34:07 +04:00
__uwb_rc_neh_rm ( rc , neh ) ;
2008-11-07 21:19:19 +03:00
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
del_timer_sync ( & neh - > timer ) ;
2008-09-17 19:34:07 +04:00
uwb_rc_neh_cb ( neh , NULL , error ) ;
}
}
EXPORT_SYMBOL_GPL ( uwb_rc_neh_error ) ;
static void uwb_rc_neh_timer ( unsigned long arg )
{
struct uwb_rc_neh * neh = ( struct uwb_rc_neh * ) arg ;
struct uwb_rc * rc = neh - > rc ;
unsigned long flags ;
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
2008-11-07 21:19:19 +03:00
if ( neh - > context )
__uwb_rc_neh_rm ( rc , neh ) ;
else
neh = NULL ;
2008-09-17 19:34:07 +04:00
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
2008-11-07 21:19:19 +03:00
if ( neh )
uwb_rc_neh_cb ( neh , NULL , - ETIMEDOUT ) ;
2008-09-17 19:34:07 +04:00
}
/** Initializes the @rc's neh subsystem
*/
void uwb_rc_neh_create ( struct uwb_rc * rc )
{
spin_lock_init ( & rc - > neh_lock ) ;
INIT_LIST_HEAD ( & rc - > neh_list ) ;
set_bit ( 0 , rc - > ctx_bm ) ; /* 0 is reserved (see [WUSB] table 8-65) */
set_bit ( 0xff , rc - > ctx_bm ) ; /* and 0xff is invalid */
rc - > ctx_roll = 1 ;
}
/** Release's the @rc's neh subsystem */
void uwb_rc_neh_destroy ( struct uwb_rc * rc )
{
unsigned long flags ;
2008-11-07 21:19:19 +03:00
struct uwb_rc_neh * neh ;
2008-09-17 19:34:07 +04:00
2008-11-07 21:19:19 +03:00
for ( ; ; ) {
spin_lock_irqsave ( & rc - > neh_lock , flags ) ;
if ( list_empty ( & rc - > neh_list ) ) {
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
break ;
}
neh = list_first_entry ( & rc - > neh_list , struct uwb_rc_neh , list_node ) ;
2008-09-17 19:34:07 +04:00
__uwb_rc_neh_rm ( rc , neh ) ;
2008-11-07 21:19:19 +03:00
spin_unlock_irqrestore ( & rc - > neh_lock , flags ) ;
del_timer_sync ( & neh - > timer ) ;
2008-09-17 19:34:07 +04:00
uwb_rc_neh_put ( neh ) ;
}
}