2007-09-25 17:57:13 -07:00
/*
2009-01-17 20:42:32 +01:00
Copyright ( C ) 2004 - 2009 rt2x00 SourceForge Project
2007-09-25 17:57:13 -07:00
< http : //rt2x00.serialmonkey.com>
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the
Free Software Foundation , Inc . ,
59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/*
Module : rt2x00lib
Abstract : rt2x00 debugfs specific routines .
*/
# include <linux/debugfs.h>
# include <linux/kernel.h>
# include <linux/module.h>
2007-11-27 21:49:29 +01:00
# include <linux/poll.h>
2007-09-25 17:57:13 -07:00
# include <linux/uaccess.h>
# include "rt2x00.h"
# include "rt2x00lib.h"
2007-11-27 21:49:29 +01:00
# include "rt2x00dump.h"
2007-09-25 17:57:13 -07:00
2008-02-10 22:50:28 +01:00
# define MAX_LINE_LENGTH 64
2007-09-25 17:57:13 -07:00
2008-08-04 16:37:44 +02:00
struct rt2x00debug_crypto {
unsigned long success ;
unsigned long icv_error ;
unsigned long mic_error ;
unsigned long key_error ;
} ;
2007-09-25 17:57:13 -07:00
struct rt2x00debug_intf {
/*
* Pointer to driver structure where
* this debugfs entry belongs to .
*/
struct rt2x00_dev * rt2x00dev ;
/*
* Reference to the rt2x00debug structure
* which can be used to communicate with
* the registers .
*/
const struct rt2x00debug * debug ;
/*
* Debugfs entries for :
* - driver folder
2007-11-27 21:48:16 +01:00
* - driver file
* - chipset file
* - device flags file
* - register folder
* - csr offset / value files
* - eeprom offset / value files
* - bbp offset / value files
* - rf offset / value files
2008-02-10 22:50:28 +01:00
* - queue folder
2007-11-27 21:49:29 +01:00
* - frame dump file
2008-02-10 22:50:28 +01:00
* - queue stats file
2008-08-04 16:37:44 +02:00
* - crypto stats file
2007-09-25 17:57:13 -07:00
*/
struct dentry * driver_folder ;
struct dentry * driver_entry ;
struct dentry * chipset_entry ;
2007-09-25 20:13:51 +02:00
struct dentry * dev_flags ;
2007-11-27 21:48:16 +01:00
struct dentry * register_folder ;
2007-09-25 17:57:13 -07:00
struct dentry * csr_off_entry ;
struct dentry * csr_val_entry ;
struct dentry * eeprom_off_entry ;
struct dentry * eeprom_val_entry ;
struct dentry * bbp_off_entry ;
struct dentry * bbp_val_entry ;
struct dentry * rf_off_entry ;
struct dentry * rf_val_entry ;
2008-02-10 22:50:28 +01:00
struct dentry * queue_folder ;
struct dentry * queue_frame_dump_entry ;
struct dentry * queue_stats_entry ;
2008-08-04 16:37:44 +02:00
struct dentry * crypto_stats_entry ;
2007-11-27 21:49:29 +01:00
/*
* The frame dump file only allows a single reader ,
* so we need to store the current state here .
*/
unsigned long frame_dump_flags ;
# define FRAME_DUMP_FILE_OPEN 1
/*
* We queue each frame before dumping it to the user ,
* per read command we will pass a single skb structure
* so we should be prepared to queue multiple sk buffers
* before sending it to userspace .
*/
struct sk_buff_head frame_dump_skbqueue ;
wait_queue_head_t frame_dump_waitqueue ;
2007-09-25 17:57:13 -07:00
2008-08-04 16:37:44 +02:00
/*
* HW crypto statistics .
* All statistics are stored seperately per cipher type .
*/
struct rt2x00debug_crypto crypto_stats [ CIPHER_MAX ] ;
2007-09-25 17:57:13 -07:00
/*
* Driver and chipset files will use a data buffer
* that has been created in advance . This will simplify
* the code since we can use the debugfs functions .
*/
struct debugfs_blob_wrapper driver_blob ;
struct debugfs_blob_wrapper chipset_blob ;
/*
* Requested offset for each register type .
*/
unsigned int offset_csr ;
unsigned int offset_eeprom ;
unsigned int offset_bbp ;
unsigned int offset_rf ;
} ;
2008-08-04 16:37:44 +02:00
void rt2x00debug_update_crypto ( struct rt2x00_dev * rt2x00dev ,
2008-12-20 10:53:29 +01:00
struct rxdone_entry_desc * rxdesc )
2008-08-04 16:37:44 +02:00
{
struct rt2x00debug_intf * intf = rt2x00dev - > debugfs_intf ;
2008-12-20 10:53:29 +01:00
enum cipher cipher = rxdesc - > cipher ;
enum rx_crypto status = rxdesc - > cipher_status ;
2008-08-04 16:37:44 +02:00
if ( cipher = = CIPHER_TKIP_NO_MIC )
cipher = CIPHER_TKIP ;
2009-05-20 02:12:56 +02:00
if ( cipher = = CIPHER_NONE | | cipher > = CIPHER_MAX )
2008-08-04 16:37:44 +02:00
return ;
/* Remove CIPHER_NONE index */
cipher - - ;
intf - > crypto_stats [ cipher ] . success + = ( status = = RX_CRYPTO_SUCCESS ) ;
intf - > crypto_stats [ cipher ] . icv_error + = ( status = = RX_CRYPTO_FAIL_ICV ) ;
intf - > crypto_stats [ cipher ] . mic_error + = ( status = = RX_CRYPTO_FAIL_MIC ) ;
intf - > crypto_stats [ cipher ] . key_error + = ( status = = RX_CRYPTO_FAIL_KEY ) ;
}
2007-11-27 21:49:29 +01:00
void rt2x00debug_dump_frame ( struct rt2x00_dev * rt2x00dev ,
2008-05-10 13:41:32 +02:00
enum rt2x00_dump_type type , struct sk_buff * skb )
2007-11-27 21:49:29 +01:00
{
struct rt2x00debug_intf * intf = rt2x00dev - > debugfs_intf ;
2008-02-05 16:42:23 -05:00
struct skb_frame_desc * desc = get_skb_frame_desc ( skb ) ;
2007-11-27 21:49:29 +01:00
struct sk_buff * skbcopy ;
struct rt2x00dump_hdr * dump_hdr ;
struct timeval timestamp ;
do_gettimeofday ( & timestamp ) ;
if ( ! test_bit ( FRAME_DUMP_FILE_OPEN , & intf - > frame_dump_flags ) )
return ;
if ( skb_queue_len ( & intf - > frame_dump_skbqueue ) > 20 ) {
DEBUG ( rt2x00dev , " txrx dump queue length exceeded. \n " ) ;
return ;
}
2008-06-06 22:54:08 +02:00
skbcopy = alloc_skb ( sizeof ( * dump_hdr ) + desc - > desc_len + skb - > len ,
2007-11-27 21:49:29 +01:00
GFP_ATOMIC ) ;
if ( ! skbcopy ) {
DEBUG ( rt2x00dev , " Failed to copy skb for dump. \n " ) ;
return ;
}
dump_hdr = ( struct rt2x00dump_hdr * ) skb_put ( skbcopy , sizeof ( * dump_hdr ) ) ;
dump_hdr - > version = cpu_to_le32 ( DUMP_HEADER_VERSION ) ;
dump_hdr - > header_length = cpu_to_le32 ( sizeof ( * dump_hdr ) ) ;
dump_hdr - > desc_length = cpu_to_le32 ( desc - > desc_len ) ;
2008-06-06 22:54:08 +02:00
dump_hdr - > data_length = cpu_to_le32 ( skb - > len ) ;
2007-11-27 21:49:29 +01:00
dump_hdr - > chip_rt = cpu_to_le16 ( rt2x00dev - > chip . rt ) ;
dump_hdr - > chip_rf = cpu_to_le16 ( rt2x00dev - > chip . rf ) ;
dump_hdr - > chip_rev = cpu_to_le32 ( rt2x00dev - > chip . rev ) ;
2008-05-10 13:41:32 +02:00
dump_hdr - > type = cpu_to_le16 ( type ) ;
2008-02-05 16:42:23 -05:00
dump_hdr - > queue_index = desc - > entry - > queue - > qid ;
2008-01-06 23:39:25 +01:00
dump_hdr - > entry_index = desc - > entry - > entry_idx ;
2007-11-27 21:49:29 +01:00
dump_hdr - > timestamp_sec = cpu_to_le32 ( timestamp . tv_sec ) ;
dump_hdr - > timestamp_usec = cpu_to_le32 ( timestamp . tv_usec ) ;
memcpy ( skb_put ( skbcopy , desc - > desc_len ) , desc - > desc , desc - > desc_len ) ;
2008-06-06 22:54:08 +02:00
memcpy ( skb_put ( skbcopy , skb - > len ) , skb - > data , skb - > len ) ;
2007-11-27 21:49:29 +01:00
skb_queue_tail ( & intf - > frame_dump_skbqueue , skbcopy ) ;
wake_up_interruptible ( & intf - > frame_dump_waitqueue ) ;
/*
* Verify that the file has not been closed while we were working .
*/
if ( ! test_bit ( FRAME_DUMP_FILE_OPEN , & intf - > frame_dump_flags ) )
skb_queue_purge ( & intf - > frame_dump_skbqueue ) ;
}
2007-09-25 17:57:13 -07:00
static int rt2x00debug_file_open ( struct inode * inode , struct file * file )
{
struct rt2x00debug_intf * intf = inode - > i_private ;
file - > private_data = inode - > i_private ;
if ( ! try_module_get ( intf - > debug - > owner ) )
return - EBUSY ;
return 0 ;
}
static int rt2x00debug_file_release ( struct inode * inode , struct file * file )
{
struct rt2x00debug_intf * intf = file - > private_data ;
module_put ( intf - > debug - > owner ) ;
return 0 ;
}
2008-02-05 16:42:23 -05:00
static int rt2x00debug_open_queue_dump ( struct inode * inode , struct file * file )
2007-11-27 21:49:29 +01:00
{
struct rt2x00debug_intf * intf = inode - > i_private ;
int retval ;
retval = rt2x00debug_file_open ( inode , file ) ;
if ( retval )
return retval ;
if ( test_and_set_bit ( FRAME_DUMP_FILE_OPEN , & intf - > frame_dump_flags ) ) {
rt2x00debug_file_release ( inode , file ) ;
return - EBUSY ;
}
return 0 ;
}
2008-02-05 16:42:23 -05:00
static int rt2x00debug_release_queue_dump ( struct inode * inode , struct file * file )
2007-11-27 21:49:29 +01:00
{
struct rt2x00debug_intf * intf = inode - > i_private ;
skb_queue_purge ( & intf - > frame_dump_skbqueue ) ;
clear_bit ( FRAME_DUMP_FILE_OPEN , & intf - > frame_dump_flags ) ;
return rt2x00debug_file_release ( inode , file ) ;
}
2008-02-05 16:42:23 -05:00
static ssize_t rt2x00debug_read_queue_dump ( struct file * file ,
char __user * buf ,
size_t length ,
loff_t * offset )
2007-11-27 21:49:29 +01:00
{
struct rt2x00debug_intf * intf = file - > private_data ;
struct sk_buff * skb ;
size_t status ;
int retval ;
if ( file - > f_flags & O_NONBLOCK )
return - EAGAIN ;
retval =
wait_event_interruptible ( intf - > frame_dump_waitqueue ,
( skb =
skb_dequeue ( & intf - > frame_dump_skbqueue ) ) ) ;
if ( retval )
return retval ;
status = min ( ( size_t ) skb - > len , length ) ;
if ( copy_to_user ( buf , skb - > data , status ) ) {
status = - EFAULT ;
goto exit ;
}
* offset + = status ;
exit :
kfree_skb ( skb ) ;
return status ;
}
2008-02-05 16:42:23 -05:00
static unsigned int rt2x00debug_poll_queue_dump ( struct file * file ,
2008-10-17 12:16:17 -07:00
poll_table * wait )
2007-11-27 21:49:29 +01:00
{
struct rt2x00debug_intf * intf = file - > private_data ;
poll_wait ( file , & intf - > frame_dump_waitqueue , wait ) ;
if ( ! skb_queue_empty ( & intf - > frame_dump_skbqueue ) )
return POLLOUT | POLLWRNORM ;
return 0 ;
}
2008-02-05 16:42:23 -05:00
static const struct file_operations rt2x00debug_fop_queue_dump = {
2007-11-27 21:49:29 +01:00
. owner = THIS_MODULE ,
2008-02-05 16:42:23 -05:00
. read = rt2x00debug_read_queue_dump ,
. poll = rt2x00debug_poll_queue_dump ,
. open = rt2x00debug_open_queue_dump ,
. release = rt2x00debug_release_queue_dump ,
2007-11-27 21:49:29 +01:00
} ;
2008-02-10 22:50:28 +01:00
static ssize_t rt2x00debug_read_queue_stats ( struct file * file ,
char __user * buf ,
size_t length ,
loff_t * offset )
{
struct rt2x00debug_intf * intf = file - > private_data ;
struct data_queue * queue ;
2008-03-09 22:44:30 +01:00
unsigned long irqflags ;
2008-02-10 22:50:28 +01:00
unsigned int lines = 1 + intf - > rt2x00dev - > data_queues ;
size_t size ;
char * data ;
char * temp ;
if ( * offset )
return 0 ;
data = kzalloc ( lines * MAX_LINE_LENGTH , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
temp = data +
sprintf ( data , " qid \t count \t limit \t length \t index \t done \t crypto \n " ) ;
queue_for_each ( intf - > rt2x00dev , queue ) {
2008-03-09 22:44:30 +01:00
spin_lock_irqsave ( & queue - > lock , irqflags ) ;
2008-02-10 22:50:28 +01:00
temp + = sprintf ( temp , " %d \t %d \t %d \t %d \t %d \t %d \t %d \n " , queue - > qid ,
queue - > count , queue - > limit , queue - > length ,
queue - > index [ Q_INDEX ] ,
queue - > index [ Q_INDEX_DONE ] ,
queue - > index [ Q_INDEX_CRYPTO ] ) ;
2008-03-09 22:44:30 +01:00
spin_unlock_irqrestore ( & queue - > lock , irqflags ) ;
2008-02-10 22:50:28 +01:00
}
size = strlen ( data ) ;
size = min ( size , length ) ;
if ( copy_to_user ( buf , data , size ) ) {
kfree ( data ) ;
return - EFAULT ;
}
kfree ( data ) ;
* offset + = size ;
return size ;
}
static const struct file_operations rt2x00debug_fop_queue_stats = {
. owner = THIS_MODULE ,
. read = rt2x00debug_read_queue_stats ,
. open = rt2x00debug_file_open ,
. release = rt2x00debug_file_release ,
} ;
2008-08-04 16:37:44 +02:00
# ifdef CONFIG_RT2X00_LIB_CRYPTO
static ssize_t rt2x00debug_read_crypto_stats ( struct file * file ,
char __user * buf ,
size_t length ,
loff_t * offset )
{
struct rt2x00debug_intf * intf = file - > private_data ;
char * name [ ] = { " WEP64 " , " WEP128 " , " TKIP " , " AES " } ;
char * data ;
char * temp ;
size_t size ;
unsigned int i ;
if ( * offset )
return 0 ;
2008-10-17 12:16:17 -07:00
data = kzalloc ( ( 1 + CIPHER_MAX ) * MAX_LINE_LENGTH , GFP_KERNEL ) ;
2008-08-04 16:37:44 +02:00
if ( ! data )
return - ENOMEM ;
temp = data ;
temp + = sprintf ( data , " cipher \t success \t icv err \t mic err \t key err \n " ) ;
for ( i = 0 ; i < CIPHER_MAX ; i + + ) {
temp + = sprintf ( temp , " %s \t %lu \t %lu \t %lu \t %lu \n " , name [ i ] ,
intf - > crypto_stats [ i ] . success ,
intf - > crypto_stats [ i ] . icv_error ,
intf - > crypto_stats [ i ] . mic_error ,
intf - > crypto_stats [ i ] . key_error ) ;
}
size = strlen ( data ) ;
size = min ( size , length ) ;
if ( copy_to_user ( buf , data , size ) ) {
kfree ( data ) ;
return - EFAULT ;
}
kfree ( data ) ;
* offset + = size ;
return size ;
}
static const struct file_operations rt2x00debug_fop_crypto_stats = {
. owner = THIS_MODULE ,
. read = rt2x00debug_read_crypto_stats ,
. open = rt2x00debug_file_open ,
. release = rt2x00debug_file_release ,
} ;
# endif
2007-09-25 17:57:13 -07:00
# define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
static ssize_t rt2x00debug_read_ # # __name ( struct file * file , \
char __user * buf , \
size_t length , \
loff_t * offset ) \
{ \
2007-11-27 21:48:16 +01:00
struct rt2x00debug_intf * intf = file - > private_data ; \
2007-09-25 17:57:13 -07:00
const struct rt2x00debug * debug = intf - > debug ; \
char line [ 16 ] ; \
size_t size ; \
2008-10-29 19:41:03 +01:00
unsigned int index = intf - > offset_ # # __name ; \
2007-09-25 17:57:13 -07:00
__type value ; \
\
if ( * offset ) \
return 0 ; \
\
2008-10-29 19:41:03 +01:00
if ( index > = debug - > __name . word_count ) \
2007-09-25 17:57:13 -07:00
return - EINVAL ; \
\
2009-02-17 14:04:29 +01:00
index + = ( debug - > __name . word_base / \
debug - > __name . word_size ) ; \
\
2008-10-29 19:41:03 +01:00
if ( debug - > __name . flags & RT2X00DEBUGFS_OFFSET ) \
index * = debug - > __name . word_size ; \
\
debug - > __name . read ( intf - > rt2x00dev , index , & value ) ; \
2007-09-25 17:57:13 -07:00
\
size = sprintf ( line , __format , value ) ; \
\
if ( copy_to_user ( buf , line , size ) ) \
return - EFAULT ; \
\
* offset + = size ; \
return size ; \
}
# define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
static ssize_t rt2x00debug_write_ # # __name ( struct file * file , \
const char __user * buf , \
size_t length , \
loff_t * offset ) \
{ \
2007-11-27 21:48:16 +01:00
struct rt2x00debug_intf * intf = file - > private_data ; \
2007-09-25 17:57:13 -07:00
const struct rt2x00debug * debug = intf - > debug ; \
char line [ 16 ] ; \
size_t size ; \
2008-10-29 19:41:03 +01:00
unsigned int index = intf - > offset_ # # __name ; \
2007-09-25 17:57:13 -07:00
__type value ; \
\
if ( * offset ) \
return 0 ; \
\
2008-10-29 19:41:03 +01:00
if ( index > = debug - > __name . word_count ) \
2007-09-25 17:57:13 -07:00
return - EINVAL ; \
\
if ( copy_from_user ( line , buf , length ) ) \
return - EFAULT ; \
\
size = strlen ( line ) ; \
value = simple_strtoul ( line , NULL , 0 ) ; \
\
2009-02-17 14:04:29 +01:00
index + = ( debug - > __name . word_base / \
debug - > __name . word_size ) ; \
\
2008-10-29 19:41:03 +01:00
if ( debug - > __name . flags & RT2X00DEBUGFS_OFFSET ) \
index * = debug - > __name . word_size ; \
\
debug - > __name . write ( intf - > rt2x00dev , index , value ) ; \
2007-09-25 17:57:13 -07:00
\
* offset + = size ; \
return size ; \
}
# define RT2X00DEBUGFS_OPS(__name, __format, __type) \
RT2X00DEBUGFS_OPS_READ ( __name , __format , __type ) ; \
RT2X00DEBUGFS_OPS_WRITE ( __name , __type ) ; \
\
static const struct file_operations rt2x00debug_fop_ # # __name = { \
. owner = THIS_MODULE , \
. read = rt2x00debug_read_ # # __name , \
. write = rt2x00debug_write_ # # __name , \
. open = rt2x00debug_file_open , \
. release = rt2x00debug_file_release , \
} ;
RT2X00DEBUGFS_OPS ( csr , " 0x%.8x \n " , u32 ) ;
RT2X00DEBUGFS_OPS ( eeprom , " 0x%.4x \n " , u16 ) ;
RT2X00DEBUGFS_OPS ( bbp , " 0x%.2x \n " , u8 ) ;
RT2X00DEBUGFS_OPS ( rf , " 0x%.8x \n " , u32 ) ;
2007-09-25 20:13:51 +02:00
static ssize_t rt2x00debug_read_dev_flags ( struct file * file ,
char __user * buf ,
size_t length ,
loff_t * offset )
{
struct rt2x00debug_intf * intf = file - > private_data ;
char line [ 16 ] ;
size_t size ;
if ( * offset )
return 0 ;
size = sprintf ( line , " 0x%.8x \n " , ( unsigned int ) intf - > rt2x00dev - > flags ) ;
if ( copy_to_user ( buf , line , size ) )
return - EFAULT ;
* offset + = size ;
return size ;
}
static const struct file_operations rt2x00debug_fop_dev_flags = {
. owner = THIS_MODULE ,
. read = rt2x00debug_read_dev_flags ,
. open = rt2x00debug_file_open ,
. release = rt2x00debug_file_release ,
} ;
2007-09-25 17:57:13 -07:00
static struct dentry * rt2x00debug_create_file_driver ( const char * name ,
struct rt2x00debug_intf
* intf ,
struct debugfs_blob_wrapper
* blob )
{
char * data ;
2008-02-10 22:50:28 +01:00
data = kzalloc ( 3 * MAX_LINE_LENGTH , GFP_KERNEL ) ;
2007-09-25 17:57:13 -07:00
if ( ! data )
return NULL ;
blob - > data = data ;
2009-03-03 18:14:18 +01:00
data + = sprintf ( data , " driver: \t %s \n " , intf - > rt2x00dev - > ops - > name ) ;
data + = sprintf ( data , " version: \t %s \n " , DRV_VERSION ) ;
data + = sprintf ( data , " compiled: \t %s %s \n " , __DATE__ , __TIME__ ) ;
2007-09-25 17:57:13 -07:00
blob - > size = strlen ( blob - > data ) ;
2008-07-27 15:06:05 +02:00
return debugfs_create_blob ( name , S_IRUSR , intf - > driver_folder , blob ) ;
2007-09-25 17:57:13 -07:00
}
static struct dentry * rt2x00debug_create_file_chipset ( const char * name ,
struct rt2x00debug_intf
* intf ,
struct
debugfs_blob_wrapper
* blob )
{
const struct rt2x00debug * debug = intf - > debug ;
char * data ;
2008-02-10 22:50:28 +01:00
data = kzalloc ( 8 * MAX_LINE_LENGTH , GFP_KERNEL ) ;
2007-09-25 17:57:13 -07:00
if ( ! data )
return NULL ;
2008-01-06 23:38:10 +01:00
blob - > data = data ;
2009-03-03 18:14:18 +01:00
data + = sprintf ( data , " rt chip: \t %04x \n " , intf - > rt2x00dev - > chip . rt ) ;
data + = sprintf ( data , " rf chip: \t %04x \n " , intf - > rt2x00dev - > chip . rf ) ;
data + = sprintf ( data , " revision: \t %08x \n " , intf - > rt2x00dev - > chip . rev ) ;
2007-11-27 21:48:37 +01:00
data + = sprintf ( data , " \n " ) ;
2009-03-03 18:14:18 +01:00
data + = sprintf ( data , " register \t base \t words \t wordsize \n " ) ;
data + = sprintf ( data , " csr \t %d \t %d \t %d \n " ,
debug - > csr . word_base ,
debug - > csr . word_count ,
debug - > csr . word_size ) ;
data + = sprintf ( data , " eeprom \t %d \t %d \t %d \n " ,
debug - > eeprom . word_base ,
debug - > eeprom . word_count ,
debug - > eeprom . word_size ) ;
data + = sprintf ( data , " bbp \t %d \t %d \t %d \n " ,
debug - > bbp . word_base ,
debug - > bbp . word_count ,
debug - > bbp . word_size ) ;
data + = sprintf ( data , " rf \t %d \t %d \t %d \n " ,
debug - > rf . word_base ,
debug - > rf . word_count ,
debug - > rf . word_size ) ;
2008-01-06 23:38:10 +01:00
blob - > size = strlen ( blob - > data ) ;
2007-09-25 17:57:13 -07:00
2008-07-27 15:06:05 +02:00
return debugfs_create_blob ( name , S_IRUSR , intf - > driver_folder , blob ) ;
2007-09-25 17:57:13 -07:00
}
void rt2x00debug_register ( struct rt2x00_dev * rt2x00dev )
{
const struct rt2x00debug * debug = rt2x00dev - > ops - > debugfs ;
struct rt2x00debug_intf * intf ;
intf = kzalloc ( sizeof ( struct rt2x00debug_intf ) , GFP_KERNEL ) ;
if ( ! intf ) {
ERROR ( rt2x00dev , " Failed to allocate debug handler. \n " ) ;
return ;
}
intf - > debug = debug ;
intf - > rt2x00dev = rt2x00dev ;
rt2x00dev - > debugfs_intf = intf ;
intf - > driver_folder =
debugfs_create_dir ( intf - > rt2x00dev - > ops - > name ,
rt2x00dev - > hw - > wiphy - > debugfsdir ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > driver_folder ) | | ! intf - > driver_folder )
2007-09-25 17:57:13 -07:00
goto exit ;
intf - > driver_entry =
rt2x00debug_create_file_driver ( " driver " , intf , & intf - > driver_blob ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > driver_entry ) | | ! intf - > driver_entry )
2007-09-25 17:57:13 -07:00
goto exit ;
intf - > chipset_entry =
rt2x00debug_create_file_chipset ( " chipset " ,
intf , & intf - > chipset_blob ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > chipset_entry ) | | ! intf - > chipset_entry )
2007-09-25 17:57:13 -07:00
goto exit ;
2008-07-27 15:06:05 +02:00
intf - > dev_flags = debugfs_create_file ( " dev_flags " , S_IRUSR ,
2007-09-25 20:13:51 +02:00
intf - > driver_folder , intf ,
& rt2x00debug_fop_dev_flags ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > dev_flags ) | | ! intf - > dev_flags )
2007-09-25 20:13:51 +02:00
goto exit ;
2007-11-27 21:48:16 +01:00
intf - > register_folder =
debugfs_create_dir ( " register " , intf - > driver_folder ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > register_folder ) | | ! intf - > register_folder )
2007-11-27 21:48:16 +01:00
goto exit ;
# define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \
2007-09-25 17:57:13 -07:00
( { \
( __intf ) - > __name # # _off_entry = \
debugfs_create_u32 ( __stringify ( __name ) " _offset " , \
2008-07-27 15:06:05 +02:00
S_IRUSR | S_IWUSR , \
2007-11-27 21:48:16 +01:00
( __intf ) - > register_folder , \
2007-09-25 17:57:13 -07:00
& ( __intf ) - > offset_ # # __name ) ; \
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( ( __intf ) - > __name # # _off_entry ) \
| | ! ( __intf ) - > __name # # _off_entry ) \
2007-09-25 17:57:13 -07:00
goto exit ; \
\
( __intf ) - > __name # # _val_entry = \
debugfs_create_file ( __stringify ( __name ) " _value " , \
2008-07-27 15:06:05 +02:00
S_IRUSR | S_IWUSR , \
2007-11-27 21:48:16 +01:00
( __intf ) - > register_folder , \
2007-09-25 17:57:13 -07:00
( __intf ) , & rt2x00debug_fop_ # # __name ) ; \
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( ( __intf ) - > __name # # _val_entry ) \
| | ! ( __intf ) - > __name # # _val_entry ) \
2007-09-25 17:57:13 -07:00
goto exit ; \
} )
2007-11-27 21:48:16 +01:00
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY ( intf , csr ) ;
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY ( intf , eeprom ) ;
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY ( intf , bbp ) ;
RT2X00DEBUGFS_CREATE_REGISTER_ENTRY ( intf , rf ) ;
2007-09-25 17:57:13 -07:00
2007-11-27 21:48:16 +01:00
# undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
2007-09-25 17:57:13 -07:00
2008-02-10 22:50:28 +01:00
intf - > queue_folder =
debugfs_create_dir ( " queue " , intf - > driver_folder ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > queue_folder ) | | ! intf - > queue_folder )
2007-11-27 21:49:29 +01:00
goto exit ;
2008-02-10 22:50:28 +01:00
intf - > queue_frame_dump_entry =
2008-07-27 15:06:05 +02:00
debugfs_create_file ( " dump " , S_IRUSR , intf - > queue_folder ,
2008-02-05 16:42:23 -05:00
intf , & rt2x00debug_fop_queue_dump ) ;
2008-10-22 17:07:25 +08:00
if ( IS_ERR ( intf - > queue_frame_dump_entry )
| | ! intf - > queue_frame_dump_entry )
2007-11-27 21:49:29 +01:00
goto exit ;
skb_queue_head_init ( & intf - > frame_dump_skbqueue ) ;
init_waitqueue_head ( & intf - > frame_dump_waitqueue ) ;
2008-02-10 22:50:28 +01:00
intf - > queue_stats_entry =
2008-07-27 15:06:05 +02:00
debugfs_create_file ( " queue " , S_IRUSR , intf - > queue_folder ,
2008-02-10 22:50:28 +01:00
intf , & rt2x00debug_fop_queue_stats ) ;
2008-08-04 16:37:44 +02:00
# ifdef CONFIG_RT2X00_LIB_CRYPTO
if ( test_bit ( CONFIG_SUPPORT_HW_CRYPTO , & rt2x00dev - > flags ) )
intf - > crypto_stats_entry =
debugfs_create_file ( " crypto " , S_IRUGO , intf - > queue_folder ,
intf , & rt2x00debug_fop_crypto_stats ) ;
# endif
2007-09-25 17:57:13 -07:00
return ;
exit :
rt2x00debug_deregister ( rt2x00dev ) ;
ERROR ( rt2x00dev , " Failed to register debug handler. \n " ) ;
return ;
}
void rt2x00debug_deregister ( struct rt2x00_dev * rt2x00dev )
{
2007-11-27 21:49:29 +01:00
struct rt2x00debug_intf * intf = rt2x00dev - > debugfs_intf ;
2007-09-25 17:57:13 -07:00
if ( unlikely ( ! intf ) )
return ;
2007-11-27 21:49:29 +01:00
skb_queue_purge ( & intf - > frame_dump_skbqueue ) ;
2008-08-04 16:37:44 +02:00
# ifdef CONFIG_RT2X00_LIB_CRYPTO
debugfs_remove ( intf - > crypto_stats_entry ) ;
# endif
2008-02-10 22:50:28 +01:00
debugfs_remove ( intf - > queue_stats_entry ) ;
debugfs_remove ( intf - > queue_frame_dump_entry ) ;
debugfs_remove ( intf - > queue_folder ) ;
2007-09-25 17:57:13 -07:00
debugfs_remove ( intf - > rf_val_entry ) ;
debugfs_remove ( intf - > rf_off_entry ) ;
debugfs_remove ( intf - > bbp_val_entry ) ;
debugfs_remove ( intf - > bbp_off_entry ) ;
debugfs_remove ( intf - > eeprom_val_entry ) ;
debugfs_remove ( intf - > eeprom_off_entry ) ;
debugfs_remove ( intf - > csr_val_entry ) ;
debugfs_remove ( intf - > csr_off_entry ) ;
2007-11-27 21:48:16 +01:00
debugfs_remove ( intf - > register_folder ) ;
2007-09-25 20:13:51 +02:00
debugfs_remove ( intf - > dev_flags ) ;
2007-09-25 17:57:13 -07:00
debugfs_remove ( intf - > chipset_entry ) ;
debugfs_remove ( intf - > driver_entry ) ;
debugfs_remove ( intf - > driver_folder ) ;
kfree ( intf - > chipset_blob . data ) ;
kfree ( intf - > driver_blob . data ) ;
kfree ( intf ) ;
rt2x00dev - > debugfs_intf = NULL ;
}