Commit b6727b12 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6:
  Staging: fix wireless drivers depends
  Staging: wireless drivers Kconfig change
  Staging: android: mark subsystem as broken
  Staging: remove stlc45xx driver
  Staging: rtl8187se/rtl8192e/rtl8192su: allow module unload
  Staging: vt6656: fix the memory free bug in vntwusb_disconnect()
  Staging: Panel: prevent driver from calling misc_deregister twice on same ressource
  Staging: hv: fix oops in vmbus - missing #include
  Staging: hv: fix oops in vmbus - netvsc list_head
  Staging: hv: fix oops in vmbus - udev events
  Staging: hv: Fix vmbus load hang caused by faulty data packing
  Staging: hv: Fix null pointer error after vmbus loading
  Staging: hv TODO patches
parents eb2890c9 b881c6cb
...@@ -93,8 +93,6 @@ source "drivers/staging/dst/Kconfig" ...@@ -93,8 +93,6 @@ source "drivers/staging/dst/Kconfig"
source "drivers/staging/pohmelfs/Kconfig" source "drivers/staging/pohmelfs/Kconfig"
source "drivers/staging/stlc45xx/Kconfig"
source "drivers/staging/b3dfg/Kconfig" source "drivers/staging/b3dfg/Kconfig"
source "drivers/staging/phison/Kconfig" source "drivers/staging/phison/Kconfig"
......
...@@ -29,7 +29,6 @@ obj-$(CONFIG_ANDROID) += android/ ...@@ -29,7 +29,6 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_ANDROID) += dream/ obj-$(CONFIG_ANDROID) += dream/
obj-$(CONFIG_DST) += dst/ obj-$(CONFIG_DST) += dst/
obj-$(CONFIG_POHMELFS) += pohmelfs/ obj-$(CONFIG_POHMELFS) += pohmelfs/
obj-$(CONFIG_STLC45XX) += stlc45xx/
obj-$(CONFIG_B3DFG) += b3dfg/ obj-$(CONFIG_B3DFG) += b3dfg/
obj-$(CONFIG_IDE_PHISON) += phison/ obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_PLAN9AUTH) += p9auth/ obj-$(CONFIG_PLAN9AUTH) += p9auth/
......
...@@ -2,6 +2,7 @@ menu "Android" ...@@ -2,6 +2,7 @@ menu "Android"
config ANDROID config ANDROID
bool "Android Drivers" bool "Android Drivers"
depends on BROKEN
default N default N
---help--- ---help---
Enable support for various drivers needed on the Android platform Enable support for various drivers needed on the Android platform
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define _CHANNEL_MGMT_H_ #define _CHANNEL_MGMT_H_
#include <linux/list.h> #include <linux/list.h>
#include <linux/timer.h>
#include "RingBuffer.h" #include "RingBuffer.h"
#include "VmbusChannelInterface.h" #include "VmbusChannelInterface.h"
#include "VmbusPacketFormat.h" #include "VmbusPacketFormat.h"
...@@ -54,7 +55,7 @@ enum vmbus_channel_message_type { ...@@ -54,7 +55,7 @@ enum vmbus_channel_message_type {
ChannelMessageViewRangeRemove = 18, ChannelMessageViewRangeRemove = 18,
#endif #endif
ChannelMessageCount ChannelMessageCount
} __attribute__((packed)); };
struct vmbus_channel_message_header { struct vmbus_channel_message_header {
enum vmbus_channel_message_type MessageType; enum vmbus_channel_message_type MessageType;
......
...@@ -1052,7 +1052,7 @@ static void NetVscOnReceive(struct hv_device *Device, ...@@ -1052,7 +1052,7 @@ static void NetVscOnReceive(struct hv_device *Device,
*/ */
spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags); spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
while (!list_empty(&netDevice->ReceivePacketList)) { while (!list_empty(&netDevice->ReceivePacketList)) {
list_move_tail(&netDevice->ReceivePacketList, &listHead); list_move_tail(netDevice->ReceivePacketList.next, &listHead);
if (++count == vmxferpagePacket->RangeCount + 1) if (++count == vmxferpagePacket->RangeCount + 1)
break; break;
} }
...@@ -1071,7 +1071,7 @@ static void NetVscOnReceive(struct hv_device *Device, ...@@ -1071,7 +1071,7 @@ static void NetVscOnReceive(struct hv_device *Device,
/* Return it to the freelist */ /* Return it to the freelist */
spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags); spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
for (i = count; i != 0; i--) { for (i = count; i != 0; i--) {
list_move_tail(&listHead, list_move_tail(listHead.next,
&netDevice->ReceivePacketList); &netDevice->ReceivePacketList);
} }
spin_unlock_irqrestore(&netDevice->receive_packet_list_lock, spin_unlock_irqrestore(&netDevice->receive_packet_list_lock,
...@@ -1085,8 +1085,7 @@ static void NetVscOnReceive(struct hv_device *Device, ...@@ -1085,8 +1085,7 @@ static void NetVscOnReceive(struct hv_device *Device,
} }
/* Remove the 1st packet to represent the xfer page packet itself */ /* Remove the 1st packet to represent the xfer page packet itself */
xferpagePacket = list_entry(&listHead, struct xferpage_packet, xferpagePacket = (struct xferpage_packet*)listHead.next;
ListEntry);
list_del(&xferpagePacket->ListEntry); list_del(&xferpagePacket->ListEntry);
/* This is how much we can satisfy */ /* This is how much we can satisfy */
...@@ -1102,8 +1101,7 @@ static void NetVscOnReceive(struct hv_device *Device, ...@@ -1102,8 +1101,7 @@ static void NetVscOnReceive(struct hv_device *Device,
/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
for (i = 0; i < (count - 1); i++) { for (i = 0; i < (count - 1); i++) {
netvscPacket = list_entry(&listHead, struct hv_netvsc_packet, netvscPacket = (struct hv_netvsc_packet*)listHead.next;
ListEntry);
list_del(&netvscPacket->ListEntry); list_del(&netvscPacket->ListEntry);
/* Initialize the netvsc packet */ /* Initialize the netvsc packet */
......
TODO: TODO:
- fix remaining checkpatch warnings and errors - fix remaining checkpatch warnings and errors
- use of /** when it is not a kerneldoc header
- remove RingBuffer.c to us in-kernel ringbuffer functions instead. - remove RingBuffer.c to us in-kernel ringbuffer functions instead.
- audit the vmbus to verify it is working properly with the - audit the vmbus to verify it is working properly with the
driver model driver model
- convert vmbus driver interface function pointer tables
to constant, a.k.a vmbus_ops
- see if the vmbus can be merged with the other virtual busses - see if the vmbus can be merged with the other virtual busses
in the kernel in the kernel
- audit the network driver - audit the network driver
- use existing net_device_stats struct in network device
- checking for carrier inside open is wrong, network device API
confusion??
- audit the block driver - audit the block driver
- audit the scsi driver - audit the scsi driver
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#ifndef _OSD_H_ #ifndef _OSD_H_
#define _OSD_H_ #define _OSD_H_
#include <linux/workqueue.h>
/* Defines */ /* Defines */
#define ALIGN_UP(value, align) (((value) & (align-1)) ? \ #define ALIGN_UP(value, align) (((value) & (align-1)) ? \
......
...@@ -507,12 +507,12 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type, ...@@ -507,12 +507,12 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
child_device_obj = &child_device_ctx->device_obj; child_device_obj = &child_device_ctx->device_obj;
child_device_obj->context = context; child_device_obj->context = context;
memcpy(&child_device_obj->deviceType, &type, sizeof(struct hv_guid)); memcpy(&child_device_obj->deviceType, type, sizeof(struct hv_guid));
memcpy(&child_device_obj->deviceInstance, &instance, memcpy(&child_device_obj->deviceInstance, instance,
sizeof(struct hv_guid)); sizeof(struct hv_guid));
memcpy(&child_device_ctx->class_id, &type, sizeof(struct hv_guid)); memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid));
memcpy(&child_device_ctx->device_id, &instance, sizeof(struct hv_guid)); memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid));
DPRINT_EXIT(VMBUS_DRV); DPRINT_EXIT(VMBUS_DRV);
...@@ -537,18 +537,7 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj, ...@@ -537,18 +537,7 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
child_device_ctx); child_device_ctx);
/* Make sure we are not registered already */ /* Set the device name. Otherwise, device_register() will fail. */
if (strlen(dev_name(&child_device_ctx->device)) != 0) {
DPRINT_ERR(VMBUS_DRV,
"child device (%p) already registered - busid %s",
child_device_ctx,
dev_name(&child_device_ctx->device));
ret = -1;
goto Cleanup;
}
/* Set the device bus id. Otherwise, device_register()will fail. */
dev_set_name(&child_device_ctx->device, "vmbus_0_%d", dev_set_name(&child_device_ctx->device, "vmbus_0_%d",
atomic_inc_return(&device_num)); atomic_inc_return(&device_num));
...@@ -573,7 +562,6 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj, ...@@ -573,7 +562,6 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
&child_device_ctx->device); &child_device_ctx->device);
Cleanup:
DPRINT_EXIT(VMBUS_DRV); DPRINT_EXIT(VMBUS_DRV);
return ret; return ret;
...@@ -623,8 +611,6 @@ static void vmbus_child_device_destroy(struct hv_device *device_obj) ...@@ -623,8 +611,6 @@ static void vmbus_child_device_destroy(struct hv_device *device_obj)
static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
{ {
struct device_context *device_ctx = device_to_device_context(device); struct device_context *device_ctx = device_to_device_context(device);
int i = 0;
int len = 0;
int ret; int ret;
DPRINT_ENTER(VMBUS_DRV); DPRINT_ENTER(VMBUS_DRV);
...@@ -644,8 +630,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) ...@@ -644,8 +630,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
device_ctx->class_id.data[14], device_ctx->class_id.data[14],
device_ctx->class_id.data[15]); device_ctx->class_id.data[15]);
env->envp_idx = i;
env->buflen = len;
ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={" ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
"%02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}", "%02x%02x%02x%02x%02x%02x%02x%02x}",
...@@ -691,8 +675,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) ...@@ -691,8 +675,6 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
if (ret) if (ret)
return ret; return ret;
env->envp[env->envp_idx] = NULL;
DPRINT_EXIT(VMBUS_DRV); DPRINT_EXIT(VMBUS_DRV);
return 0; return 0;
......
config OTUS config OTUS
tristate "Atheros OTUS 802.11n USB wireless support" tristate "Atheros OTUS 802.11n USB wireless support"
depends on USB && WLAN_80211 && MAC80211 depends on USB && WLAN && MAC80211
default N default N
---help--- ---help---
Enable support for Atheros 802.11n USB hardware: Enable support for Atheros 802.11n USB hardware:
......
...@@ -2071,11 +2071,15 @@ static void panel_detach(struct parport *port) ...@@ -2071,11 +2071,15 @@ static void panel_detach(struct parport *port)
return; return;
} }
if (keypad_enabled && keypad_initialized) if (keypad_enabled && keypad_initialized) {
misc_deregister(&keypad_dev); misc_deregister(&keypad_dev);
keypad_initialized = 0;
}
if (lcd_enabled && lcd_initialized) if (lcd_enabled && lcd_initialized) {
misc_deregister(&lcd_dev); misc_deregister(&lcd_dev);
lcd_initialized = 0;
}
parport_release(pprt); parport_release(pprt);
parport_unregister_device(pprt); parport_unregister_device(pprt);
...@@ -2211,13 +2215,16 @@ static void __exit panel_cleanup_module(void) ...@@ -2211,13 +2215,16 @@ static void __exit panel_cleanup_module(void)
del_timer(&scan_timer); del_timer(&scan_timer);
if (pprt != NULL) { if (pprt != NULL) {
if (keypad_enabled) if (keypad_enabled) {
misc_deregister(&keypad_dev); misc_deregister(&keypad_dev);
keypad_initialized = 0;
}
if (lcd_enabled) { if (lcd_enabled) {
panel_lcd_print("\x0cLCD driver " PANEL_VERSION panel_lcd_print("\x0cLCD driver " PANEL_VERSION
"\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
misc_deregister(&lcd_dev); misc_deregister(&lcd_dev);
lcd_initialized = 0;
} }
/* TODO: free all input signals */ /* TODO: free all input signals */
......
config RT2860 config RT2860
tristate "Ralink 2860 wireless support" tristate "Ralink 2860 wireless support"
depends on PCI && X86 && WLAN_80211 depends on PCI && X86 && WLAN
---help--- ---help---
This is an experimental driver for the Ralink 2860 wireless chip. This is an experimental driver for the Ralink 2860 wireless chip.
config RT2870 config RT2870
tristate "Ralink 2870/3070 wireless support" tristate "Ralink 2870/3070 wireless support"
depends on USB && X86 && WLAN_80211 depends on USB && X86 && WLAN
---help--- ---help---
This is an experimental driver for the Ralink xx70 wireless chips. This is an experimental driver for the Ralink xx70 wireless chips.
config RT3090 config RT3090
tristate "Ralink 3090 wireless support" tristate "Ralink 3090 wireless support"
depends on PCI && X86 && WLAN_80211 depends on PCI && X86 && WLAN
---help--- ---help---
This is an experimental driver for the Ralink 3090 wireless chip. This is an experimental driver for the Ralink 3090 wireless chip.
config RTL8187SE config RTL8187SE
tristate "RealTek RTL8187SE Wireless LAN NIC driver" tristate "RealTek RTL8187SE Wireless LAN NIC driver"
depends on PCI depends on PCI && WLAN
depends on WIRELESS_EXT depends on WIRELESS_EXT
default N default N
---help--- ---help---
...@@ -53,10 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ...@@ -53,10 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee,
list_del(ptr); list_del(ptr);
if (entry->ops) { if (entry->ops)
entry->ops->deinit(entry->priv); entry->ops->deinit(entry->priv);
module_put(entry->ops->owner);
}
kfree(entry); kfree(entry);
} }
} }
......
...@@ -189,10 +189,8 @@ void free_ieee80211(struct net_device *dev) ...@@ -189,10 +189,8 @@ void free_ieee80211(struct net_device *dev)
for (i = 0; i < WEP_KEYS; i++) { for (i = 0; i < WEP_KEYS; i++) {
struct ieee80211_crypt_data *crypt = ieee->crypt[i]; struct ieee80211_crypt_data *crypt = ieee->crypt[i];
if (crypt) { if (crypt) {
if (crypt->ops) { if (crypt->ops)
crypt->ops->deinit(crypt->priv); crypt->ops->deinit(crypt->priv);
module_put(crypt->ops->owner);
}
kfree(crypt); kfree(crypt);
ieee->crypt[i] = NULL; ieee->crypt[i] = NULL;
} }
......
...@@ -2839,16 +2839,12 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -2839,16 +2839,12 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
goto skip_host_crypt; goto skip_host_crypt;
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0)
request_module("ieee80211_crypt_wep");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0)
request_module("ieee80211_crypt_tkip");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0)
request_module("ieee80211_crypt_ccmp");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
}
if (ops == NULL) { if (ops == NULL) {
printk("unknown crypto alg '%s'\n", param->u.crypt.alg); printk("unknown crypto alg '%s'\n", param->u.crypt.alg);
param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG;
...@@ -2869,7 +2865,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -2869,7 +2865,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
} }
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops; new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->priv =
new_crypt->ops->init(param->u.crypt.idx); new_crypt->ops->init(param->u.crypt.idx);
......
...@@ -331,12 +331,10 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -331,12 +331,10 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
return -ENOMEM; return -ENOMEM;
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
if (!new_crypt->ops) { if (!new_crypt->ops)
request_module("ieee80211_crypt_wep");
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
}
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->ops->init(key); new_crypt->priv = new_crypt->ops->init(key);
if (!new_crypt->ops || !new_crypt->priv) { if (!new_crypt->ops || !new_crypt->priv) {
...@@ -483,7 +481,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -483,7 +481,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int i, idx, ret = 0; int i, idx, ret = 0;
int group_key = 0; int group_key = 0;
const char *alg, *module; const char *alg;
struct ieee80211_crypto_ops *ops; struct ieee80211_crypto_ops *ops;
struct ieee80211_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
...@@ -539,15 +537,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -539,15 +537,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
switch (ext->alg) { switch (ext->alg) {
case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_WEP:
alg = "WEP"; alg = "WEP";
module = "ieee80211_crypt_wep";
break; break;
case IW_ENCODE_ALG_TKIP: case IW_ENCODE_ALG_TKIP:
alg = "TKIP"; alg = "TKIP";
module = "ieee80211_crypt_tkip";
break; break;
case IW_ENCODE_ALG_CCMP: case IW_ENCODE_ALG_CCMP:
alg = "CCMP"; alg = "CCMP";
module = "ieee80211_crypt_ccmp";
break; break;
default: default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
...@@ -558,10 +553,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -558,10 +553,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
// printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg); // printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) { if (ops == NULL)
request_module(module);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
}
if (ops == NULL) { if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg); dev->name, ext->alg);
...@@ -581,7 +574,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -581,7 +574,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
goto done; goto done;
} }
new_crypt->ops = ops; new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->ops->init(idx); new_crypt->priv = new_crypt->ops->init(idx);
if (new_crypt->priv == NULL) { if (new_crypt->priv == NULL) {
kfree(new_crypt); kfree(new_crypt);
......
config RTL8192E config RTL8192E
tristate "RealTek RTL8192E Wireless LAN NIC driver" tristate "RealTek RTL8192E Wireless LAN NIC driver"
depends on PCI depends on PCI && WLAN
depends on WIRELESS_EXT depends on WIRELESS_EXT
default N default N
---help--- ---help---
...@@ -53,14 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ...@@ -53,14 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee,
list_del(ptr); list_del(ptr);
if (entry->ops) { if (entry->ops)
entry->ops->deinit(entry->priv); entry->ops->deinit(entry->priv);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
module_put(entry->ops->owner);
#else
__MOD_DEC_USE_COUNT(entry->ops->owner);
#endif
}
kfree(entry); kfree(entry);
} }
} }
......
...@@ -242,14 +242,8 @@ void free_ieee80211(struct net_device *dev) ...@@ -242,14 +242,8 @@ void free_ieee80211(struct net_device *dev)
for (i = 0; i < WEP_KEYS; i++) { for (i = 0; i < WEP_KEYS; i++) {
struct ieee80211_crypt_data *crypt = ieee->crypt[i]; struct ieee80211_crypt_data *crypt = ieee->crypt[i];
if (crypt) { if (crypt) {
if (crypt->ops) { if (crypt->ops)
crypt->ops->deinit(crypt->priv); crypt->ops->deinit(crypt->priv);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
module_put(crypt->ops->owner);
#else
__MOD_DEC_USE_COUNT(crypt->ops->owner);
#endif
}
kfree(crypt); kfree(crypt);
ieee->crypt[i] = NULL; ieee->crypt[i] = NULL;
} }
......
...@@ -3284,17 +3284,14 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -3284,17 +3284,14 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
goto skip_host_crypt; goto skip_host_crypt;
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0)
request_module("ieee80211_crypt_wep");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
//set WEP40 first, it will be modified according to WEP104 or WEP40 at other place /* set WEP40 first, it will be modified according to WEP104 or
} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { * WEP40 at other place */
request_module("ieee80211_crypt_tkip"); else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0)
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0)
request_module("ieee80211_crypt_ccmp");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
}
if (ops == NULL) { if (ops == NULL) {
printk("unknown crypto alg '%s'\n", param->u.crypt.alg); printk("unknown crypto alg '%s'\n", param->u.crypt.alg);
param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG;
...@@ -3315,11 +3312,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -3315,11 +3312,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
} }
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops; new_crypt->ops = ops;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (new_crypt->ops)
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
#else
if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner))
#endif
new_crypt->priv = new_crypt->priv =
new_crypt->ops->init(param->u.crypt.idx); new_crypt->ops->init(param->u.crypt.idx);
......
...@@ -482,15 +482,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -482,15 +482,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
return -ENOMEM; return -ENOMEM;
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
if (!new_crypt->ops) { if (!new_crypt->ops)
request_module("ieee80211_crypt_wep");
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
} if (new_crypt->ops)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
#else
if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner))
#endif
new_crypt->priv = new_crypt->ops->init(key); new_crypt->priv = new_crypt->ops->init(key);
if (!new_crypt->ops || !new_crypt->priv) { if (!new_crypt->ops || !new_crypt->priv) {
...@@ -644,7 +638,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -644,7 +638,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int i, idx; int i, idx;
int group_key = 0; int group_key = 0;
const char *alg, *module; const char *alg;
struct ieee80211_crypto_ops *ops; struct ieee80211_crypto_ops *ops;
struct ieee80211_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
...@@ -711,15 +705,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -711,15 +705,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
switch (ext->alg) { switch (ext->alg) {
case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_WEP:
alg = "WEP"; alg = "WEP";
module = "ieee80211_crypt_wep";
break; break;
case IW_ENCODE_ALG_TKIP: case IW_ENCODE_ALG_TKIP:
alg = "TKIP"; alg = "TKIP";
module = "ieee80211_crypt_tkip";
break; break;
case IW_ENCODE_ALG_CCMP: case IW_ENCODE_ALG_CCMP:
alg = "CCMP"; alg = "CCMP";
module = "ieee80211_crypt_ccmp";
break; break;
default: default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
...@@ -730,10 +721,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -730,10 +721,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
printk("alg name:%s\n",alg); printk("alg name:%s\n",alg);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) { if (ops == NULL)
request_module(module);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
}
if (ops == NULL) { if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg); dev->name, ext->alg);
...@@ -758,7 +747,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -758,7 +747,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
goto done; goto done;
} }
new_crypt->ops = ops; new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->ops->init(idx); new_crypt->priv = new_crypt->ops->init(idx);
if (new_crypt->priv == NULL) { if (new_crypt->priv == NULL) {
kfree(new_crypt); kfree(new_crypt);
......
config RTL8192SU config RTL8192SU
tristate "RealTek RTL8192SU Wireless LAN NIC driver" tristate "RealTek RTL8192SU Wireless LAN NIC driver"
depends on PCI depends on PCI && WLAN
depends on WIRELESS_EXT depends on WIRELESS_EXT
default N default N
---help--- ---help---
...@@ -53,10 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ...@@ -53,10 +53,8 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee,
list_del(ptr); list_del(ptr);
if (entry->ops) { if (entry->ops)
entry->ops->deinit(entry->priv); entry->ops->deinit(entry->priv);
module_put(entry->ops->owner);
}
kfree(entry); kfree(entry);
} }
} }
......
...@@ -216,10 +216,8 @@ void free_ieee80211(struct net_device *dev) ...@@ -216,10 +216,8 @@ void free_ieee80211(struct net_device *dev)
for (i = 0; i < WEP_KEYS; i++) { for (i = 0; i < WEP_KEYS; i++) {
struct ieee80211_crypt_data *crypt = ieee->crypt[i]; struct ieee80211_crypt_data *crypt = ieee->crypt[i];
if (crypt) { if (crypt) {
if (crypt->ops) { if (crypt->ops)
crypt->ops->deinit(crypt->priv); crypt->ops->deinit(crypt->priv);
module_put(crypt->ops->owner);
}
kfree(crypt); kfree(crypt);
ieee->crypt[i] = NULL; ieee->crypt[i] = NULL;
} }
......
...@@ -3026,17 +3026,14 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -3026,17 +3026,14 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
goto skip_host_crypt; goto skip_host_crypt;
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0)
request_module("ieee80211_crypt_wep");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
//set WEP40 first, it will be modified according to WEP104 or WEP40 at other place /* set WEP40 first, it will be modified according to WEP104 or
} else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { * WEP40 at other place */
request_module("ieee80211_crypt_tkip"); else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0)
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
} else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0)
request_module("ieee80211_crypt_ccmp");
ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
}
if (ops == NULL) { if (ops == NULL) {
printk("unknown crypto alg '%s'\n", param->u.crypt.alg); printk("unknown crypto alg '%s'\n", param->u.crypt.alg);
param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG;
...@@ -3058,7 +3055,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ...@@ -3058,7 +3055,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops; new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->priv =
new_crypt->ops->init(param->u.crypt.idx); new_crypt->ops->init(param->u.crypt.idx);
......
...@@ -358,11 +358,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ...@@ -358,11 +358,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
return -ENOMEM; return -ENOMEM;
memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
if (!new_crypt->ops) { if (!new_crypt->ops)
request_module("ieee80211_crypt_wep");
new_crypt->ops = ieee80211_get_crypto_ops("WEP"); new_crypt->ops = ieee80211_get_crypto_ops("WEP");
} if (new_crypt->ops)
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
new_crypt->priv = new_crypt->ops->init(key); new_crypt->priv = new_crypt->ops->init(key);
if (!new_crypt->ops || !new_crypt->priv) { if (!new_crypt->ops || !new_crypt->priv) {
...@@ -507,7 +505,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -507,7 +505,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int i, idx; int i, idx;
int group_key = 0; int group_key = 0;
const char *alg, *module; const char *alg;
struct ieee80211_crypto_ops *ops; struct ieee80211_crypto_ops *ops;
struct ieee80211_crypt_data **crypt; struct ieee80211_crypt_data **crypt;
...@@ -570,15 +568,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -570,15 +568,12 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
switch (ext->alg) { switch (ext->alg) {
case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_WEP:
alg = "WEP"; alg = "WEP";
module = "ieee80211_crypt_wep";
break; break;
case IW_ENCODE_ALG_TKIP: case IW_ENCODE_ALG_TKIP:
alg = "TKIP"; alg = "TKIP";
module = "ieee80211_crypt_tkip";
break; break;
case IW_ENCODE_ALG_CCMP: case IW_ENCODE_ALG_CCMP:
alg = "CCMP"; alg = "CCMP";
module = "ieee80211_crypt_ccmp";
break; break;
default: default:
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
...@@ -589,10 +584,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -589,10 +584,8 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
printk("alg name:%s\n",alg); printk("alg name:%s\n",alg);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) { if (ops == NULL)
request_module("%s", module);
ops = ieee80211_get_crypto_ops(alg); ops = ieee80211_get_crypto_ops(alg);
}
if (ops == NULL) { if (ops == NULL) {
IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
dev->name, ext->alg); dev->name, ext->alg);
...@@ -612,7 +605,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ...@@ -612,7 +605,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
goto done; goto done;
} }
new_crypt->ops = ops; new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) if (new_crypt->ops)
new_crypt->priv = new_crypt->ops->init(idx); new_crypt->priv = new_crypt->ops->init(idx);
if (new_crypt->priv == NULL) { if (new_crypt->priv == NULL) {
kfree(new_crypt); kfree(new_crypt);
......
config STLC45XX
tristate "stlc4550/4560 support"
depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS
---help---
This is a driver for stlc4550 and stlc4560 chipsets.
To compile this driver as a module, choose M here: the module will be
called stlc45xx. If unsure, say N.
obj-$(CONFIG_STLC45XX) += stlc45xx.o
/*
* This file is part of stlc45xx
*
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
*
* Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "stlc45xx.h"
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/spi/spi.h>
#include <linux/etherdevice.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>
#include "stlc45xx_lmac.h"
/*
* gpios should be handled in board files and provided via platform data,
* but because it's currently impossible for stlc45xx to have a header file
* in include/linux, let's use module paramaters for now
*/
static int stlc45xx_gpio_power = 97;
module_param(stlc45xx_gpio_power, int, 0444);
MODULE_PARM_DESC(stlc45xx_gpio_power, "stlc45xx gpio number for power line");
static int stlc45xx_gpio_irq = 87;
module_param(stlc45xx_gpio_irq, int, 0444);
MODULE_PARM_DESC(stlc45xx_gpio_irq, "stlc45xx gpio number for irq line");
static const u8 default_cal_channels[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x09,
0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10,
0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xe0, 0x00, 0xe0, 0x00,
0xe0, 0x00, 0xe0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9,
0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d,
0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17,
0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00,
0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x71, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8,
0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0,
0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6,
0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca,
0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21,
0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00,
0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0,
0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76,
0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01,
0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0,
0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37,
0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b,
0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00,
0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0,
0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a,
0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x09, 0x00, 0x00, 0xc9, 0xff,
0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab,
0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33,
0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00,
0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0,
0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7,
0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d,
0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00,
0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00,
0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0,
0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42,
0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01,
0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0,
0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0,
0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17,
0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x09, 0x00, 0x00, 0xc9,
0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01,
0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01,
0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0,
0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb,
0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21,
0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0,
0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x8a, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00,
0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0,
0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0,
0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22,
0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b,
0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0,
0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d,
0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x09, 0x00, 0x00,
0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10,
0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54,
0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33,
0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0,
0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0,
0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17,
0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c,
0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00,
0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0,
0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42,
0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0,
0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0,
0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21,
0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d,
0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0,
0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x09, 0x00,
0x00, 0xc9, 0xff, 0xd8, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x01,
0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0,
0x00, 0xf0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
0x54, 0x01, 0xab, 0xf6, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0,
0x42, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0,
0x33, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc,
0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0xfb, 0x00, 0xca, 0x79, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b,
0xc0, 0x2b, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54,
0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00,
0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0xa7, 0x00, 0xa9, 0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0,
0x17, 0xc0, 0x17, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06,
0x2c, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96,
0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x9e, 0x09, 0x00, 0x00, 0xc9, 0xff, 0xd8, 0xff,
0x00, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10,
0x01, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xd0, 0x00,
0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0x54, 0x01, 0xab, 0xf6, 0xc0,
0x42, 0xc0, 0x42, 0xc0, 0x42, 0xc0, 0x42, 0x00, 0xcb, 0x00, 0xcb,
0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00, 0xcb, 0x00,
0xcb, 0x22, 0x01, 0x37, 0xa9, 0xc0, 0x33, 0xc0, 0x33, 0xc0, 0x33,
0xc0, 0x33, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00,
0xbc, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbc, 0xfb, 0x00, 0xca, 0x79,
0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0xc0, 0x2b, 0x00, 0xb4, 0x00,
0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4, 0x00, 0xb4,
0x00, 0xb4, 0xd0, 0x00, 0x5d, 0x54, 0xc0, 0x21, 0xc0, 0x21, 0xc0,
0x21, 0xc0, 0x21, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0xa7, 0x00, 0xa9,
0x3d, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0xc0, 0x17, 0x00, 0xa0,
0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00,
0xa0, 0x00, 0xa0, 0x7a, 0x00, 0x06, 0x2c, 0xc0, 0x0d, 0xc0, 0x0d,
0xc0, 0x0d, 0xc0, 0x0d, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00,
0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x96, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 };
static const u8 default_cal_rssi[] = {
0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72,
0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00,
0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a,
0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe,
0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00,
0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01,
0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a,
0x00, 0x00, 0x00, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
static void stlc45xx_tx_edcf(struct stlc45xx *stlc);
static void stlc45xx_tx_setup(struct stlc45xx *stlc);
static void stlc45xx_tx_scan(struct stlc45xx *stlc);
static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable);
static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave);
static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave);
static ssize_t stlc45xx_sysfs_show_cal_rssi(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct stlc45xx *stlc = dev_get_drvdata(dev);
ssize_t len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
len = PAGE_SIZE;
mutex_lock(&stlc->mutex);
if (stlc->cal_rssi)
hex_dump_to_buffer(stlc->cal_rssi, RSSI_CAL_ARRAY_LEN, 16,
2, buf, len, 0);
mutex_unlock(&stlc->mutex);
len = strlen(buf);
return len;
}
static ssize_t stlc45xx_sysfs_store_cal_rssi(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct stlc45xx *stlc = dev_get_drvdata(dev);
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
if (count != RSSI_CAL_ARRAY_LEN) {
stlc45xx_error("invalid cal_rssi length: %zu", count);
count = 0;
goto out_unlock;
}
kfree(stlc->cal_rssi);
stlc->cal_rssi = kmemdup(buf, RSSI_CAL_ARRAY_LEN, GFP_KERNEL);
if (!stlc->cal_rssi) {
stlc45xx_error("failed to allocate memory for cal_rssi");
count = 0;
goto out_unlock;
}
out_unlock:
mutex_unlock(&stlc->mutex);
return count;
}
static ssize_t stlc45xx_sysfs_show_cal_channels(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct stlc45xx *stlc = dev_get_drvdata(dev);
ssize_t len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
len = PAGE_SIZE;
mutex_lock(&stlc->mutex);
if (stlc->cal_channels)
hex_dump_to_buffer(stlc->cal_channels, CHANNEL_CAL_ARRAY_LEN,
16, 2, buf, len, 0);
mutex_unlock(&stlc->mutex);
len = strlen(buf);
return len;
}
static ssize_t stlc45xx_sysfs_store_cal_channels(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct stlc45xx *stlc = dev_get_drvdata(dev);
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
if (count != CHANNEL_CAL_ARRAY_LEN) {
stlc45xx_error("invalid cal_channels size: %zu ", count);
count = 0;
goto out_unlock;
}
kfree(stlc->cal_channels);
stlc->cal_channels = kmemdup(buf, count, GFP_KERNEL);
if (!stlc->cal_channels) {
stlc45xx_error("failed to allocate memory for cal_channels");
count = 0;
goto out_unlock;
}
out_unlock:
mutex_unlock(&stlc->mutex);
return count;
}
static ssize_t stlc45xx_sysfs_show_tx_buf(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct stlc45xx *stlc = dev_get_drvdata(dev);
struct txbuffer *entry;
ssize_t len = 0;
stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
mutex_lock(&stlc->mutex);
list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
len += sprintf(buf + len, "0x%x: 0x%x-0x%x\n",
entry->handle, entry->start,
entry->end);
}
mutex_unlock(&stlc->mutex);
return len;
}
static DEVICE_ATTR(cal_rssi, S_IRUGO | S_IWUSR,
stlc45xx_sysfs_show_cal_rssi,
stlc45xx_sysfs_store_cal_rssi);
static DEVICE_ATTR(cal_channels, S_IRUGO | S_IWUSR,
stlc45xx_sysfs_show_cal_channels,
stlc45xx_sysfs_store_cal_channels);
static DEVICE_ATTR(tx_buf, S_IRUGO, stlc45xx_sysfs_show_tx_buf, NULL);
static void stlc45xx_spi_read(struct stlc45xx *stlc, unsigned long addr,
void *buf, size_t len)
{
struct spi_transfer t[2];
struct spi_message m;
/* We first push the address */
addr = (addr << 8) | ADDR_READ_BIT_15;
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].tx_buf = &addr;
t[0].len = 2;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
spi_sync(stlc->spi, &m);
}
static void stlc45xx_spi_write(struct stlc45xx *stlc, unsigned long addr,
void *buf, size_t len)
{
struct spi_transfer t[3];
struct spi_message m;
u16 last_word;
/* We first push the address */
addr = addr << 8;
spi_message_init(&m);
memset(t, 0, sizeof(t));
t[0].tx_buf = &addr;
t[0].len = 2;
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
if (len % 2) {
last_word = ((u8 *)buf)[len - 1];
t[2].tx_buf = &last_word;
t[2].len = 2;
spi_message_add_tail(&t[2], &m);
}
spi_sync(stlc->spi, &m);
}
static u16 stlc45xx_read16(struct stlc45xx *stlc, unsigned long addr)
{
u16 val;
stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
return val;
}
static u32 stlc45xx_read32(struct stlc45xx *stlc, unsigned long addr)
{
u32 val;
stlc45xx_spi_read(stlc, addr, &val, sizeof(val));
return val;
}
static void stlc45xx_write16(struct stlc45xx *stlc, unsigned long addr, u16 val)
{
stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
}
static void stlc45xx_write32(struct stlc45xx *stlc, unsigned long addr, u32 val)
{
stlc45xx_spi_write(stlc, addr, &val, sizeof(val));
}
struct stlc45xx_spi_reg {
u16 address;
u16 length;
char *name;
};
/* caller must hold tx_lock */
static void stlc45xx_txbuffer_dump(struct stlc45xx *stlc)
{
struct txbuffer *txbuffer;
char *buf, *pos;
int buf_len, l, count;
if (!(DEBUG_LEVEL & DEBUG_TXBUFFER))
return;
stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
buf_len = 500;
buf = kmalloc(buf_len, GFP_ATOMIC);
if (!buf)
return;
pos = buf;
count = 0;
list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
l = snprintf(pos, buf_len, "0x%x-0x%x,",
txbuffer->start, txbuffer->end);
/* drop the null byte */
pos += l;
buf_len -= l;
count++;
}
if (count == 0)
*pos = '\0';
else
*--pos = '\0';
stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: in buffer %d regions: %s",
count, buf);
kfree(buf);
}
/* caller must hold tx_lock */
static int stlc45xx_txbuffer_find(struct stlc45xx *stlc, size_t len)
{
struct txbuffer *txbuffer;
int pos;
stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
pos = FIRMWARE_TXBUFFER_START;
if (list_empty(&stlc->txbuffer))
goto out;
/*
* the entries in txbuffer must be in the same order as they are in
* the real buffer
*/
list_for_each_entry(txbuffer, &stlc->txbuffer, buffer_list) {
if (pos + len < txbuffer->start)
break;
pos = ALIGN(txbuffer->end + 1, 4);
}
if (pos + len > FIRMWARE_TXBUFFER_END)
/* not enough room */
pos = -1;
stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: find %zu B: 0x%x", len, pos);
out:
return pos;
}
static int stlc45xx_txbuffer_add(struct stlc45xx *stlc,
struct txbuffer *txbuffer)
{
struct txbuffer *r, *prev = NULL;
if (list_empty(&stlc->txbuffer)) {
list_add(&txbuffer->buffer_list, &stlc->txbuffer);
return 0;
}
r = list_first_entry(&stlc->txbuffer, struct txbuffer, buffer_list);
if (txbuffer->start < r->start) {
/* add to the beginning of the list */
list_add(&txbuffer->buffer_list, &stlc->txbuffer);
return 0;
}
prev = NULL;
list_for_each_entry(r, &stlc->txbuffer, buffer_list) {
/* skip first entry, we checked for that above */
if (!prev) {
prev = r;
continue;
}
/* double-check overlaps */
WARN_ON_ONCE(txbuffer->start >= r->start &&
txbuffer->start <= r->end);
WARN_ON_ONCE(txbuffer->end >= r->start &&
txbuffer->end <= r->end);
if (prev->end < txbuffer->start &&
txbuffer->end < r->start) {
/* insert at this spot */
list_add_tail(&txbuffer->buffer_list, &r->buffer_list);
return 0;
}
prev = r;
}
/* not found */
list_add_tail(&txbuffer->buffer_list, &stlc->txbuffer);
return 0;
}
/* caller must hold tx_lock */
static struct txbuffer *stlc45xx_txbuffer_alloc(struct stlc45xx *stlc,
size_t frame_len)
{
struct txbuffer *entry = NULL;
size_t len;
int pos;
stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
len = FIRMWARE_TXBUFFER_HEADER + frame_len + FIRMWARE_TXBUFFER_TRAILER;
pos = stlc45xx_txbuffer_find(stlc, len);
if (pos < 0)
return NULL;
WARN_ON_ONCE(pos + len > FIRMWARE_TXBUFFER_END);
WARN_ON_ONCE(pos < FIRMWARE_TXBUFFER_START);
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
entry->start = pos;
entry->frame_start = pos + FIRMWARE_TXBUFFER_HEADER;
entry->end = entry->start + len - 1;
stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: allocated 0x%x-0x%x",
entry->start, entry->end);
stlc45xx_txbuffer_add(stlc, entry);
stlc45xx_txbuffer_dump(stlc);
return entry;
}
/* caller must hold tx_lock */
static void stlc45xx_txbuffer_free(struct stlc45xx *stlc,
struct txbuffer *txbuffer)
{
stlc45xx_debug(DEBUG_FUNC, "%s()", __func__);
stlc45xx_debug(DEBUG_TXBUFFER, "txbuffer: freed 0x%x-0x%x",
txbuffer->start, txbuffer->end);
list_del(&txbuffer->buffer_list);
kfree(txbuffer);
}
static int stlc45xx_wait_bit(struct stlc45xx *stlc, u16 reg, u32 mask,
u32 expected)
{
int i;
char buffer[4];
for (i = 0; i < 2000; i++) {
stlc45xx_spi_read(stlc, reg, buffer, sizeof(buffer));
if (((*(u32 *)buffer) & mask) == expected)
return 1;
msleep(1);
}
return 0;
}
static int stlc45xx_request_firmware(struct stlc45xx *stlc)
{
const struct firmware *fw;
int ret;
/* FIXME: should driver use it's own struct device? */
ret = request_firmware(&fw, "3826.arm", &stlc->spi->dev);
if (ret < 0) {
stlc45xx_error("request_firmware() failed: %d", ret);
return ret;
}
if (fw->size % 4) {
stlc45xx_error("firmware size is not multiple of 32bit: %zu",
fw->size);
return -EILSEQ; /* Illegal byte sequence */;
}
if (fw->size < 1000) {
stlc45xx_error("firmware is too small: %zu", fw->size);
return -EILSEQ;
}
stlc->fw = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!stlc->fw) {
stlc45xx_error("could not allocate memory for firmware");
return -ENOMEM;
}
stlc->fw_len = fw->size;
release_firmware(fw);
return 0;
}
static int stlc45xx_upload_firmware(struct stlc45xx *stlc)
{
struct s_dma_regs dma_regs;
unsigned long fw_len, fw_addr;
long _fw_len;
int ret;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
if (!stlc->fw) {
ret = stlc45xx_request_firmware(stlc);
if (ret < 0)
return ret;
}
/* stop the device */
stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
| SPI_CTRL_STAT_START_HALTED);
msleep(TARGET_BOOT_SLEEP);
stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
SPI_CTRL_STAT_HOST_OVERRIDE
| SPI_CTRL_STAT_START_HALTED);
msleep(TARGET_BOOT_SLEEP);
fw_addr = FIRMWARE_ADDRESS;
fw_len = stlc->fw_len;
while (fw_len > 0) {
_fw_len = (fw_len > SPI_MAX_PACKET_SIZE)
? SPI_MAX_PACKET_SIZE : fw_len;
dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
dma_regs.len = cpu_to_le16(_fw_len);
dma_regs.addr = cpu_to_le32(fw_addr);
fw_len -= _fw_len;
fw_addr += _fw_len;
stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_CTRL, dma_regs.cmd);
if (stlc45xx_wait_bit(stlc, SPI_ADRS_DMA_WRITE_CTRL,
HOST_ALLOWED, HOST_ALLOWED) == 0) {
stlc45xx_error("fw_upload not allowed to DMA write");
return -EAGAIN;
}
stlc45xx_write16(stlc, SPI_ADRS_DMA_WRITE_LEN, dma_regs.len);
stlc45xx_write32(stlc, SPI_ADRS_DMA_WRITE_BASE, dma_regs.addr);
stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, stlc->fw, _fw_len);
/* FIXME: I think this doesn't work if firmware is large,
* this loop goes to second round. fw->data is not
* increased at all! */
}
BUG_ON(fw_len != 0);
/* enable host interrupts */
stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN, SPI_HOST_INTS_DEFAULT);
/* boot the device */
stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET
| SPI_CTRL_STAT_RAM_BOOT);
msleep(TARGET_BOOT_SLEEP);
stlc45xx_write16(stlc, SPI_ADRS_DEV_CTRL_STAT,
SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT);
msleep(TARGET_BOOT_SLEEP);
return 0;
}
/* caller must hold tx_lock */
static void stlc45xx_check_txsent(struct stlc45xx *stlc)
{
struct txbuffer *entry, *n;
list_for_each_entry_safe(entry, n, &stlc->tx_sent, tx_list) {
if (time_after(jiffies, entry->lifetime)) {
if (net_ratelimit())
stlc45xx_warning("frame 0x%x lifetime exceeded",
entry->start);
list_del(&entry->tx_list);
skb_pull(entry->skb, entry->header_len);
ieee80211_tx_status(stlc->hw, entry->skb);
stlc45xx_txbuffer_free(stlc, entry);
}
}
}
static void stlc45xx_power_off(struct stlc45xx *stlc)
{
disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
gpio_set_value(stlc45xx_gpio_power, 0);
}
static void stlc45xx_power_on(struct stlc45xx *stlc)
{
gpio_set_value(stlc45xx_gpio_power, 1);
enable_irq(gpio_to_irq(stlc45xx_gpio_irq));
/*
* need to wait a while before device can be accessed, the length
* is just a guess
*/
msleep(10);
}
/* caller must hold tx_lock */
static void stlc45xx_flush_queues(struct stlc45xx *stlc)
{
struct txbuffer *entry;
while (!list_empty(&stlc->tx_sent)) {
entry = list_first_entry(&stlc->tx_sent,
struct txbuffer, tx_list);
list_del(&entry->tx_list);
dev_kfree_skb(entry->skb);
stlc45xx_txbuffer_free(stlc, entry);
}
WARN_ON(!list_empty(&stlc->tx_sent));
while (!list_empty(&stlc->tx_pending)) {
entry = list_first_entry(&stlc->tx_pending,
struct txbuffer, tx_list);
list_del(&entry->tx_list);
dev_kfree_skb(entry->skb);
stlc45xx_txbuffer_free(stlc, entry);
}
WARN_ON(!list_empty(&stlc->tx_pending));
WARN_ON(!list_empty(&stlc->txbuffer));
}
static void stlc45xx_work_reset(struct work_struct *work)
{
struct stlc45xx *stlc = container_of(work, struct stlc45xx,
work_reset);
mutex_lock(&stlc->mutex);
if (stlc->fw_state != FW_STATE_RESET)
goto out;
stlc45xx_power_off(stlc);
mutex_unlock(&stlc->mutex);
/* wait that all work_structs have finished, we can't hold
* stlc->mutex to avoid deadlock */
cancel_work_sync(&stlc->work);
/* FIXME: find out good value to wait for chip power down */
msleep(100);
mutex_lock(&stlc->mutex);
/* FIXME: we should gracefully handle if the state has changed
* after re-acquiring mutex */
WARN_ON(stlc->fw_state != FW_STATE_RESET);
spin_lock_bh(&stlc->tx_lock);
stlc45xx_flush_queues(stlc);
spin_unlock_bh(&stlc->tx_lock);
stlc->fw_state = FW_STATE_RESETTING;
stlc45xx_power_on(stlc);
stlc45xx_upload_firmware(stlc);
out:
mutex_unlock(&stlc->mutex);
}
/* caller must hold mutex */
static void stlc45xx_reset(struct stlc45xx *stlc)
{
stlc45xx_warning("resetting firmware");
stlc->fw_state = FW_STATE_RESET;
ieee80211_stop_queues(stlc->hw);
queue_work(stlc->hw->workqueue, &stlc->work_reset);
}
static void stlc45xx_work_tx_timeout(struct work_struct *work)
{
struct stlc45xx *stlc = container_of(work, struct stlc45xx,
work_tx_timeout.work);
stlc45xx_warning("tx timeout");
mutex_lock(&stlc->mutex);
if (stlc->fw_state != FW_STATE_READY)
goto out;
stlc45xx_reset(stlc);
out:
mutex_unlock(&stlc->mutex);
}
static void stlc45xx_int_ack(struct stlc45xx *stlc, u32 val)
{
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_ACK, val);
}
static void stlc45xx_wakeup(struct stlc45xx *stlc)
{
unsigned long timeout;
u32 ints;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
/* wake the chip */
stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_WAKEUP);
/* And wait for the READY interrupt */
timeout = jiffies + HZ;
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
while (!(ints & SPI_HOST_INT_READY)) {
if (time_after(jiffies, timeout))
goto out;
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
}
stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
out:
return;
}
static void stlc45xx_sleep(struct stlc45xx *stlc)
{
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
stlc45xx_write32(stlc, SPI_ADRS_ARM_INTERRUPTS, SPI_TARGET_INT_SLEEP);
}
static void stlc45xx_int_ready(struct stlc45xx *stlc)
{
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
stlc45xx_write32(stlc, SPI_ADRS_HOST_INT_EN,
SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE);
switch (stlc->fw_state) {
case FW_STATE_BOOTING:
stlc->fw_state = FW_STATE_READY;
complete(&stlc->fw_comp);
break;
case FW_STATE_RESETTING:
stlc->fw_state = FW_STATE_READY;
stlc45xx_tx_scan(stlc);
stlc45xx_tx_setup(stlc);
stlc45xx_tx_edcf(stlc);
ieee80211_wake_queues(stlc->hw);
break;
default:
break;
}
}
static int stlc45xx_rx_txack(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
struct s_lm_control *control;
struct s_lmo_tx *tx;
struct txbuffer *entry;
int found = 0;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
control = (struct s_lm_control *) skb->data;
tx = (struct s_lmo_tx *) (control + 1);
if (list_empty(&stlc->tx_sent)) {
if (net_ratelimit())
stlc45xx_warning("no frames waiting for "
"acknowledgement");
return -1;
}
list_for_each_entry(entry, &stlc->tx_sent, tx_list) {
if (control->handle == entry->handle) {
found = 1;
break;
}
}
if (!found) {
if (net_ratelimit())
stlc45xx_warning("couldn't find frame for tx ack 0x%x",
control->handle);
return -1;
}
stlc45xx_debug(DEBUG_TX, "TX ACK 0x%x", entry->handle);
if (entry->status_needed) {
info = IEEE80211_SKB_CB(entry->skb);
if (!(tx->flags & LM_TX_FAILED)) {
/* frame was acked */
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = tx->rcpi / 2 - 110;
}
skb_pull(entry->skb, entry->header_len);
ieee80211_tx_status(stlc->hw, entry->skb);
}
list_del(&entry->tx_list);
stlc45xx_check_txsent(stlc);
if (list_empty(&stlc->tx_sent))
/* there are no pending frames, we can stop the tx timeout
* timer */
cancel_delayed_work(&stlc->work_tx_timeout);
spin_lock_bh(&stlc->tx_lock);
stlc45xx_txbuffer_free(stlc, entry);
if (stlc->tx_queue_stopped &&
stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) != -1) {
stlc45xx_debug(DEBUG_QUEUE, "room in tx buffer, waking queues");
ieee80211_wake_queues(stlc->hw);
stlc->tx_queue_stopped = 0;
}
spin_unlock_bh(&stlc->tx_lock);
return 0;
}
static int stlc45xx_rx_control(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct s_lm_control *control;
int ret = 0;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
control = (struct s_lm_control *) skb->data;
switch (control->oid) {
case LM_OID_TX:
ret = stlc45xx_rx_txack(stlc, skb);
break;
case LM_OID_SETUP:
case LM_OID_SCAN:
case LM_OID_TRAP:
case LM_OID_EDCF:
case LM_OID_KEYCACHE:
case LM_OID_PSM:
case LM_OID_STATS:
case LM_OID_LED:
default:
stlc45xx_warning("unhandled rx control oid %d\n",
control->oid);
break;
}
dev_kfree_skb(skb);
return ret;
}
/* copied from mac80211 */
static void stlc45xx_parse_elems(u8 *start, size_t len,
struct stlc45xx_ie_tim **tim,
size_t *tim_len)
{
size_t left = len;
u8 *pos = start;
while (left >= 2) {
u8 id, elen;
id = *pos++;
elen = *pos++;
left -= 2;
if (elen > left)
return;
switch (id) {
case WLAN_EID_TIM:
*tim = (struct stlc45xx_ie_tim *) pos;
*tim_len = elen;
break;
default:
break;
}
left -= elen;
pos += elen;
}
}
/*
* mac80211 doesn't have support for asking frames with PS-Poll, so let's
* implement in the driver for now. We have to add support to mac80211
* later.
*/
static int stlc45xx_check_more_data(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
struct ieee80211_hdr *hdr;
size_t len;
u16 fc;
hdr = (void *) skb->data + sizeof(*data);
len = skb->len - sizeof(*data);
/* minimum frame length is the null frame length 24 bytes */
if (len < 24) {
stlc45xx_warning("invalid frame length when checking for "
"more data");
return -EINVAL;
}
fc = le16_to_cpu(hdr->frame_control);
if (!(fc & IEEE80211_FCTL_FROMDS))
/* this is not from DS */
return 0;
if (compare_ether_addr(hdr->addr1, stlc->mac_addr) != 0)
/* the frame was not for us */
return 0;
if (!(fc & IEEE80211_FCTL_MOREDATA)) {
/* AP has no more frames buffered for us */
stlc45xx_debug(DEBUG_PSM, "all buffered frames retrieved");
stlc->pspolling = false;
return 0;
}
/* MOREDATA bit is set, let's ask for a new frame from the AP */
stlc45xx_tx_pspoll(stlc, stlc->psm);
return 0;
}
/*
* mac80211 cannot read TIM from beacons, so let's add a hack to the
* driver. We have to add support to mac80211 later.
*/
static int stlc45xx_rx_data_beacon(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
size_t len = skb->len, tim_len = 0, baselen, pvbmap_len;
struct ieee80211_mgmt *mgmt;
struct stlc45xx_ie_tim *tim = NULL;
int bmap_offset, index, aid_bit;
mgmt = (void *) skb->data + sizeof(*data);
baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
if (baselen > len) {
stlc45xx_warning("invalid baselen in beacon");
return -EINVAL;
}
stlc45xx_parse_elems(mgmt->u.beacon.variable, len - baselen, &tim,
&tim_len);
if (!tim) {
stlc45xx_warning("didn't find tim from a beacon");
return -EINVAL;
}
bmap_offset = tim->bmap_control & 0xfe;
index = stlc->aid / 8 - bmap_offset;
pvbmap_len = tim_len - 3;
if (index > pvbmap_len)
return -EINVAL;
aid_bit = !!(tim->pvbmap[index] & (1 << stlc->aid % 8));
stlc45xx_debug(DEBUG_PSM, "fc 0x%x duration %d seq %d dtim %u "
"bmap_control 0x%x aid_bit %d",
mgmt->frame_control, mgmt->duration, mgmt->seq_ctrl >> 4,
tim->dtim_count, tim->bmap_control, aid_bit);
if (!aid_bit)
return 0;
stlc->pspolling = true;
stlc45xx_tx_pspoll(stlc, stlc->psm);
return 0;
}
static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct ieee80211_rx_status status;
struct s_lm_data_in *data = (struct s_lm_data_in *) skb->data;
int align = 0;
u8 *p, align_len;
u16 len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
if (stlc->psm) {
if (data->flags & LM_IN_BEACON)
stlc45xx_rx_data_beacon(stlc, skb);
else if (stlc->pspolling && (data->flags & LM_IN_DATA))
stlc45xx_check_more_data(stlc, skb);
}
memset(&status, 0, sizeof(status));
status.freq = data->frequency;
status.signal = data->rcpi / 2 - 110;
/* let's assume that maximum rcpi value is 140 (= 35 dBm) */
status.qual = data->rcpi * 100 / 140;
status.band = IEEE80211_BAND_2GHZ;
/*
* FIXME: this gives warning from __ieee80211_rx()
*
* status.rate_idx = data->rate;
*/
len = data->length;
if (data->flags & LM_FLAG_ALIGN)
align = 1;
skb_pull(skb, sizeof(*data));
if (align) {
p = skb->data;
align_len = *p;
skb_pull(skb, align_len);
}
skb_trim(skb, len);
stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
ieee80211_rx(stlc->hw, skb);
return 0;
}
static int stlc45xx_rx(struct stlc45xx *stlc)
{
struct s_lm_control *control;
struct sk_buff *skb;
int ret;
u16 len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
stlc45xx_wakeup(stlc);
/* dummy read to flush SPI DMA controller bug */
stlc45xx_read16(stlc, SPI_ADRS_GEN_PURP_1);
len = stlc45xx_read16(stlc, SPI_ADRS_DMA_DATA);
if (len == 0) {
stlc45xx_warning("rx request of zero bytes");
return 0;
}
skb = dev_alloc_skb(len);
if (!skb) {
stlc45xx_warning("could not alloc skb");
return 0;
}
stlc45xx_spi_read(stlc, SPI_ADRS_DMA_DATA, skb_put(skb, len), len);
stlc45xx_sleep(stlc);
stlc45xx_debug(DEBUG_RX, "rx frame 0x%p %d B", skb->data, skb->len);
stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
control = (struct s_lm_control *) skb->data;
if (control->flags & LM_FLAG_CONTROL)
ret = stlc45xx_rx_control(stlc, skb);
else
ret = stlc45xx_rx_data(stlc, skb);
return ret;
}
static irqreturn_t stlc45xx_interrupt(int irq, void *config)
{
struct spi_device *spi = config;
struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
stlc45xx_debug(DEBUG_IRQ, "IRQ");
queue_work(stlc->hw->workqueue, &stlc->work);
return IRQ_HANDLED;
}
static int stlc45xx_tx_frame(struct stlc45xx *stlc, u32 address,
void *buf, size_t len)
{
struct s_dma_regs dma_regs;
unsigned long timeout;
int ret = 0;
u32 ints;
stlc->tx_frames++;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
stlc45xx_debug(DEBUG_TX, "tx frame 0x%p %zu B", buf, len);
stlc45xx_dump(DEBUG_TX_CONTENT, buf, len);
stlc45xx_wakeup(stlc);
dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE;
dma_regs.len = cpu_to_le16(len);
dma_regs.addr = cpu_to_le32(address);
stlc45xx_spi_write(stlc, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs,
sizeof(dma_regs));
stlc45xx_spi_write(stlc, SPI_ADRS_DMA_DATA, buf, len);
timeout = jiffies + 2 * HZ;
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
while (!(ints & SPI_HOST_INT_WR_READY)) {
if (time_after(jiffies, timeout)) {
stlc45xx_warning("WR_READY timeout");
ret = -1;
goto out;
}
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
}
stlc45xx_int_ack(stlc, SPI_HOST_INT_WR_READY);
stlc45xx_sleep(stlc);
out:
return ret;
}
static int stlc45xx_wq_tx(struct stlc45xx *stlc)
{
struct txbuffer *entry;
int ret = 0;
spin_lock_bh(&stlc->tx_lock);
while (!list_empty(&stlc->tx_pending)) {
entry = list_entry(stlc->tx_pending.next,
struct txbuffer, tx_list);
list_del_init(&entry->tx_list);
spin_unlock_bh(&stlc->tx_lock);
ret = stlc45xx_tx_frame(stlc, entry->frame_start,
entry->skb->data, entry->skb->len);
spin_lock_bh(&stlc->tx_lock);
if (ret < 0) {
/* frame transfer to firmware buffer failed */
/* FIXME: report this to mac80211 */
dev_kfree_skb(entry->skb);
stlc45xx_txbuffer_free(stlc, entry);
goto out;
}
list_add(&entry->tx_list, &stlc->tx_sent);
queue_delayed_work(stlc->hw->workqueue,
&stlc->work_tx_timeout,
msecs_to_jiffies(TX_TIMEOUT));
}
out:
spin_unlock_bh(&stlc->tx_lock);
return ret;
}
static void stlc45xx_work(struct work_struct *work)
{
struct stlc45xx *stlc = container_of(work, struct stlc45xx, work);
u32 ints;
int ret;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
if (stlc->fw_state == FW_STATE_OFF &&
stlc->fw_state == FW_STATE_RESET)
goto out;
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
stlc45xx_debug(DEBUG_BH, "begin host_ints 0x%08x", ints);
if (ints & SPI_HOST_INT_READY) {
stlc45xx_int_ready(stlc);
stlc45xx_int_ack(stlc, SPI_HOST_INT_READY);
}
if (stlc->fw_state != FW_STATE_READY)
goto out;
if (ints & SPI_HOST_INT_UPDATE) {
stlc45xx_int_ack(stlc, SPI_HOST_INT_UPDATE);
ret = stlc45xx_rx(stlc);
if (ret < 0) {
stlc45xx_reset(stlc);
goto out;
}
}
if (ints & SPI_HOST_INT_SW_UPDATE) {
stlc45xx_int_ack(stlc, SPI_HOST_INT_SW_UPDATE);
ret = stlc45xx_rx(stlc);
if (ret < 0) {
stlc45xx_reset(stlc);
goto out;
}
}
ret = stlc45xx_wq_tx(stlc);
if (ret < 0) {
stlc45xx_reset(stlc);
goto out;
}
ints = stlc45xx_read32(stlc, SPI_ADRS_HOST_INTERRUPTS);
stlc45xx_debug(DEBUG_BH, "end host_ints 0x%08x", ints);
out:
mutex_unlock(&stlc->mutex);
}
static void stlc45xx_tx_edcf(struct stlc45xx *stlc)
{
struct s_lm_control *control;
struct s_lmo_edcf *edcf;
size_t len, edcf_len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
edcf_len = sizeof(*edcf);
len = sizeof(*control) + edcf_len;
control = kzalloc(len, GFP_KERNEL);
edcf = (struct s_lmo_edcf *) (control + 1);
control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
control->length = edcf_len;
control->oid = LM_OID_EDCF;
edcf->slottime = 0x14;
edcf->sifs = 10;
edcf->eofpad = 6;
edcf->maxburst = 1500;
edcf->queues[0].aifs = 2;
edcf->queues[0].pad0 = 1;
edcf->queues[0].cwmin = 3;
edcf->queues[0].cwmax = 7;
edcf->queues[0].txop = 47;
edcf->queues[1].aifs = 2;
edcf->queues[1].pad0 = 0;
edcf->queues[1].cwmin = 7;
edcf->queues[1].cwmax = 15;
edcf->queues[1].txop = 94;
edcf->queues[2].aifs = 3;
edcf->queues[2].pad0 = 0;
edcf->queues[2].cwmin = 15;
edcf->queues[2].cwmax = 1023;
edcf->queues[2].txop = 0;
edcf->queues[3].aifs = 7;
edcf->queues[3].pad0 = 0;
edcf->queues[3].cwmin = 15;
edcf->queues[3].cwmax = 1023;
edcf->queues[3].txop = 0;
edcf->queues[4].aifs = 13;
edcf->queues[4].pad0 = 99;
edcf->queues[4].cwmin = 3437;
edcf->queues[4].cwmax = 512;
edcf->queues[4].txop = 12;
edcf->queues[5].aifs = 142;
edcf->queues[5].pad0 = 109;
edcf->queues[5].cwmin = 8756;
edcf->queues[5].cwmax = 6;
edcf->queues[5].txop = 0;
edcf->queues[6].aifs = 4;
edcf->queues[6].pad0 = 0;
edcf->queues[6].cwmin = 0;
edcf->queues[6].cwmax = 58705;
edcf->queues[6].txop = 25716;
edcf->queues[7].aifs = 0;
edcf->queues[7].pad0 = 0;
edcf->queues[7].cwmin = 0;
edcf->queues[7].cwmax = 0;
edcf->queues[7].txop = 0;
stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
kfree(control);
}
static void stlc45xx_tx_setup(struct stlc45xx *stlc)
{
struct s_lm_control *control;
struct s_lmo_setup *setup;
size_t len, setup_len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
setup_len = sizeof(*setup);
len = sizeof(*control) + setup_len;
control = kzalloc(len, GFP_KERNEL);
setup = (struct s_lmo_setup *) (control + 1);
control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
control->length = setup_len;
control->oid = LM_OID_SETUP;
setup->flags = LM_SETUP_INFRA;
setup->antenna = 2;
setup->rx_align = 0;
setup->rx_buffer = FIRMWARE_RXBUFFER_START;
setup->rx_mtu = FIRMWARE_MTU;
setup->frontend = 5;
setup->timeout = 0;
setup->truncate = 48896;
setup->bratemask = 0xffffffff;
setup->ref_clock = 644245094;
setup->lpf_bandwidth = 65535;
setup->osc_start_delay = 65535;
memcpy(setup->macaddr, stlc->mac_addr, ETH_ALEN);
memcpy(setup->bssid, stlc->bssid, ETH_ALEN);
stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
kfree(control);
}
static void stlc45xx_tx_scan(struct stlc45xx *stlc)
{
struct s_lm_control *control;
struct s_lmo_scan *scan;
size_t len, scan_len;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
scan_len = sizeof(*scan);
len = sizeof(*control) + scan_len;
control = kzalloc(len, GFP_KERNEL);
scan = (struct s_lmo_scan *) (control + 1);
control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
control->length = scan_len;
control->oid = LM_OID_SCAN;
scan->flags = LM_SCAN_EXIT;
scan->bratemask = 0x15f;
scan->aloft[0] = 3;
scan->aloft[1] = 3;
scan->aloft[2] = 1;
scan->aloft[3] = 0;
scan->aloft[4] = 0;
scan->aloft[5] = 0;
scan->aloft[6] = 0;
scan->aloft[7] = 0;
memcpy(&scan->rssical, &stlc->cal_rssi[(stlc->channel - 1) *
RSSI_CAL_LEN],
RSSI_CAL_LEN);
memcpy(&scan->channel, &stlc->cal_channels[(stlc->channel - 1) *
CHANNEL_CAL_LEN],
CHANNEL_CAL_LEN);
stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
kfree(control);
}
/*
* caller must hold mutex
*/
static int stlc45xx_tx_pspoll(struct stlc45xx *stlc, bool powersave)
{
struct ieee80211_hdr *pspoll;
int payload_len, padding, i;
struct s_lm_data_out *data;
struct txbuffer *entry;
struct sk_buff *skb;
char *payload;
u16 fc;
skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 16);
if (!skb) {
stlc45xx_warning("failed to allocate pspoll frame");
return -ENOMEM;
}
skb_reserve(skb, stlc->hw->extra_tx_headroom);
pspoll = (struct ieee80211_hdr *) skb_put(skb, 16);
memset(pspoll, 0, 16);
fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL;
if (powersave)
fc |= IEEE80211_FCTL_PM;
pspoll->frame_control = cpu_to_le16(fc);
pspoll->duration_id = cpu_to_le16(stlc->aid);
/* aid in PS-Poll has its two MSBs each set to 1 */
pspoll->duration_id |= cpu_to_le16(1 << 15) | cpu_to_le16(1 << 14);
memcpy(pspoll->addr1, stlc->bssid, ETH_ALEN);
memcpy(pspoll->addr2, stlc->mac_addr, ETH_ALEN);
stlc45xx_debug(DEBUG_PSM, "sending PS-Poll frame to %pM (powersave %d, "
"fc 0x%x, aid %d)", pspoll->addr1,
powersave, fc, stlc->aid);
spin_lock_bh(&stlc->tx_lock);
entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
spin_unlock_bh(&stlc->tx_lock);
if (!entry) {
/*
* The queue should be stopped before the firmware buffer
* is full, so firmware buffer should always have enough
* space.
*
* But I'm too lazy and omit it for now.
*/
if (net_ratelimit())
stlc45xx_warning("firmware tx buffer full is full "
"for null frame");
return -ENOSPC;
}
payload = skb->data;
payload_len = skb->len;
padding = (int) (skb->data - sizeof(*data)) & 3;
entry->header_len = sizeof(*data) + padding;
entry->skb = skb;
entry->status_needed = false;
entry->handle = (u32) skb;
entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
"padding %d header_len %d)",
entry->handle, payload, payload_len, padding,
entry->header_len);
stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
memset(data, 0, entry->header_len);
if (padding)
data->flags = LM_FLAG_ALIGN;
data->flags = LM_OUT_BURST;
data->length = payload_len;
data->handle = entry->handle;
data->aid = 1;
data->rts_retries = 7;
data->retries = 7;
data->aloft_ctrl = 0;
data->crypt_offset = 58;
data->keytype = 0;
data->keylen = 0;
data->queue = LM_QUEUE_DATA3;
data->backlog = 32;
data->antenna = 2;
data->cts = 3;
data->power = 127;
for (i = 0; i < 8; i++)
data->aloft[i] = 0;
/*
* check if there's enough space in tx buffer
*
* FIXME: ignored for now
*/
stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
list_add(&entry->tx_list, &stlc->tx_sent);
return 0;
}
/*
* caller must hold mutex
*
* shamelessly stolen from mac80211/ieee80211_send_nullfunc
*/
static int stlc45xx_tx_nullfunc(struct stlc45xx *stlc, bool powersave)
{
struct ieee80211_hdr *nullfunc;
int payload_len, padding, i;
struct s_lm_data_out *data;
struct txbuffer *entry;
struct sk_buff *skb;
char *payload;
u16 fc;
skb = dev_alloc_skb(stlc->hw->extra_tx_headroom + 24);
if (!skb) {
stlc45xx_warning("failed to allocate buffer for null frame\n");
return -ENOMEM;
}
skb_reserve(skb, stlc->hw->extra_tx_headroom);
nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
memset(nullfunc, 0, 24);
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_TODS;
if (powersave)
fc |= IEEE80211_FCTL_PM;
nullfunc->frame_control = cpu_to_le16(fc);
memcpy(nullfunc->addr1, stlc->bssid, ETH_ALEN);
memcpy(nullfunc->addr2, stlc->mac_addr, ETH_ALEN);
memcpy(nullfunc->addr3, stlc->bssid, ETH_ALEN);
stlc45xx_debug(DEBUG_PSM, "sending Null frame to %pM (powersave %d, "
"fc 0x%x)", nullfunc->addr1, powersave, fc);
spin_lock_bh(&stlc->tx_lock);
entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
spin_unlock_bh(&stlc->tx_lock);
if (!entry) {
/*
* The queue should be stopped before the firmware buffer
* is full, so firmware buffer should always have enough
* space.
*
* But I'm too lazy and omit it for now.
*/
if (net_ratelimit())
stlc45xx_warning("firmware tx buffer full is full "
"for null frame");
return -ENOSPC;
}
payload = skb->data;
payload_len = skb->len;
padding = (int) (skb->data - sizeof(*data)) & 3;
entry->header_len = sizeof(*data) + padding;
entry->skb = skb;
entry->status_needed = false;
entry->handle = (u32) skb;
entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
"padding %d header_len %d)",
entry->handle, payload, payload_len, padding,
entry->header_len);
stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
memset(data, 0, entry->header_len);
if (padding)
data->flags = LM_FLAG_ALIGN;
data->flags = LM_OUT_BURST;
data->length = payload_len;
data->handle = entry->handle;
data->aid = 1;
data->rts_retries = 7;
data->retries = 7;
data->aloft_ctrl = 0;
data->crypt_offset = 58;
data->keytype = 0;
data->keylen = 0;
data->queue = LM_QUEUE_DATA3;
data->backlog = 32;
data->antenna = 2;
data->cts = 3;
data->power = 127;
for (i = 0; i < 8; i++)
data->aloft[i] = 0;
/*
* check if there's enough space in tx buffer
*
* FIXME: ignored for now
*/
stlc45xx_tx_frame(stlc, entry->start, skb->data, skb->len);
list_add(&entry->tx_list, &stlc->tx_sent);
return 0;
}
/* caller must hold mutex */
static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable)
{
struct s_lm_control *control;
struct s_lmo_psm *psm;
size_t len, psm_len;
WARN_ON(!stlc->associated);
WARN_ON(stlc->aid < 1);
WARN_ON(stlc->aid > 2007);
psm_len = sizeof(*psm);
len = sizeof(*control) + psm_len;
control = kzalloc(len, GFP_KERNEL);
psm = (struct s_lmo_psm *) (control + 1);
control->flags = LM_FLAG_CONTROL | LM_CTRL_OPSET;
control->length = psm_len;
control->oid = LM_OID_PSM;
if (enable)
psm->flags |= LM_PSM;
psm->aid = stlc->aid;
psm->beacon_rcpi_skip_max = 60;
psm->intervals[0].interval = 1;
psm->intervals[0].periods = 1;
psm->intervals[1].interval = 1;
psm->intervals[1].periods = 1;
psm->intervals[2].interval = 1;
psm->intervals[2].periods = 1;
psm->intervals[3].interval = 1;
psm->intervals[3].periods = 1;
psm->nr = 0;
psm->exclude[0] = 0;
stlc45xx_debug(DEBUG_PSM, "sending LM_OID_PSM (aid %d, interval %d)",
psm->aid, psm->intervals[0].interval);
stlc45xx_tx_frame(stlc, FIRMWARE_CONFIG_START, control, len);
kfree(control);
}
static int stlc45xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct stlc45xx *stlc = hw->priv;
struct ieee80211_tx_info *info;
struct ieee80211_rate *rate;
int payload_len, padding, i;
struct s_lm_data_out *data;
struct txbuffer *entry;
char *payload;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
spin_lock_bh(&stlc->tx_lock);
entry = stlc45xx_txbuffer_alloc(stlc, skb->len);
if (!entry) {
/* the queue should be stopped before the firmware buffer
* is full, so firmware buffer should always have enough
* space */
if (net_ratelimit())
stlc45xx_warning("firmware buffer full");
spin_unlock_bh(&stlc->tx_lock);
return NETDEV_TX_BUSY;
}
info = IEEE80211_SKB_CB(skb);
payload = skb->data;
payload_len = skb->len;
padding = (int) (skb->data - sizeof(*data)) & 3;
entry->header_len = sizeof(*data) + padding;
entry->skb = skb;
entry->status_needed = true;
entry->handle = (u32) skb;
entry->lifetime = jiffies + msecs_to_jiffies(TX_FRAME_LIFETIME);
stlc45xx_debug(DEBUG_TX, "tx data 0x%x (0x%p payload %d B "
"padding %d header_len %d)",
entry->handle, payload, payload_len, padding,
entry->header_len);
stlc45xx_dump(DEBUG_TX_CONTENT, payload, payload_len);
data = (struct s_lm_data_out *) skb_push(skb, entry->header_len);
memset(data, 0, entry->header_len);
if (padding)
data->flags = LM_FLAG_ALIGN;
data->flags = LM_OUT_BURST;
data->length = payload_len;
data->handle = entry->handle;
data->aid = 1;
data->rts_retries = 7;
data->retries = 7;
data->aloft_ctrl = 0;
data->crypt_offset = 58;
data->keytype = 0;
data->keylen = 0;
data->queue = 2;
data->backlog = 32;
data->antenna = 2;
data->cts = 3;
data->power = 127;
for (i = 0; i < 8; i++) {
rate = ieee80211_get_tx_rate(stlc->hw, info);
data->aloft[i] = rate->hw_value;
}
list_add_tail(&entry->tx_list, &stlc->tx_pending);
/* check if there's enough space in tx buffer */
if (stlc45xx_txbuffer_find(stlc, MAX_FRAME_LEN) == -1) {
stlc45xx_debug(DEBUG_QUEUE, "tx buffer full, stopping queues");
stlc->tx_queue_stopped = 1;
ieee80211_stop_queues(stlc->hw);
}
queue_work(stlc->hw->workqueue, &stlc->work);
spin_unlock_bh(&stlc->tx_lock);
return NETDEV_TX_OK;
}
static int stlc45xx_op_start(struct ieee80211_hw *hw)
{
struct stlc45xx *stlc = hw->priv;
unsigned long timeout;
int ret = 0;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
stlc->fw_state = FW_STATE_BOOTING;
stlc->channel = 1;
stlc45xx_power_on(stlc);
ret = stlc45xx_upload_firmware(stlc);
if (ret < 0) {
stlc45xx_power_off(stlc);
goto out_unlock;
}
stlc->tx_queue_stopped = 0;
mutex_unlock(&stlc->mutex);
timeout = msecs_to_jiffies(2000);
timeout = wait_for_completion_interruptible_timeout(&stlc->fw_comp,
timeout);
if (!timeout) {
stlc45xx_error("firmware boot failed");
stlc45xx_power_off(stlc);
ret = -1;
goto out;
}
stlc45xx_debug(DEBUG_BOOT, "firmware booted");
/* FIXME: should we take mutex just after wait_for_completion()? */
mutex_lock(&stlc->mutex);
WARN_ON(stlc->fw_state != FW_STATE_READY);
out_unlock:
mutex_unlock(&stlc->mutex);
out:
return ret;
}
static void stlc45xx_op_stop(struct ieee80211_hw *hw)
{
struct stlc45xx *stlc = hw->priv;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
WARN_ON(stlc->fw_state != FW_STATE_READY);
stlc45xx_power_off(stlc);
/* FIXME: make sure that all work_structs have completed */
spin_lock_bh(&stlc->tx_lock);
stlc45xx_flush_queues(stlc);
spin_unlock_bh(&stlc->tx_lock);
stlc->fw_state = FW_STATE_OFF;
mutex_unlock(&stlc->mutex);
}
static int stlc45xx_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct stlc45xx *stlc = hw->priv;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
switch (conf->type) {
case NL80211_IFTYPE_STATION:
break;
default:
return -EOPNOTSUPP;
}
memcpy(stlc->mac_addr, conf->mac_addr, ETH_ALEN);
return 0;
}
static void stlc45xx_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
}
static int stlc45xx_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct stlc45xx *stlc = hw->priv;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
stlc->channel = hw->conf.channel->hw_value;
stlc45xx_tx_scan(stlc);
stlc45xx_tx_setup(stlc);
stlc45xx_tx_edcf(stlc);
if ((hw->conf.flags & IEEE80211_CONF_PS) != stlc->psm) {
stlc->psm = hw->conf.flags & IEEE80211_CONF_PS;
if (stlc->associated) {
stlc45xx_tx_psm(stlc, stlc->psm);
stlc45xx_tx_nullfunc(stlc, stlc->psm);
}
}
mutex_unlock(&stlc->mutex);
return 0;
}
static void stlc45xx_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count,
struct dev_addr_list *mc_list)
{
*total_flags = 0;
}
static void stlc45xx_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed)
{
struct stlc45xx *stlc = hw->priv;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
mutex_lock(&stlc->mutex);
memcpy(stlc->bssid, info->bssid, ETH_ALEN);
stlc45xx_tx_setup(stlc);
mutex_unlock(&stlc->mutex);
if (changed & BSS_CHANGED_ASSOC) {
stlc->associated = info->assoc;
if (info->assoc)
stlc->aid = info->aid;
else
stlc->aid = -1;
if (stlc->psm) {
stlc45xx_tx_psm(stlc, stlc->psm);
stlc45xx_tx_nullfunc(stlc, stlc->psm);
}
}
}
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate stlc45xx_rates[] = {
{ .bitrate = 10, .hw_value = 0, .hw_value_short = 0, },
{ .bitrate = 20, .hw_value = 1, .hw_value_short = 1, },
{ .bitrate = 55, .hw_value = 2, .hw_value_short = 2, },
{ .bitrate = 110, .hw_value = 3, .hw_value_short = 3, },
{ .bitrate = 60, .hw_value = 4, .hw_value_short = 4, },
{ .bitrate = 90, .hw_value = 5, .hw_value_short = 5, },
{ .bitrate = 120, .hw_value = 6, .hw_value_short = 6, },
{ .bitrate = 180, .hw_value = 7, .hw_value_short = 7, },
{ .bitrate = 240, .hw_value = 8, .hw_value_short = 8, },
{ .bitrate = 360, .hw_value = 9, .hw_value_short = 9, },
{ .bitrate = 480, .hw_value = 10, .hw_value_short = 10, },
{ .bitrate = 540, .hw_value = 11, .hw_value_short = 11, },
};
/* can't be const, mac80211 writes to this */
static struct ieee80211_channel stlc45xx_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
{ .hw_value = 4, .center_freq = 2427},
{ .hw_value = 5, .center_freq = 2432},
{ .hw_value = 6, .center_freq = 2437},
{ .hw_value = 7, .center_freq = 2442},
{ .hw_value = 8, .center_freq = 2447},
{ .hw_value = 9, .center_freq = 2452},
{ .hw_value = 10, .center_freq = 2457},
{ .hw_value = 11, .center_freq = 2462},
{ .hw_value = 12, .center_freq = 2467},
{ .hw_value = 13, .center_freq = 2472},
};
/* can't be const, mac80211 writes to this */
static struct ieee80211_supported_band stlc45xx_band_2ghz = {
.channels = stlc45xx_channels,
.n_channels = ARRAY_SIZE(stlc45xx_channels),
.bitrates = stlc45xx_rates,
.n_bitrates = ARRAY_SIZE(stlc45xx_rates),
};
static const struct ieee80211_ops stlc45xx_ops = {
.start = stlc45xx_op_start,
.stop = stlc45xx_op_stop,
.add_interface = stlc45xx_op_add_interface,
.remove_interface = stlc45xx_op_remove_interface,
.config = stlc45xx_op_config,
.configure_filter = stlc45xx_op_configure_filter,
.tx = stlc45xx_op_tx,
.bss_info_changed = stlc45xx_op_bss_info_changed,
};
static int stlc45xx_register_mac80211(struct stlc45xx *stlc)
{
/* FIXME: SET_IEEE80211_PERM_ADDR() requires default_mac_addr
to be non-const for some strange reason */
static u8 default_mac_addr[ETH_ALEN] = {
0x00, 0x02, 0xee, 0xc0, 0xff, 0xee
};
int ret;
SET_IEEE80211_PERM_ADDR(stlc->hw, default_mac_addr);
ret = ieee80211_register_hw(stlc->hw);
if (ret) {
stlc45xx_error("unable to register mac80211 hw: %d", ret);
return ret;
}
return 0;
}
static void stlc45xx_device_release(struct device *dev)
{
}
static struct platform_device stlc45xx_device = {
.name = "stlc45xx",
.id = -1,
/* device model insists to have a release function */
.dev = {
.release = stlc45xx_device_release,
},
};
static int __devinit stlc45xx_probe(struct spi_device *spi)
{
struct stlc45xx *stlc;
struct ieee80211_hw *hw;
int ret;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
/* mac80211 alloc */
hw = ieee80211_alloc_hw(sizeof(*stlc), &stlc45xx_ops);
if (!hw) {
stlc45xx_error("could not alloc ieee80211_hw");
ret = -ENOMEM;
goto out;
}
/* mac80211 clears hw->priv */
stlc = hw->priv;
stlc->hw = hw;
dev_set_drvdata(&spi->dev, stlc);
stlc->spi = spi;
spi->bits_per_word = 16;
spi->max_speed_hz = 24000000;
ret = spi_setup(spi);
if (ret < 0)
stlc45xx_error("spi_setup failed");
ret = gpio_request(stlc45xx_gpio_power, "stlc45xx power");
if (ret < 0) {
stlc45xx_error("power GPIO request failed: %d", ret);
return ret;
}
ret = gpio_request(stlc45xx_gpio_irq, "stlc45xx irq");
if (ret < 0) {
stlc45xx_error("irq GPIO request failed: %d", ret);
goto out;
}
gpio_direction_output(stlc45xx_gpio_power, 0);
gpio_direction_input(stlc45xx_gpio_irq);
ret = request_irq(gpio_to_irq(stlc45xx_gpio_irq),
stlc45xx_interrupt, IRQF_DISABLED, "stlc45xx",
stlc->spi);
if (ret < 0)
/* FIXME: handle the error */
stlc45xx_error("request_irq() failed");
set_irq_type(gpio_to_irq(stlc45xx_gpio_irq),
IRQ_TYPE_EDGE_RISING);
disable_irq(gpio_to_irq(stlc45xx_gpio_irq));
ret = platform_device_register(&stlc45xx_device);
if (ret) {
stlc45xx_error("Couldn't register wlan_omap device.");
return ret;
}
dev_set_drvdata(&stlc45xx_device.dev, stlc);
INIT_WORK(&stlc->work, stlc45xx_work);
INIT_WORK(&stlc->work_reset, stlc45xx_work_reset);
INIT_DELAYED_WORK(&stlc->work_tx_timeout, stlc45xx_work_tx_timeout);
mutex_init(&stlc->mutex);
init_completion(&stlc->fw_comp);
spin_lock_init(&stlc->tx_lock);
INIT_LIST_HEAD(&stlc->txbuffer);
INIT_LIST_HEAD(&stlc->tx_pending);
INIT_LIST_HEAD(&stlc->tx_sent);
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
/* four bytes for padding */
hw->extra_tx_headroom = sizeof(struct s_lm_data_out) + 4;
/* unit us */
hw->channel_change_time = 1000;
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &stlc45xx_band_2ghz;
SET_IEEE80211_DEV(hw, &spi->dev);
BUILD_BUG_ON(sizeof(default_cal_rssi) != RSSI_CAL_ARRAY_LEN);
BUILD_BUG_ON(sizeof(default_cal_channels) != CHANNEL_CAL_ARRAY_LEN);
stlc->cal_rssi = kmemdup(default_cal_rssi, RSSI_CAL_ARRAY_LEN,
GFP_KERNEL);
stlc->cal_channels = kmemdup(default_cal_channels,
CHANNEL_CAL_ARRAY_LEN,
GFP_KERNEL);
ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_rssi);
if (ret < 0) {
stlc45xx_error("failed to create sysfs file cal_rssi");
goto out;
}
ret = device_create_file(&stlc45xx_device.dev, &dev_attr_cal_channels);
if (ret < 0) {
stlc45xx_error("failed to create sysfs file cal_channels");
goto out;
}
ret = device_create_file(&stlc45xx_device.dev, &dev_attr_tx_buf);
if (ret < 0) {
stlc45xx_error("failed to create sysfs file tx_buf");
goto out;
}
ret = stlc45xx_register_mac80211(stlc);
if (ret < 0)
goto out;
stlc45xx_info("v" DRIVER_VERSION " loaded");
stlc45xx_info("config buffer 0x%x-0x%x",
FIRMWARE_CONFIG_START, FIRMWARE_CONFIG_END);
stlc45xx_info("tx 0x%x-0x%x, rx 0x%x-0x%x",
FIRMWARE_TXBUFFER_START, FIRMWARE_TXBUFFER_END,
FIRMWARE_RXBUFFER_START, FIRMWARE_RXBUFFER_END);
out:
return ret;
}
static int __devexit stlc45xx_remove(struct spi_device *spi)
{
struct stlc45xx *stlc = dev_get_drvdata(&spi->dev);
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
platform_device_unregister(&stlc45xx_device);
ieee80211_unregister_hw(stlc->hw);
free_irq(gpio_to_irq(stlc45xx_gpio_irq), spi);
gpio_free(stlc45xx_gpio_power);
gpio_free(stlc45xx_gpio_irq);
/* FIXME: free cal_channels and cal_rssi? */
kfree(stlc->fw);
mutex_destroy(&stlc->mutex);
/* frees also stlc */
ieee80211_free_hw(stlc->hw);
stlc = NULL;
return 0;
}
static struct spi_driver stlc45xx_spi_driver = {
.driver = {
/* use cx3110x name because board-n800.c uses that for the
* SPI port */
.name = "cx3110x",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = stlc45xx_probe,
.remove = __devexit_p(stlc45xx_remove),
};
static int __init stlc45xx_init(void)
{
int ret;
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
ret = spi_register_driver(&stlc45xx_spi_driver);
if (ret < 0) {
stlc45xx_error("failed to register SPI driver: %d", ret);
goto out;
}
out:
return ret;
}
static void __exit stlc45xx_exit(void)
{
stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
spi_unregister_driver(&stlc45xx_spi_driver);
stlc45xx_info("unloaded");
}
module_init(stlc45xx_init);
module_exit(stlc45xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
MODULE_ALIAS("spi:cx3110x");
/*
* This file is part of stlc45xx
*
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
*
* Contact: Kalle Valo <kalle.valo@nokia.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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/mutex.h>
#include <linux/list.h>
#include <net/mac80211.h>
#include "stlc45xx_lmac.h"
#define DRIVER_NAME "stlc45xx"
#define DRIVER_VERSION "0.1.3"
#define DRIVER_PREFIX DRIVER_NAME ": "
enum {
DEBUG_NONE = 0,
DEBUG_FUNC = 1 << 0,
DEBUG_IRQ = 1 << 1,
DEBUG_BH = 1 << 2,
DEBUG_RX = 1 << 3,
DEBUG_RX_CONTENT = 1 << 5,
DEBUG_TX = 1 << 6,
DEBUG_TX_CONTENT = 1 << 8,
DEBUG_TXBUFFER = 1 << 9,
DEBUG_QUEUE = 1 << 10,
DEBUG_BOOT = 1 << 11,
DEBUG_PSM = 1 << 12,
DEBUG_ALL = ~0,
};
#define DEBUG_LEVEL DEBUG_NONE
/* #define DEBUG_LEVEL DEBUG_ALL */
/* #define DEBUG_LEVEL (DEBUG_TX | DEBUG_RX | DEBUG_IRQ) */
/* #define DEBUG_LEVEL (DEBUG_TX | DEBUG_MEMREGION | DEBUG_QUEUE) */
/* #define DEBUG_LEVEL (DEBUG_MEMREGION | DEBUG_QUEUE) */
#define stlc45xx_error(fmt, arg...) \
printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
#define stlc45xx_warning(fmt, arg...) \
printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
#define stlc45xx_info(fmt, arg...) \
printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
#define stlc45xx_debug(level, fmt, arg...) \
do { \
if (level & DEBUG_LEVEL) \
printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
} while (0)
#define stlc45xx_dump(level, buf, len) \
do { \
if (level & DEBUG_LEVEL) \
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
16, 1, buf, len, 1); \
} while (0)
#define MAC2STR(a) ((a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5])
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */
#define ADDR_READ_BIT_15 0x8000
#define SPI_ADRS_ARM_INTERRUPTS 0x00
#define SPI_ADRS_ARM_INT_EN 0x04
#define SPI_ADRS_HOST_INTERRUPTS 0x08
#define SPI_ADRS_HOST_INT_EN 0x0c
#define SPI_ADRS_HOST_INT_ACK 0x10
#define SPI_ADRS_GEN_PURP_1 0x14
#define SPI_ADRS_GEN_PURP_2 0x18
/* high word */
#define SPI_ADRS_DEV_CTRL_STAT 0x26
#define SPI_ADRS_DMA_DATA 0x28
#define SPI_ADRS_DMA_WRITE_CTRL 0x2c
#define SPI_ADRS_DMA_WRITE_LEN 0x2e
#define SPI_ADRS_DMA_WRITE_BASE 0x30
#define SPI_ADRS_DMA_READ_CTRL 0x34
#define SPI_ADRS_DMA_READ_LEN 0x36
#define SPI_ADRS_DMA_READ_BASE 0x38
#define SPI_CTRL_STAT_HOST_OVERRIDE 0x8000
#define SPI_CTRL_STAT_START_HALTED 0x4000
#define SPI_CTRL_STAT_RAM_BOOT 0x2000
#define SPI_CTRL_STAT_HOST_RESET 0x1000
#define SPI_CTRL_STAT_HOST_CPU_EN 0x0800
#define SPI_DMA_WRITE_CTRL_ENABLE 0x0001
#define SPI_DMA_READ_CTRL_ENABLE 0x0001
#define HOST_ALLOWED (1 << 7)
#define FIRMWARE_ADDRESS 0x20000
#define SPI_TIMEOUT 100 /* msec */
#define SPI_MAX_TX_PACKETS 32
#define SPI_MAX_PACKET_SIZE 32767
#define SPI_TARGET_INT_WAKEUP 0x00000001
#define SPI_TARGET_INT_SLEEP 0x00000002
#define SPI_TARGET_INT_RDDONE 0x00000004
#define SPI_TARGET_INT_CTS 0x00004000
#define SPI_TARGET_INT_DR 0x00008000
#define SPI_HOST_INT_READY 0x00000001
#define SPI_HOST_INT_WR_READY 0x00000002
#define SPI_HOST_INT_SW_UPDATE 0x00000004
#define SPI_HOST_INT_UPDATE 0x10000000
/* clear to send */
#define SPI_HOST_INT_CTS 0x00004000
/* data ready */
#define SPI_HOST_INT_DR 0x00008000
#define SPI_HOST_INTS_DEFAULT \
(SPI_HOST_INT_READY | SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE)
#define TARGET_BOOT_SLEEP 50
/* The firmware buffer is divided into three areas:
*
* o config area (for control commands)
* o tx buffer
* o rx buffer
*/
#define FIRMWARE_BUFFER_START 0x20200
#define FIRMWARE_BUFFER_END 0x27c60
#define FIRMWARE_BUFFER_LEN (FIRMWARE_BUFFER_END - FIRMWARE_BUFFER_START)
#define FIRMWARE_MTU 3240
#define FIRMWARE_CONFIG_PAYLOAD_LEN 1024
#define FIRMWARE_CONFIG_START FIRMWARE_BUFFER_START
#define FIRMWARE_CONFIG_LEN (sizeof(struct s_lm_control) + \
FIRMWARE_CONFIG_PAYLOAD_LEN)
#define FIRMWARE_CONFIG_END (FIRMWARE_CONFIG_START + FIRMWARE_CONFIG_LEN - 1)
#define FIRMWARE_RXBUFFER_LEN (5 * FIRMWARE_MTU + 1024)
#define FIRMWARE_RXBUFFER_START (FIRMWARE_BUFFER_END - FIRMWARE_RXBUFFER_LEN)
#define FIRMWARE_RXBUFFER_END (FIRMWARE_RXBUFFER_START + \
FIRMWARE_RXBUFFER_LEN - 1)
#define FIRMWARE_TXBUFFER_START (FIRMWARE_BUFFER_START + FIRMWARE_CONFIG_LEN)
#define FIRMWARE_TXBUFFER_LEN (FIRMWARE_BUFFER_LEN - FIRMWARE_CONFIG_LEN - \
FIRMWARE_RXBUFFER_LEN)
#define FIRMWARE_TXBUFFER_END (FIRMWARE_TXBUFFER_START + \
FIRMWARE_TXBUFFER_LEN - 1)
#define FIRMWARE_TXBUFFER_HEADER 100
#define FIRMWARE_TXBUFFER_TRAILER 4
/* FIXME: come up with a proper value */
#define MAX_FRAME_LEN 2500
/* unit is ms */
#define TX_FRAME_LIFETIME 2000
#define TX_TIMEOUT 4000
#define SUPPORTED_CHANNELS 13
/* FIXME */
/* #define CHANNEL_CAL_LEN offsetof(struct s_lmo_scan, bratemask) - \ */
/* offsetof(struct s_lmo_scan, channel) */
#define CHANNEL_CAL_LEN 292
#define CHANNEL_CAL_ARRAY_LEN (SUPPORTED_CHANNELS * CHANNEL_CAL_LEN)
/* FIXME */
/* #define RSSI_CAL_LEN sizeof(struct s_lmo_scan) - \ */
/* offsetof(struct s_lmo_scan, rssical) */
#define RSSI_CAL_LEN 8
#define RSSI_CAL_ARRAY_LEN (SUPPORTED_CHANNELS * RSSI_CAL_LEN)
struct s_dma_regs {
unsigned short cmd;
unsigned short len;
unsigned long addr;
};
struct stlc45xx_ie_tim {
u8 dtim_count;
u8 dtim_period;
u8 bmap_control;
u8 pvbmap[251];
};
struct txbuffer {
/* can be removed when switched to skb queue */
struct list_head tx_list;
struct list_head buffer_list;
int start;
int frame_start;
int end;
struct sk_buff *skb;
u32 handle;
bool status_needed;
int header_len;
/* unit jiffies */
unsigned long lifetime;
};
enum fw_state {
FW_STATE_OFF,
FW_STATE_BOOTING,
FW_STATE_READY,
FW_STATE_RESET,
FW_STATE_RESETTING,
};
struct stlc45xx {
struct ieee80211_hw *hw;
struct spi_device *spi;
struct work_struct work;
struct work_struct work_reset;
struct delayed_work work_tx_timeout;
struct mutex mutex;
struct completion fw_comp;
u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
int channel;
u8 *cal_rssi;
u8 *cal_channels;
enum fw_state fw_state;
spinlock_t tx_lock;
/* protected by tx_lock */
struct list_head txbuffer;
/* protected by tx_lock */
struct list_head tx_pending;
/* protected by tx_lock */
int tx_queue_stopped;
/* protected by mutex */
struct list_head tx_sent;
int tx_frames;
u8 *fw;
int fw_len;
bool psm;
bool associated;
int aid;
bool pspolling;
};
/************************************************************************
* This is the LMAC API interface header file for STLC4560. *
* Copyright (C) 2007 Conexant Systems, Inc. *
* 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, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#ifndef __lmac_h__
#define __lmac_h__
#define LM_TOP_VARIANT 0x0506
#define LM_BOTTOM_VARIANT 0x0506
/*
* LMAC - UMAC interface definition:
*/
#define LM_FLAG_CONTROL 0x8000
#define LM_FLAG_ALIGN 0x4000
#define LM_CTRL_OPSET 0x0001
#define LM_OUT_PROMISC 0x0001
#define LM_OUT_TIMESTAMP 0x0002
#define LM_OUT_SEQNR 0x0004
#define LM_OUT_BURST 0x0010
#define LM_OUT_NOCANCEL 0x0020
#define LM_OUT_CLEARTIM 0x0040
#define LM_OUT_HITCHHIKE 0x0080
#define LM_OUT_COMPRESS 0x0100
#define LM_OUT_CONCAT 0x0200
#define LM_OUT_PCS_ACCEPT 0x0400
#define LM_OUT_WAITEOSP 0x0800
#define LM_ALOFT_SP 0x10
#define LM_ALOFT_CTS 0x20
#define LM_ALOFT_RTS 0x40
#define LM_ALOFT_MASK 0x1f
#define LM_ALOFT_RATE 0x0f
#define LM_IN_FCS_GOOD 0x0001
#define LM_IN_MATCH_MAC 0x0002
#define LM_IN_MCBC 0x0004
#define LM_IN_BEACON 0x0008
#define LM_IN_MATCH_BSS 0x0010
#define LM_IN_BCAST_BSS 0x0020
#define LM_IN_DATA 0x0040
#define LM_IN_TRUNCATED 0x0080
#define LM_IN_TRANSPARENT 0x0200
#define LM_QUEUE_BEACON 0
#define LM_QUEUE_SCAN 1
#define LM_QUEUE_MGT 2
#define LM_QUEUE_MCBC 3
#define LM_QUEUE_DATA 4
#define LM_QUEUE_DATA0 4
#define LM_QUEUE_DATA1 5
#define LM_QUEUE_DATA2 6
#define LM_QUEUE_DATA3 7
#define LM_SETUP_INFRA 0x0001
#define LM_SETUP_IBSS 0x0002
#define LM_SETUP_TRANSPARENT 0x0008
#define LM_SETUP_PROMISCUOUS 0x0010
#define LM_SETUP_HIBERNATE 0x0020
#define LM_SETUP_NOACK 0x0040
#define LM_SETUP_RX_DISABLED 0x0080
#define LM_ANTENNA_0 0
#define LM_ANTENNA_1 1
#define LM_ANTENNA_DIVERSITY 2
#define LM_TX_FAILED 0x0001
#define LM_TX_PSM 0x0002
#define LM_TX_PSM_CANCELLED 0x0004
#define LM_SCAN_EXIT 0x0001
#define LM_SCAN_TRAP 0x0002
#define LM_SCAN_ACTIVE 0x0004
#define LM_SCAN_FILTER 0x0008
#define LM_PSM 0x0001
#define LM_PSM_DTIM 0x0002
#define LM_PSM_MCBC 0x0004
#define LM_PSM_CHECKSUM 0x0008
#define LM_PSM_SKIP_MORE_DATA 0x0010
#define LM_PSM_BEACON_TIMEOUT 0x0020
#define LM_PSM_HFOSLEEP 0x0040
#define LM_PSM_AUTOSWITCH_SLEEP 0x0080
#define LM_PSM_LPIT 0x0100
#define LM_PSM_BF_UCAST_SKIP 0x0200
#define LM_PSM_BF_MCAST_SKIP 0x0400
/* hfosleep */
#define LM_PSM_SLEEP_OPTION_MASK (LM_PSM_AUTOSWITCH_SLEEP | LM_PSM_HFOSLEEP)
#define LM_PSM_SLEEP_OPTION_SHIFT 6
/* hfosleepend */
#define LM_PSM_BF_OPTION_MASK (LM_PSM_BF_MCAST_SKIP | LM_PSM_BF_UCAST_SKIP)
#define LM_PSM_BF_OPTION_SHIFT 9
#define LM_PRIVACC_WEP 0x01
#define LM_PRIVACC_TKIP 0x02
#define LM_PRIVACC_MICHAEL 0x04
#define LM_PRIVACC_CCX_KP 0x08
#define LM_PRIVACC_CCX_MIC 0x10
#define LM_PRIVACC_AES_CCMP 0x20
/* size of s_lm_descr in words */
#define LM_DESCR_SIZE_WORDS 11
#ifndef __ASSEMBLER__
enum {
LM_MODE_CLIENT = 0,
LM_MODE_AP
};
struct s_lm_descr {
uint16_t modes;
uint16_t flags;
uint32_t buffer_start;
uint32_t buffer_end;
uint8_t header;
uint8_t trailer;
uint8_t tx_queues;
uint8_t tx_depth;
uint8_t privacy;
uint8_t rx_keycache;
uint8_t tim_size;
uint8_t pad1;
uint8_t rates[16];
uint32_t link;
uint16_t mtu;
};
struct s_lm_control {
uint16_t flags;
uint16_t length;
uint32_t handle;
uint16_t oid;
uint16_t pad;
/* uint8_t data[]; */
};
enum {
LM_PRIV_NONE = 0,
LM_PRIV_WEP,
LM_PRIV_TKIP,
LM_PRIV_TKIPMICHAEL,
LM_PRIV_CCX_WEPMIC,
LM_PRIV_CCX_KPMIC,
LM_PRIV_CCX_KP,
LM_PRIV_AES_CCMP
};
enum {
LM_DECRYPT_NONE,
LM_DECRYPT_OK,
LM_DECRYPT_NOKEY,
LM_DECRYPT_NOMICHAEL,
LM_DECRYPT_NOCKIPMIC,
LM_DECRYPT_FAIL_WEP,
LM_DECRYPT_FAIL_TKIP,
LM_DECRYPT_FAIL_MICHAEL,
LM_DECRYPT_FAIL_CKIPKP,
LM_DECRYPT_FAIL_CKIPMIC,
LM_DECRYPT_FAIL_AESCCMP
};
struct s_lm_data_out {
uint16_t flags;
uint16_t length;
uint32_t handle;
uint16_t aid;
uint8_t rts_retries;
uint8_t retries;
uint8_t aloft[8];
uint8_t aloft_ctrl;
uint8_t crypt_offset;
uint8_t keytype;
uint8_t keylen;
uint8_t key[16];
uint8_t queue;
uint8_t backlog;
uint16_t durations[4];
uint8_t antenna;
uint8_t cts;
int16_t power;
uint8_t pad[2];
/*uint8_t data[];*/
};
#define LM_RCPI_INVALID (0xff)
struct s_lm_data_in {
uint16_t flags;
uint16_t length;
uint16_t frequency;
uint8_t antenna;
uint8_t rate;
uint8_t rcpi;
uint8_t sq;
uint8_t decrypt;
uint8_t rssi_raw;
uint32_t clock[2];
/*uint8_t data[];*/
};
union u_lm_data {
struct s_lm_data_out out;
struct s_lm_data_in in;
};
enum {
LM_OID_SETUP = 0,
LM_OID_SCAN = 1,
LM_OID_TRAP = 2,
LM_OID_EDCF = 3,
LM_OID_KEYCACHE = 4,
LM_OID_PSM = 6,
LM_OID_TXCANCEL = 7,
LM_OID_TX = 8,
LM_OID_BURST = 9,
LM_OID_STATS = 10,
LM_OID_LED = 13,
LM_OID_TIMER = 15,
LM_OID_NAV = 20,
LM_OID_PCS = 22,
LM_OID_BT_BALANCER = 28,
LM_OID_GROUP_ADDRESS_TABLE = 30,
LM_OID_ARPTABLE = 31,
LM_OID_BT_OPTIONS = 35
};
enum {
LM_FRONTEND_UNKNOWN = 0,
LM_FRONTEND_DUETTE3,
LM_FRONTEND_DUETTE2,
LM_FRONTEND_FRISBEE,
LM_FRONTEND_CROSSBOW,
LM_FRONTEND_LONGBOW
};
#define INVALID_LPF_BANDWIDTH 0xffff
#define INVALID_OSC_START_DELAY 0xffff
struct s_lmo_setup {
uint16_t flags;
uint8_t macaddr[6];
uint8_t bssid[6];
uint8_t antenna;
uint8_t rx_align;
uint32_t rx_buffer;
uint16_t rx_mtu;
uint16_t frontend;
uint16_t timeout;
uint16_t truncate;
uint32_t bratemask;
uint8_t sbss_offset;
uint8_t mcast_window;
uint8_t rx_rssi_threshold;
uint8_t rx_ed_threshold;
uint32_t ref_clock;
uint16_t lpf_bandwidth;
uint16_t osc_start_delay;
};
struct s_lmo_scan {
uint16_t flags;
uint16_t dwell;
uint8_t channel[292];
uint32_t bratemask;
uint8_t aloft[8];
uint8_t rssical[8];
};
enum {
LM_TRAP_SCAN = 0,
LM_TRAP_TIMER,
LM_TRAP_BEACON_TX,
LM_TRAP_FAA_RADIO_ON,
LM_TRAP_FAA_RADIO_OFF,
LM_TRAP_RADAR,
LM_TRAP_NO_BEACON,
LM_TRAP_TBTT,
LM_TRAP_SCO_ENTER,
LM_TRAP_SCO_EXIT
};
struct s_lmo_trap {
uint16_t event;
uint16_t frequency;
};
struct s_lmo_timer {
uint32_t interval;
};
struct s_lmo_nav {
uint32_t period;
};
struct s_lmo_edcf_queue;
struct s_lmo_edcf {
uint8_t flags;
uint8_t slottime;
uint8_t sifs;
uint8_t eofpad;
struct s_lmo_edcf_queue {
uint8_t aifs;
uint8_t pad0;
uint16_t cwmin;
uint16_t cwmax;
uint16_t txop;
} queues[8];
uint8_t mapping[4];
uint16_t maxburst;
uint16_t round_trip_delay;
};
struct s_lmo_keycache {
uint8_t entry;
uint8_t keyid;
uint8_t address[6];
uint8_t pad[2];
uint8_t keytype;
uint8_t keylen;
uint8_t key[24];
};
struct s_lm_interval;
struct s_lmo_psm {
uint16_t flags;
uint16_t aid;
struct s_lm_interval {
uint16_t interval;
uint16_t periods;
} intervals[4];
/* uint16_t pad; */
uint8_t beacon_rcpi_skip_max;
uint8_t rcpi_delta_threshold;
uint8_t nr;
uint8_t exclude[1];
};
#define MC_FILTER_ADDRESS_NUM 4
struct s_lmo_group_address_table {
uint16_t filter_enable;
uint16_t num_address;
uint8_t macaddr_list[MC_FILTER_ADDRESS_NUM][6];
};
struct s_lmo_txcancel {
uint32_t address[1];
};
struct s_lmo_tx {
uint8_t flags;
uint8_t retries;
uint8_t rcpi;
uint8_t sq;
uint16_t seqctrl;
uint8_t antenna;
uint8_t pad;
};
struct s_lmo_burst {
uint8_t flags;
uint8_t queue;
uint8_t backlog;
uint8_t pad;
uint16_t durations[32];
};
struct s_lmo_stats {
uint32_t valid;
uint32_t fcs;
uint32_t abort;
uint32_t phyabort;
uint32_t rts_success;
uint32_t rts_fail;
uint32_t timestamp;
uint32_t time_tx;
uint32_t noisefloor;
uint32_t sample_noise[8];
uint32_t sample_cca;
uint32_t sample_tx;
};
struct s_lmo_led {
uint16_t flags;
uint16_t mask[2];
uint16_t delay/*[2]*/;
};
struct s_lmo_bt_balancer {
uint16_t prio_thresh;
uint16_t acl_thresh;
};
struct s_lmo_arp_table {
uint16_t filter_enable;
uint32_t ipaddr;
};
#endif /* __ASSEMBLER__ */
#endif /* __lmac_h__ */
...@@ -1332,7 +1332,6 @@ device_release_WPADEV(pDevice); ...@@ -1332,7 +1332,6 @@ device_release_WPADEV(pDevice);
free_netdev(pDevice->dev); free_netdev(pDevice->dev);
} }
kfree(pDevice);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_disconnect3.. \n"); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_disconnect3.. \n");
} }
......
config W35UND config W35UND
tristate "IS89C35 WLAN USB driver" tristate "IS89C35 WLAN USB driver"
depends on MAC80211 && WLAN_80211 && USB && EXPERIMENTAL depends on MAC80211 && WLAN && USB && EXPERIMENTAL
default n default n
---help--- ---help---
This is highly experimental driver for Winbond WIFI card. This is highly experimental driver for Winbond WIFI card.
......
config PRISM2_USB config PRISM2_USB
tristate "Prism2.5/3 USB driver" tristate "Prism2.5/3 USB driver"
depends on WLAN_80211 && USB && WIRELESS_EXT depends on WLAN && USB && WIRELESS_EXT
default n default n
---help--- ---help---
This is the wlan-ng prism 2.5/3 USB driver for a wide range of This is the wlan-ng prism 2.5/3 USB driver for a wide range of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment