2008-09-17 19:34:15 +04:00
/*
* WUSB Host Wire Adapter : Radio Control Interface ( WUSB [ 8.6 ] )
* Radio Control command / event transport
*
* 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 .
*
*
* Initialize the Radio Control interface Driver .
*
* For each device probed , creates an ' struct hwarc ' which contains
* just the representation of the UWB Radio Controller , and the logic
* for reading notifications and passing them to the UWB Core .
*
* So we initialize all of those , register the UWB Radio Controller
* and setup the notification / event handle to pipe the notifications
* to the UWB management Daemon .
*
* Command and event filtering .
*
* This is the driver for the Radio Control Interface described in WUSB
* 1.0 . The core UWB module assumes that all drivers are compliant to the
* WHCI 0.95 specification . We thus create a filter that parses all
* incoming messages from the ( WUSB 1.0 ) device and manipulate them to
* conform to the WHCI 0.95 specification . Similarly , outgoing messages
* are parsed and manipulated to conform to the WUSB 1.0 compliant messages
* that the device expects . Only a few messages are affected :
* Affected events :
* UWB_RC_EVT_BEACON
* UWB_RC_EVT_BP_SLOT_CHANGE
* UWB_RC_EVT_DRP_AVAIL
* UWB_RC_EVT_DRP
* Affected commands :
* UWB_RC_CMD_SCAN
* UWB_RC_CMD_SET_DRP_IE
*
*
*
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/usb.h>
# include <linux/usb/wusb.h>
# include <linux/usb/wusb-wa.h>
# include <linux/uwb.h>
2008-12-22 21:22:50 +03:00
2008-09-17 19:34:15 +04:00
# include "uwb-internal.h"
2008-09-17 19:34:35 +04:00
/* The device uses commands and events from the WHCI specification, although
* reporting itself as WUSB compliant . */
# define WUSB_QUIRK_WHCI_CMD_EVT 0x01
2008-09-17 19:34:15 +04:00
/**
* Descriptor for an instance of the UWB Radio Control Driver that
* attaches to the RCI interface of the Host Wired Adapter .
*
* Unless there is a lock specific to the ' data members ' , all access
* is protected by uwb_rc - > mutex .
*
* The NEEP ( Notification / Event EndPoint ) URB ( @ neep_urb ) writes to
* @ rd_buffer . Note there is no locking because it is perfectly ( heh ! )
* serialized - - probe ( ) submits an URB , callback is called , processes
* the data ( synchronously ) , submits another URB , and so on . There is
* no concurrent access to the buffer .
*/
struct hwarc {
struct usb_device * usb_dev ;
struct usb_interface * usb_iface ;
struct uwb_rc * uwb_rc ; /* UWB host controller */
struct urb * neep_urb ; /* Notification endpoint handling */
struct edc neep_edc ;
void * rd_buffer ; /* NEEP read buffer */
} ;
/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
struct uwb_rc_evt_beacon_WUSB_0100 {
struct uwb_rceb rceb ;
u8 bChannelNumber ;
__le16 wBPSTOffset ;
u8 bLQI ;
u8 bRSSI ;
__le16 wBeaconInfoLength ;
u8 BeaconInfo [ ] ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
*
* @ header : the incoming event
* @ buf_size : size of buffer containing incoming event
* @ new_size : size of event after filtering completed
*
* The WHCI 0.95 spec has a " Beacon Type " field . This value is unknown at
* the time we receive the beacon from WUSB so we just set it to
* UWB_RC_BEACON_TYPE_NEIGHBOR as a default .
* The solution below allocates memory upon receipt of every beacon from a
* WUSB device . This will deteriorate performance . What is the right way to
* do this ?
*/
static
int hwarc_filter_evt_beacon_WUSB_0100 ( struct uwb_rc * rc ,
struct uwb_rceb * * header ,
const size_t buf_size ,
size_t * new_size )
{
struct uwb_rc_evt_beacon_WUSB_0100 * be ;
struct uwb_rc_evt_beacon * newbe ;
size_t bytes_left , ielength ;
struct device * dev = & rc - > uwb_dev . dev ;
be = container_of ( * header , struct uwb_rc_evt_beacon_WUSB_0100 , rceb ) ;
bytes_left = buf_size ;
if ( bytes_left < sizeof ( * be ) ) {
dev_err ( dev , " Beacon Received Notification: Not enough data "
" to decode for filtering (%zu vs %zu bytes needed) \n " ,
bytes_left , sizeof ( * be ) ) ;
return - EINVAL ;
}
bytes_left - = sizeof ( * be ) ;
ielength = le16_to_cpu ( be - > wBeaconInfoLength ) ;
if ( bytes_left < ielength ) {
dev_err ( dev , " Beacon Received Notification: Not enough data "
" to decode IEs (%zu vs %zu bytes needed) \n " ,
bytes_left , ielength ) ;
return - EINVAL ;
}
newbe = kzalloc ( sizeof ( * newbe ) + ielength , GFP_ATOMIC ) ;
if ( newbe = = NULL )
return - ENOMEM ;
newbe - > rceb = be - > rceb ;
newbe - > bChannelNumber = be - > bChannelNumber ;
newbe - > bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR ;
newbe - > wBPSTOffset = be - > wBPSTOffset ;
newbe - > bLQI = be - > bLQI ;
newbe - > bRSSI = be - > bRSSI ;
newbe - > wBeaconInfoLength = be - > wBeaconInfoLength ;
memcpy ( newbe - > BeaconInfo , be - > BeaconInfo , ielength ) ;
* header = & newbe - > rceb ;
* new_size = sizeof ( * newbe ) + ielength ;
return 1 ; /* calling function will free memory */
}
/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
struct uwb_rc_evt_drp_avail_WUSB_0100 {
struct uwb_rceb rceb ;
__le16 wIELength ;
u8 IEData [ ] ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
*
* @ header : the incoming event
* @ buf_size : size of buffer containing incoming event
* @ new_size : size of event after filtering completed
*/
static
int hwarc_filter_evt_drp_avail_WUSB_0100 ( struct uwb_rc * rc ,
struct uwb_rceb * * header ,
const size_t buf_size ,
size_t * new_size )
{
struct uwb_rc_evt_drp_avail_WUSB_0100 * da ;
struct uwb_rc_evt_drp_avail * newda ;
struct uwb_ie_hdr * ie_hdr ;
size_t bytes_left , ielength ;
struct device * dev = & rc - > uwb_dev . dev ;
da = container_of ( * header , struct uwb_rc_evt_drp_avail_WUSB_0100 , rceb ) ;
bytes_left = buf_size ;
if ( bytes_left < sizeof ( * da ) ) {
dev_err ( dev , " Not enough data to decode DRP Avail "
" Notification for filtering. Expected %zu, "
" received %zu. \n " , ( size_t ) sizeof ( * da ) , bytes_left ) ;
return - EINVAL ;
}
bytes_left - = sizeof ( * da ) ;
ielength = le16_to_cpu ( da - > wIELength ) ;
if ( bytes_left < ielength ) {
dev_err ( dev , " DRP Avail Notification filter: IE length "
" [%zu bytes] does not match actual length "
" [%zu bytes]. \n " , ielength , bytes_left ) ;
return - EINVAL ;
}
if ( ielength < sizeof ( * ie_hdr ) ) {
dev_err ( dev , " DRP Avail Notification filter: Not enough "
" data to decode IE [%zu bytes, %zu needed] \n " ,
ielength , sizeof ( * ie_hdr ) ) ;
return - EINVAL ;
}
ie_hdr = ( void * ) da - > IEData ;
if ( ie_hdr - > length > 32 ) {
dev_err ( dev , " DRP Availability Change event has unexpected "
" length for filtering. Expected < 32 bytes, "
" got %zu bytes. \n " , ( size_t ) ie_hdr - > length ) ;
return - EINVAL ;
}
newda = kzalloc ( sizeof ( * newda ) , GFP_ATOMIC ) ;
if ( newda = = NULL )
return - ENOMEM ;
newda - > rceb = da - > rceb ;
memcpy ( newda - > bmp , ( u8 * ) ie_hdr + sizeof ( * ie_hdr ) , ie_hdr - > length ) ;
* header = & newda - > rceb ;
* new_size = sizeof ( * newda ) ;
return 1 ; /* calling function will free memory */
}
/* DRP notification (WUSB 1.0 [8.6.3.9]) */
struct uwb_rc_evt_drp_WUSB_0100 {
struct uwb_rceb rceb ;
struct uwb_dev_addr wSrcAddr ;
u8 bExplicit ;
__le16 wIELength ;
u8 IEData [ ] ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter WUSB 1.0 DRP Notification to be WHCI 0.95
*
* @ header : the incoming event
* @ buf_size : size of buffer containing incoming event
* @ new_size : size of event after filtering completed
*
* It is hard to manage DRP reservations without having a Reason code .
* Unfortunately there is none in the WUSB spec . We just set the default to
* DRP IE RECEIVED .
* We do not currently use the bBeaconSlotNumber value , so we set this to
* zero for now .
*/
static
int hwarc_filter_evt_drp_WUSB_0100 ( struct uwb_rc * rc ,
struct uwb_rceb * * header ,
const size_t buf_size ,
size_t * new_size )
{
struct uwb_rc_evt_drp_WUSB_0100 * drpev ;
struct uwb_rc_evt_drp * newdrpev ;
size_t bytes_left , ielength ;
struct device * dev = & rc - > uwb_dev . dev ;
drpev = container_of ( * header , struct uwb_rc_evt_drp_WUSB_0100 , rceb ) ;
bytes_left = buf_size ;
if ( bytes_left < sizeof ( * drpev ) ) {
dev_err ( dev , " Not enough data to decode DRP Notification "
" for filtering. Expected %zu, received %zu. \n " ,
( size_t ) sizeof ( * drpev ) , bytes_left ) ;
return - EINVAL ;
}
ielength = le16_to_cpu ( drpev - > wIELength ) ;
bytes_left - = sizeof ( * drpev ) ;
if ( bytes_left < ielength ) {
dev_err ( dev , " DRP Notification filter: header length [%zu "
" bytes] does not match actual length [%zu "
" bytes]. \n " , ielength , bytes_left ) ;
return - EINVAL ;
}
newdrpev = kzalloc ( sizeof ( * newdrpev ) + ielength , GFP_ATOMIC ) ;
if ( newdrpev = = NULL )
return - ENOMEM ;
newdrpev - > rceb = drpev - > rceb ;
newdrpev - > src_addr = drpev - > wSrcAddr ;
newdrpev - > reason = UWB_DRP_NOTIF_DRP_IE_RCVD ;
newdrpev - > beacon_slot_number = 0 ;
newdrpev - > ie_length = drpev - > wIELength ;
memcpy ( newdrpev - > ie_data , drpev - > IEData , ielength ) ;
* header = & newdrpev - > rceb ;
* new_size = sizeof ( * newdrpev ) + ielength ;
return 1 ; /* calling function will free memory */
}
/* Scan Command (WUSB 1.0 [8.6.2.5]) */
struct uwb_rc_cmd_scan_WUSB_0100 {
struct uwb_rccb rccb ;
u8 bChannelNumber ;
u8 bScanState ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
*
* @ header : command sent to device ( compliant to WHCI 0.95 )
* @ size : size of command sent to device
*
* We only reduce the size by two bytes because the WUSB 1.0 scan command
* does not have the last field ( wStarttime ) . Also , make sure we don ' t send
* the device an unexpected scan type .
*/
static
int hwarc_filter_cmd_scan_WUSB_0100 ( struct uwb_rc * rc ,
struct uwb_rccb * * header ,
size_t * size )
{
struct uwb_rc_cmd_scan * sc ;
sc = container_of ( * header , struct uwb_rc_cmd_scan , rccb ) ;
if ( sc - > bScanState = = UWB_SCAN_ONLY_STARTTIME )
sc - > bScanState = UWB_SCAN_ONLY ;
/* Don't send the last two bytes. */
* size - = 2 ;
return 0 ;
}
/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
struct uwb_rccb rccb ;
u8 bExplicit ;
__le16 wIELength ;
struct uwb_ie_drp IEData [ ] ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
*
* @ header : command sent to device ( compliant to WHCI 0.95 )
* @ size : size of command sent to device
*
* WUSB has an extra bExplicit field - we assume always explicit
* negotiation so this field is set . The command expected by the device is
* thus larger than the one prepared by the driver so we need to
* reallocate memory to accommodate this .
* We trust the driver to send us the correct data so no checking is done
* on incoming data - evn though it is variable length .
*/
static
int hwarc_filter_cmd_set_drp_ie_WUSB_0100 ( struct uwb_rc * rc ,
struct uwb_rccb * * header ,
size_t * size )
{
struct uwb_rc_cmd_set_drp_ie * orgcmd ;
struct uwb_rc_cmd_set_drp_ie_WUSB_0100 * cmd ;
size_t ielength ;
orgcmd = container_of ( * header , struct uwb_rc_cmd_set_drp_ie , rccb ) ;
ielength = le16_to_cpu ( orgcmd - > wIELength ) ;
cmd = kzalloc ( sizeof ( * cmd ) + ielength , GFP_KERNEL ) ;
if ( cmd = = NULL )
return - ENOMEM ;
cmd - > rccb = orgcmd - > rccb ;
cmd - > bExplicit = 0 ;
cmd - > wIELength = orgcmd - > wIELength ;
memcpy ( cmd - > IEData , orgcmd - > IEData , ielength ) ;
* header = & cmd - > rccb ;
* size = sizeof ( * cmd ) + ielength ;
return 1 ; /* calling function will free memory */
}
/**
* Filter data from WHCI driver to WUSB device
*
* @ header : WHCI 0.95 compliant command from driver
* @ size : length of command
*
* The routine managing commands to the device ( uwb_rc_cmd ( ) ) will call the
* filtering function pointer ( if it exists ) before it passes any data to
* the device . At this time the command has been formatted according to
* WHCI 0.95 and is ready to be sent to the device .
*
* The filter function will be provided with the current command and its
* length . The function will manipulate the command if necessary and
* potentially reallocate memory for a command that needed more memory that
* the given command . If new memory was created the function will return 1
* to indicate to the calling function that the memory need to be freed
* when not needed any more . The size will contain the new length of the
* command .
* If memory has not been allocated we rely on the original mechanisms to
* free the memory of the command - even when we reduce the value of size .
*/
static
int hwarc_filter_cmd_WUSB_0100 ( struct uwb_rc * rc , struct uwb_rccb * * header ,
size_t * size )
{
int result ;
struct uwb_rccb * rccb = * header ;
int cmd = le16_to_cpu ( rccb - > wCommand ) ;
switch ( cmd ) {
case UWB_RC_CMD_SCAN :
result = hwarc_filter_cmd_scan_WUSB_0100 ( rc , header , size ) ;
break ;
case UWB_RC_CMD_SET_DRP_IE :
result = hwarc_filter_cmd_set_drp_ie_WUSB_0100 ( rc , header , size ) ;
break ;
default :
result = - ENOANO ;
break ;
}
return result ;
}
/**
* Filter data from WHCI driver to WUSB device
*
* @ header : WHCI 0.95 compliant command from driver
* @ size : length of command
*
* Filter commands based on which protocol the device supports . The WUSB
* errata should be the same as WHCI 0.95 so we do not filter that here -
* only WUSB 1.0 .
*/
static
int hwarc_filter_cmd ( struct uwb_rc * rc , struct uwb_rccb * * header ,
size_t * size )
{
int result = - ENOANO ;
if ( rc - > version = = 0x0100 )
result = hwarc_filter_cmd_WUSB_0100 ( rc , header , size ) ;
return result ;
}
/**
* Compute return value as sum of incoming value and value at given offset
*
* @ rceb : event for which we compute the size , it contains a variable
* length field .
* @ core_size : size of the " non variable " part of the event
* @ offset : place in event where the length of the variable part is stored
* @ buf_size : total length of buffer in which event arrived - we need to make
* sure we read the offset in memory that is still part of the event
*/
static
ssize_t hwarc_get_event_size ( struct uwb_rc * rc , const struct uwb_rceb * rceb ,
size_t core_size , size_t offset ,
const size_t buf_size )
{
ssize_t size = - ENOSPC ;
const void * ptr = rceb ;
size_t type_size = sizeof ( __le16 ) ;
struct device * dev = & rc - > uwb_dev . dev ;
if ( offset + type_size > = buf_size ) {
dev_err ( dev , " Not enough data to read extra size of event "
" 0x%02x/%04x/%02x, only got %zu bytes. \n " ,
rceb - > bEventType , le16_to_cpu ( rceb - > wEvent ) ,
rceb - > bEventContext , buf_size ) ;
goto out ;
}
ptr + = offset ;
size = core_size + le16_to_cpu ( * ( __le16 * ) ptr ) ;
out :
return size ;
}
/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
struct uwb_rceb rceb ;
u8 bSlotNumber ;
} __attribute__ ( ( packed ) ) ;
/**
* Filter data from WUSB device to WHCI driver
*
* @ header : incoming event
* @ buf_size : size of buffer in which event arrived
* @ _event_size : actual size of event in the buffer
* @ new_size : size of event after filtered
*
* We don ' t know how the buffer is constructed - there may be more than one
* event in it so buffer length does not determine event length . We first
* determine the expected size of the incoming event . This value is passed
* back only if the actual filtering succeeded ( so we know the computed
* expected size is correct ) . This value will be zero if
* the event did not need any filtering .
*
* WHCI interprets the BP Slot Change event ' s data differently than
* WUSB . The event sizes are exactly the same . The data field
* indicates the new beacon slot in which a RC is transmitting its
* beacon . The maximum value of this is 96 ( wMacBPLength ECMA - 368
* 17.16 ( Table 117 ) ) . We thus know that the WUSB value will not set
* the bit bNoSlot , so we don ' t really do anything ( placeholder ) .
*/
static
int hwarc_filter_event_WUSB_0100 ( struct uwb_rc * rc , struct uwb_rceb * * header ,
const size_t buf_size , size_t * _real_size ,
size_t * _new_size )
{
int result = - ENOANO ;
struct uwb_rceb * rceb = * header ;
int event = le16_to_cpu ( rceb - > wEvent ) ;
size_t event_size ;
size_t core_size , offset ;
if ( rceb - > bEventType ! = UWB_RC_CET_GENERAL )
goto out ;
switch ( event ) {
case UWB_RC_EVT_BEACON :
core_size = sizeof ( struct uwb_rc_evt_beacon_WUSB_0100 ) ;
offset = offsetof ( struct uwb_rc_evt_beacon_WUSB_0100 ,
wBeaconInfoLength ) ;
event_size = hwarc_get_event_size ( rc , rceb , core_size ,
offset , buf_size ) ;
if ( event_size < 0 )
goto out ;
* _real_size = event_size ;
result = hwarc_filter_evt_beacon_WUSB_0100 ( rc , header ,
buf_size , _new_size ) ;
break ;
case UWB_RC_EVT_BP_SLOT_CHANGE :
* _new_size = * _real_size =
sizeof ( struct uwb_rc_evt_bp_slot_change_WUSB_0100 ) ;
result = 0 ;
break ;
case UWB_RC_EVT_DRP_AVAIL :
core_size = sizeof ( struct uwb_rc_evt_drp_avail_WUSB_0100 ) ;
offset = offsetof ( struct uwb_rc_evt_drp_avail_WUSB_0100 ,
wIELength ) ;
event_size = hwarc_get_event_size ( rc , rceb , core_size ,
offset , buf_size ) ;
if ( event_size < 0 )
goto out ;
* _real_size = event_size ;
result = hwarc_filter_evt_drp_avail_WUSB_0100 (
rc , header , buf_size , _new_size ) ;
break ;
case UWB_RC_EVT_DRP :
core_size = sizeof ( struct uwb_rc_evt_drp_WUSB_0100 ) ;
offset = offsetof ( struct uwb_rc_evt_drp_WUSB_0100 , wIELength ) ;
event_size = hwarc_get_event_size ( rc , rceb , core_size ,
offset , buf_size ) ;
if ( event_size < 0 )
goto out ;
* _real_size = event_size ;
result = hwarc_filter_evt_drp_WUSB_0100 ( rc , header ,
buf_size , _new_size ) ;
break ;
default :
break ;
}
out :
return result ;
}
/**
* Filter data from WUSB device to WHCI driver
*
* @ header : incoming event
* @ buf_size : size of buffer in which event arrived
* @ _event_size : actual size of event in the buffer
* @ _new_size : size of event after filtered
*
* Filter events based on which protocol the device supports . The WUSB
* errata should be the same as WHCI 0.95 so we do not filter that here -
* only WUSB 1.0 .
*
* If we don ' t handle it , we return - ENOANO ( why the weird error code ?
* well , so if I get it , I can pinpoint in the code that raised
* it . . . after all , not too many places use the higher error codes ) .
*/
static
int hwarc_filter_event ( struct uwb_rc * rc , struct uwb_rceb * * header ,
const size_t buf_size , size_t * _real_size ,
size_t * _new_size )
{
int result = - ENOANO ;
if ( rc - > version = = 0x0100 )
result = hwarc_filter_event_WUSB_0100 (
rc , header , buf_size , _real_size , _new_size ) ;
return result ;
}
/**
* Execute an UWB RC command on HWA
*
* @ rc : Instance of a Radio Controller that is a HWA
* @ cmd : Buffer containing the RCCB and payload to execute
* @ cmd_size : Size of the command buffer .
*
* NOTE : rc ' s mutex has to be locked
*/
static
int hwarc_cmd ( struct uwb_rc * uwb_rc , const struct uwb_rccb * cmd , size_t cmd_size )
{
struct hwarc * hwarc = uwb_rc - > priv ;
return usb_control_msg (
hwarc - > usb_dev , usb_sndctrlpipe ( hwarc - > usb_dev , 0 ) ,
WA_EXEC_RC_CMD , USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ,
0 , hwarc - > usb_iface - > cur_altsetting - > desc . bInterfaceNumber ,
( void * ) cmd , cmd_size , 100 /* FIXME: this is totally arbitrary */ ) ;
}
static
int hwarc_reset ( struct uwb_rc * uwb_rc )
{
struct hwarc * hwarc = uwb_rc - > priv ;
return usb_reset_device ( hwarc - > usb_dev ) ;
}
/**
* Callback for the notification and event endpoint
*
* Check ' s that everything is fine and then passes the read data to
* the notification / event handling mechanism ( neh ) .
*/
static
void hwarc_neep_cb ( struct urb * urb )
{
struct hwarc * hwarc = urb - > context ;
struct usb_interface * usb_iface = hwarc - > usb_iface ;
struct device * dev = & usb_iface - > dev ;
int result ;
switch ( result = urb - > status ) {
case 0 :
uwb_rc_neh_grok ( hwarc - > uwb_rc , urb - > transfer_buffer ,
urb - > actual_length ) ;
break ;
case - ECONNRESET : /* Not an error, but a controlled situation; */
case - ENOENT : /* (we killed the URB)...so, no broadcast */
goto out ;
case - ESHUTDOWN : /* going away! */
goto out ;
default : /* On general errors, retry unless it gets ugly */
if ( edc_inc ( & hwarc - > neep_edc , EDC_MAX_ERRORS ,
EDC_ERROR_TIMEFRAME ) )
goto error_exceeded ;
dev_err ( dev , " NEEP: URB error %d \n " , urb - > status ) ;
}
result = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( result < 0 ) {
dev_err ( dev , " NEEP: Can't resubmit URB (%d) resetting device \n " ,
result ) ;
goto error ;
}
out :
return ;
error_exceeded :
dev_err ( dev , " NEEP: URB max acceptable errors "
" exceeded, resetting device \n " ) ;
error :
uwb_rc_neh_error ( hwarc - > uwb_rc , result ) ;
uwb_rc_reset_all ( hwarc - > uwb_rc ) ;
return ;
}
static void hwarc_init ( struct hwarc * hwarc )
{
edc_init ( & hwarc - > neep_edc ) ;
}
/**
* Initialize the notification / event endpoint stuff
*
* Note this is effectively a parallel thread ; it knows that
* hwarc - > uwb_rc always exists because the existence of a ' hwarc '
* means that there is a reverence on the hwarc - > uwb_rc ( see
* _probe ( ) ) , and thus _neep_cb ( ) can execute safely .
*/
static int hwarc_neep_init ( struct uwb_rc * rc )
{
struct hwarc * hwarc = rc - > priv ;
struct usb_interface * iface = hwarc - > usb_iface ;
struct usb_device * usb_dev = interface_to_usbdev ( iface ) ;
struct device * dev = & iface - > dev ;
int result ;
struct usb_endpoint_descriptor * epd ;
epd = & iface - > cur_altsetting - > endpoint [ 0 ] . desc ;
hwarc - > rd_buffer = ( void * ) __get_free_page ( GFP_KERNEL ) ;
if ( hwarc - > rd_buffer = = NULL ) {
dev_err ( dev , " Unable to allocate notification's read buffer \n " ) ;
goto error_rd_buffer ;
}
hwarc - > neep_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( hwarc - > neep_urb = = NULL ) {
dev_err ( dev , " Unable to allocate notification URB \n " ) ;
goto error_urb_alloc ;
}
usb_fill_int_urb ( hwarc - > neep_urb , usb_dev ,
usb_rcvintpipe ( usb_dev , epd - > bEndpointAddress ) ,
hwarc - > rd_buffer , PAGE_SIZE ,
hwarc_neep_cb , hwarc , epd - > bInterval ) ;
result = usb_submit_urb ( hwarc - > neep_urb , GFP_ATOMIC ) ;
if ( result < 0 ) {
dev_err ( dev , " Cannot submit notification URB: %d \n " , result ) ;
goto error_neep_submit ;
}
return 0 ;
error_neep_submit :
usb_free_urb ( hwarc - > neep_urb ) ;
error_urb_alloc :
free_page ( ( unsigned long ) hwarc - > rd_buffer ) ;
error_rd_buffer :
return - ENOMEM ;
}
/** Clean up all the notification endpoint resources */
static void hwarc_neep_release ( struct uwb_rc * rc )
{
struct hwarc * hwarc = rc - > priv ;
usb_kill_urb ( hwarc - > neep_urb ) ;
usb_free_urb ( hwarc - > neep_urb ) ;
free_page ( ( unsigned long ) hwarc - > rd_buffer ) ;
}
/**
* Get the version from class - specific descriptor
*
* NOTE : this descriptor comes with the big bundled configuration
* descriptor that includes the interfaces ' and endpoints ' , so
* we just look for it in the cached copy kept by the USB stack .
*
* NOTE2 : We convert LE fields to CPU order .
*/
static int hwarc_get_version ( struct uwb_rc * rc )
{
int result ;
struct hwarc * hwarc = rc - > priv ;
struct uwb_rc_control_intf_class_desc * descr ;
struct device * dev = & rc - > uwb_dev . dev ;
struct usb_device * usb_dev = hwarc - > usb_dev ;
char * itr ;
struct usb_descriptor_header * hdr ;
size_t itr_size , actconfig_idx ;
u16 version ;
actconfig_idx = ( usb_dev - > actconfig - usb_dev - > config ) /
sizeof ( usb_dev - > config [ 0 ] ) ;
itr = usb_dev - > rawdescriptors [ actconfig_idx ] ;
itr_size = le16_to_cpu ( usb_dev - > actconfig - > desc . wTotalLength ) ;
while ( itr_size > = sizeof ( * hdr ) ) {
hdr = ( struct usb_descriptor_header * ) itr ;
2008-12-22 21:22:50 +03:00
dev_dbg ( dev , " Extra device descriptor: "
" type %02x/%u bytes @ %zu (%zu left) \n " ,
hdr - > bDescriptorType , hdr - > bLength ,
( itr - usb_dev - > rawdescriptors [ actconfig_idx ] ) ,
itr_size ) ;
2008-09-17 19:34:15 +04:00
if ( hdr - > bDescriptorType = = USB_DT_CS_RADIO_CONTROL )
goto found ;
itr + = hdr - > bLength ;
itr_size - = hdr - > bLength ;
}
dev_err ( dev , " cannot find Radio Control Interface Class descriptor \n " ) ;
return - ENODEV ;
found :
result = - EINVAL ;
if ( hdr - > bLength > itr_size ) { /* is it available? */
dev_err ( dev , " incomplete Radio Control Interface Class "
" descriptor (%zu bytes left, %u needed) \n " ,
itr_size , hdr - > bLength ) ;
goto error ;
}
if ( hdr - > bLength < sizeof ( * descr ) ) {
dev_err ( dev , " short Radio Control Interface Class "
" descriptor \n " ) ;
goto error ;
}
descr = ( struct uwb_rc_control_intf_class_desc * ) hdr ;
/* Make LE fields CPU order */
version = __le16_to_cpu ( descr - > bcdRCIVersion ) ;
if ( version ! = 0x0100 ) {
dev_err ( dev , " Device reports protocol version 0x%04x. We "
" do not support that. \n " , version ) ;
result = - EINVAL ;
goto error ;
}
rc - > version = version ;
2008-12-22 21:22:50 +03:00
dev_dbg ( dev , " Device supports WUSB protocol version 0x%04x \n " , rc - > version ) ;
2008-09-17 19:34:15 +04:00
result = 0 ;
error :
return result ;
}
/*
* By creating a ' uwb_rc ' , we have a reference on it - - that reference
* is the one we drop when we disconnect .
*
* No need to switch altsettings ; according to WUSB1 .0 [ 8.6 .1 .1 ] , there
* is only one altsetting allowed .
*/
static int hwarc_probe ( struct usb_interface * iface ,
const struct usb_device_id * id )
{
int result ;
struct uwb_rc * uwb_rc ;
struct hwarc * hwarc ;
struct device * dev = & iface - > dev ;
result = - ENOMEM ;
uwb_rc = uwb_rc_alloc ( ) ;
if ( uwb_rc = = NULL ) {
dev_err ( dev , " unable to allocate RC instance \n " ) ;
goto error_rc_alloc ;
}
hwarc = kzalloc ( sizeof ( * hwarc ) , GFP_KERNEL ) ;
if ( hwarc = = NULL ) {
dev_err ( dev , " unable to allocate HWA RC instance \n " ) ;
goto error_alloc ;
}
hwarc_init ( hwarc ) ;
hwarc - > usb_dev = usb_get_dev ( interface_to_usbdev ( iface ) ) ;
hwarc - > usb_iface = usb_get_intf ( iface ) ;
hwarc - > uwb_rc = uwb_rc ;
uwb_rc - > owner = THIS_MODULE ;
uwb_rc - > start = hwarc_neep_init ;
uwb_rc - > stop = hwarc_neep_release ;
uwb_rc - > cmd = hwarc_cmd ;
uwb_rc - > reset = hwarc_reset ;
2008-09-17 19:34:35 +04:00
if ( id - > driver_info & WUSB_QUIRK_WHCI_CMD_EVT ) {
uwb_rc - > filter_cmd = NULL ;
uwb_rc - > filter_event = NULL ;
} else {
uwb_rc - > filter_cmd = hwarc_filter_cmd ;
uwb_rc - > filter_event = hwarc_filter_event ;
}
2008-09-17 19:34:15 +04:00
result = uwb_rc_add ( uwb_rc , dev , hwarc ) ;
if ( result < 0 )
goto error_rc_add ;
result = hwarc_get_version ( uwb_rc ) ;
if ( result < 0 ) {
dev_err ( dev , " cannot retrieve version of RC \n " ) ;
goto error_get_version ;
}
usb_set_intfdata ( iface , hwarc ) ;
return 0 ;
error_get_version :
uwb_rc_rm ( uwb_rc ) ;
error_rc_add :
usb_put_intf ( iface ) ;
usb_put_dev ( hwarc - > usb_dev ) ;
error_alloc :
uwb_rc_put ( uwb_rc ) ;
error_rc_alloc :
return result ;
}
static void hwarc_disconnect ( struct usb_interface * iface )
{
struct hwarc * hwarc = usb_get_intfdata ( iface ) ;
struct uwb_rc * uwb_rc = hwarc - > uwb_rc ;
usb_set_intfdata ( hwarc - > usb_iface , NULL ) ;
uwb_rc_rm ( uwb_rc ) ;
usb_put_intf ( hwarc - > usb_iface ) ;
usb_put_dev ( hwarc - > usb_dev ) ;
kfree ( hwarc ) ;
uwb_rc_put ( uwb_rc ) ; /* when creating the device, refcount = 1 */
}
2008-11-07 20:37:33 +03:00
static int hwarc_pre_reset ( struct usb_interface * iface )
{
struct hwarc * hwarc = usb_get_intfdata ( iface ) ;
struct uwb_rc * uwb_rc = hwarc - > uwb_rc ;
uwb_rc_pre_reset ( uwb_rc ) ;
return 0 ;
}
static int hwarc_post_reset ( struct usb_interface * iface )
{
struct hwarc * hwarc = usb_get_intfdata ( iface ) ;
struct uwb_rc * uwb_rc = hwarc - > uwb_rc ;
uwb_rc_post_reset ( uwb_rc ) ;
return 0 ;
}
2008-09-17 19:34:15 +04:00
/** USB device ID's that we handle */
static struct usb_device_id hwarc_id_table [ ] = {
2008-09-17 19:34:35 +04:00
/* D-Link DUB-1210 */
{ USB_DEVICE_AND_INTERFACE_INFO ( 0x07d1 , 0x3d02 , 0xe0 , 0x01 , 0x02 ) ,
. driver_info = WUSB_QUIRK_WHCI_CMD_EVT } ,
2008-09-17 19:34:36 +04:00
/* Intel i1480 (using firmware 1.3PA2-20070828) */
{ USB_DEVICE_AND_INTERFACE_INFO ( 0x8086 , 0x0c3b , 0xe0 , 0x01 , 0x02 ) ,
. driver_info = WUSB_QUIRK_WHCI_CMD_EVT } ,
2008-09-17 19:34:35 +04:00
/* Generic match for the Radio Control interface */
2008-09-17 19:34:15 +04:00
{ USB_INTERFACE_INFO ( 0xe0 , 0x01 , 0x02 ) , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , hwarc_id_table ) ;
static struct usb_driver hwarc_driver = {
. name = " hwa-rc " ,
2008-11-07 20:37:33 +03:00
. id_table = hwarc_id_table ,
2008-09-17 19:34:15 +04:00
. probe = hwarc_probe ,
. disconnect = hwarc_disconnect ,
2008-11-07 20:37:33 +03:00
. pre_reset = hwarc_pre_reset ,
. post_reset = hwarc_post_reset ,
2008-09-17 19:34:15 +04:00
} ;
static int __init hwarc_driver_init ( void )
{
2008-12-22 21:22:50 +03:00
return usb_register ( & hwarc_driver ) ;
2008-09-17 19:34:15 +04:00
}
module_init ( hwarc_driver_init ) ;
static void __exit hwarc_driver_exit ( void )
{
usb_deregister ( & hwarc_driver ) ;
}
module_exit ( hwarc_driver_exit ) ;
MODULE_AUTHOR ( " Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> " ) ;
MODULE_DESCRIPTION ( " Host Wireless Adapter Radio Control Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;