2009-05-21 21:20:45 +08:00
/*
* Intel Wireless Multicomm 3200 WiFi driver
*
* Copyright ( C ) 2009 Intel Corporation < ilw @ linux . intel . com >
* Samuel Ortiz < samuel . ortiz @ intel . com >
* Zhu Yi < yi . zhu @ 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 .
*
*/
/*
* This is the netdev related hooks for iwm .
*
* Some interesting code paths :
*
* iwm_open ( ) ( Called at netdev interface bringup time )
* - > iwm_up ( ) ( main . c )
* - > iwm_bus_enable ( )
* - > if_sdio_enable ( ) ( In case of an SDIO bus )
* - > sdio_enable_func ( )
* - > iwm_notif_wait ( BARKER_REBOOT ) ( wait for reboot barker )
* - > iwm_notif_wait ( ACK_BARKER ) ( wait for ACK barker )
* - > iwm_load_fw ( ) ( fw . c )
* - > iwm_load_umac ( )
* - > iwm_load_lmac ( ) ( Calibration LMAC )
* - > iwm_load_lmac ( ) ( Operational LMAC )
* - > iwm_send_umac_config ( )
*
* iwm_stop ( ) ( Called at netdev interface bringdown time )
* - > iwm_down ( )
* - > iwm_bus_disable ( )
* - > if_sdio_disable ( ) ( In case of an SDIO bus )
* - > sdio_disable_func ( )
*/
# include <linux/netdevice.h>
# include "iwm.h"
2009-06-15 21:59:54 +02:00
# include "commands.h"
2009-05-21 21:20:45 +08:00
# include "cfg80211.h"
# include "debug.h"
static int iwm_open ( struct net_device * ndev )
{
struct iwm_priv * iwm = ndev_to_iwm ( ndev ) ;
2009-06-15 21:59:56 +02:00
return iwm_up ( iwm ) ;
2009-05-21 21:20:45 +08:00
}
static int iwm_stop ( struct net_device * ndev )
{
struct iwm_priv * iwm = ndev_to_iwm ( ndev ) ;
2009-06-15 21:59:56 +02:00
return iwm_down ( iwm ) ;
2009-05-21 21:20:45 +08:00
}
/*
* iwm AC to queue mapping
*
* AC_VO - > queue 3
* AC_VI - > queue 2
* AC_BE - > queue 1
* AC_BK - > queue 0
*/
static const u16 iwm_1d_to_queue [ 8 ] = { 1 , 0 , 0 , 1 , 2 , 2 , 3 , 3 } ;
2009-12-16 17:01:38 +01:00
int iwm_tid_to_queue ( u16 tid )
2009-11-24 11:33:31 +08:00
{
if ( tid > IWM_UMAC_TID_NR - 2 )
return - EINVAL ;
return iwm_1d_to_queue [ tid ] ;
}
2009-05-21 21:20:45 +08:00
static u16 iwm_select_queue ( struct net_device * dev , struct sk_buff * skb )
{
skb - > priority = cfg80211_classify8021d ( skb ) ;
return iwm_1d_to_queue [ skb - > priority ] ;
}
static const struct net_device_ops iwm_netdev_ops = {
. ndo_open = iwm_open ,
. ndo_stop = iwm_stop ,
. ndo_start_xmit = iwm_xmit_frame ,
. ndo_select_queue = iwm_select_queue ,
} ;
void * iwm_if_alloc ( int sizeof_bus , struct device * dev ,
struct iwm_if_ops * if_ops )
{
struct net_device * ndev ;
struct wireless_dev * wdev ;
struct iwm_priv * iwm ;
int ret = 0 ;
wdev = iwm_wdev_alloc ( sizeof_bus , dev ) ;
2009-07-25 15:22:59 +03:00
if ( IS_ERR ( wdev ) )
return wdev ;
2009-05-21 21:20:45 +08:00
iwm = wdev_to_iwm ( wdev ) ;
iwm - > bus_ops = if_ops ;
iwm - > wdev = wdev ;
2009-06-15 21:36:13 +02:00
ret = iwm_priv_init ( iwm ) ;
if ( ret ) {
dev_err ( dev , " failed to init iwm_priv \n " ) ;
goto out_wdev ;
}
2009-05-21 21:20:45 +08:00
wdev - > iftype = iwm_mode_to_nl80211_iftype ( iwm - > conf . mode ) ;
2009-06-15 21:36:14 +02:00
ndev = alloc_netdev_mq ( 0 , " wlan%d " , ether_setup , IWM_TX_QUEUES ) ;
2009-05-21 21:20:45 +08:00
if ( ! ndev ) {
dev_err ( dev , " no memory for network device instance \n " ) ;
2009-06-15 21:36:13 +02:00
goto out_priv ;
2009-05-21 21:20:45 +08:00
}
ndev - > netdev_ops = & iwm_netdev_ops ;
ndev - > ieee80211_ptr = wdev ;
SET_NETDEV_DEV ( ndev , wiphy_dev ( wdev - > wiphy ) ) ;
wdev - > netdev = ndev ;
2009-06-15 21:59:54 +02:00
iwm - > umac_profile = kmalloc ( sizeof ( struct iwm_umac_profile ) ,
GFP_KERNEL ) ;
if ( ! iwm - > umac_profile ) {
dev_err ( dev , " Couldn't alloc memory for profile \n " ) ;
goto out_profile ;
}
iwm_init_default_profile ( iwm , iwm - > umac_profile ) ;
2009-05-21 21:20:45 +08:00
return iwm ;
2009-06-15 21:59:54 +02:00
out_profile :
free_netdev ( ndev ) ;
2009-06-15 21:36:13 +02:00
out_priv :
iwm_priv_deinit ( iwm ) ;
2009-05-21 21:20:45 +08:00
out_wdev :
iwm_wdev_free ( iwm ) ;
return ERR_PTR ( ret ) ;
}
void iwm_if_free ( struct iwm_priv * iwm )
{
if ( ! iwm_to_ndev ( iwm ) )
return ;
2009-10-16 13:18:48 +08:00
cancel_delayed_work_sync ( & iwm - > ct_kill_delay ) ;
2009-05-21 21:20:45 +08:00
free_netdev ( iwm_to_ndev ( iwm ) ) ;
2009-06-15 21:36:13 +02:00
iwm_priv_deinit ( iwm ) ;
2009-06-15 21:59:54 +02:00
kfree ( iwm - > umac_profile ) ;
iwm - > umac_profile = NULL ;
2009-07-09 17:24:15 +08:00
iwm_wdev_free ( iwm ) ;
2009-05-21 21:20:45 +08:00
}
2009-06-15 21:36:14 +02:00
int iwm_if_add ( struct iwm_priv * iwm )
{
struct net_device * ndev = iwm_to_ndev ( iwm ) ;
int ret ;
ret = register_netdev ( ndev ) ;
if ( ret < 0 ) {
dev_err ( & ndev - > dev , " Failed to register netdev: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
void iwm_if_remove ( struct iwm_priv * iwm )
{
unregister_netdev ( iwm_to_ndev ( iwm ) ) ;
}