diff options
author | Lauro Ramos Venancio <lauro.venancio@indt.org.br> | 2008-09-02 19:04:15 -0300 |
---|---|---|
committer | Rodrigo Vivi <rodrigo.vivi@openbossa.org> | 2008-10-23 18:04:37 -0300 |
commit | 94829646c42210d252a64c5133b39d3656f32ee9 (patch) | |
tree | d8f42b5048c75aee635183d1e56b748ced969d8c /packages/mamona/cx3110x-diablo-2.0.15 | |
parent | a3542f265dbbe71c797ae28bdebcf0f179c31db5 (diff) |
Add cx3110x-diablo-2.0.15.
Diffstat (limited to 'packages/mamona/cx3110x-diablo-2.0.15')
4 files changed, 556 insertions, 0 deletions
diff --git a/packages/mamona/cx3110x-diablo-2.0.15/create_sysfs_link_for_wlan0.patch b/packages/mamona/cx3110x-diablo-2.0.15/create_sysfs_link_for_wlan0.patch new file mode 100644 index 0000000000..cf4fa1e96a --- /dev/null +++ b/packages/mamona/cx3110x-diablo-2.0.15/create_sysfs_link_for_wlan0.patch @@ -0,0 +1,11 @@ +--- cx3110x-0.8.1.new/src/sm_drv_spi.c 2008-05-13 10:27:19.000000000 -0300 ++++ cx3110x-0.8.1/src/sm_drv_spi.c 2008-05-12 19:02:16.000000000 -0300 +@@ -1067,6 +1067,8 @@ + goto err_out_4; + } + ++ SET_NETDEV_DEV(dev, &wlan_omap_device.dev); ++ + register_netdev(dev); + + /* Let's fetch the firmware from userspace */ diff --git a/packages/mamona/cx3110x-diablo-2.0.15/cx3110x b/packages/mamona/cx3110x-diablo-2.0.15/cx3110x new file mode 100755 index 0000000000..592c7032ca --- /dev/null +++ b/packages/mamona/cx3110x-diablo-2.0.15/cx3110x @@ -0,0 +1,40 @@ +#!/bin/sh + +MODULE="/lib/modules/`uname -r`/cx3110x.ko" + +swap_module () { + if [ -e $MODULE ]; then + # Removing builtin driver + rmmod cx3110x + # Inserting the new one + insmod $MODULE + # Setting device options (MAC, default country, etc) + if [ -x /mnt/initfs/usr/bin/wlan-cal ]; then + chroot /mnt/initfs /usr/bin/wlan-cal + fi + # Getting up the interface to make the firmware being loaded (stupid, i know) + ifconfig wlan0 up + else + echo "OOPS: $MODULE not found, the switch is not possible" 1>&2 + fi +} + +case "$1" in + start) + swap_module + ;; + stop) + ifconfig $IFACE down + rmmod cx3110x + ;; + force-reload | restart) + swap_module + ;; + *) + echo "Usage: /etc/init.d/cx3110x {start|stop|restart|force-reload}" + exit 1 + ;; +esac + +exit 0 + diff --git a/packages/mamona/cx3110x-diablo-2.0.15/cx3110x.patch b/packages/mamona/cx3110x-diablo-2.0.15/cx3110x.patch new file mode 100644 index 0000000000..b280815efc --- /dev/null +++ b/packages/mamona/cx3110x-diablo-2.0.15/cx3110x.patch @@ -0,0 +1,492 @@ +diff -ru cx3110x-module-src-2.0.14.orig/src/sm_drv_ioctl_umac.c cx3110x-module-src-2.0.14/src/sm_drv_ioctl_umac.c +--- cx3110x-module-src-2.0.14.orig/src/sm_drv_ioctl_umac.c 2007-09-25 13:02:17.000000000 -0300 ++++ cx3110x-module-src-2.0.14/src/sm_drv_ioctl_umac.c 2007-10-09 15:32:30.000000000 -0300 +@@ -88,8 +88,8 @@ + kfree(wrqu.data.pointer); + } + +-void send_wpa_ie_event(struct net_device *dev, char * bss_addr, +- char * wpa_ie, size_t wpa_ie_len, uint32_t event) ++void send_wpa_ie_event(struct net_device *dev, char * wpa_ie, ++ size_t wpa_ie_len, uint32_t event) + { + union iwreq_data wrqu; + uint32_t we_event; +@@ -111,15 +111,12 @@ + return; + } + +- wrqu.data.pointer = kzalloc(ETH_ALEN + 1 + wpa_ie_len, GFP_ATOMIC); ++ wrqu.data.pointer = kzalloc(wpa_ie_len, GFP_ATOMIC); + if (!wrqu.data.pointer) + return; + +- memcpy(wrqu.data.pointer, bss_addr, ETH_ALEN); +- *((char *)(wrqu.data.pointer + ETH_ALEN)) = ':'; +- memcpy(wrqu.data.pointer + ETH_ALEN + 1, wpa_ie, wpa_ie_len); +- +- wrqu.data.length = ETH_ALEN + 1 + wpa_ie_len; ++ memcpy(wrqu.data.pointer, wpa_ie, wpa_ie_len); ++ wrqu.data.length = wpa_ie_len; + + wireless_send_event(dev, we_event, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +@@ -478,7 +475,7 @@ + if ((lp->link_state == DOT11_STATE_ASSOCING + || lp->link_state == DOT11_STATE_ASSOC) + && event) +- send_wpa_ie_event(dev, bssid, wpa_ie, wpa_ie_len, event); ++ send_wpa_ie_event(dev, wpa_ie, wpa_ie_len, event); + + /* try to use existing entry */ + list_for_each_entry_safe(bss, safe, &lp->bss_wpa_list, list) { +@@ -1928,6 +1925,435 @@ + (void *)&key, sizeof(struct obj_stakey)); + } + ++static int sm_drv_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_param *param = &wrqu->param; ++ u32 authen = 0, dot1x = 0; ++ u32 exunencrypt = 0, privinvoked = 0, wpa = 0; ++ u32 old_wpa; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "SET AUTH\n"); ++ ++ /* first get the flags */ ++ down(&priv->wpa_sem); ++ wpa = old_wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ ++ if (ret < 0) ++ goto out; ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ /* Do the same thing as IW_AUTH_WPA_VERSION */ ++ if (param->value) { ++ wpa = DOT11_PRIV_INV_TKIP; ++ privinvoked = 1; /* For privacy invoked */ ++ exunencrypt = 1; /* Filter out all unencrypted frames */ ++ dot1x = 0x01; /* To enable eap filter */ ++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ ++ } else { ++ wpa = DOT11_PRIV_INV_NONE; ++ privinvoked = 0; ++ exunencrypt = 0; /* Do not filter un-encrypted data */ ++ dot1x = 0; ++ } ++ break; ++ ++ case IW_AUTH_WPA_VERSION: ++ if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { ++ wpa = DOT11_PRIV_INV_NONE; ++ privinvoked = 0; ++ exunencrypt = 0; /* Do not filter un-encrypted data */ ++ dot1x = 0; ++ } else { ++ if (param->value & IW_AUTH_WPA_VERSION_WPA) ++ wpa = DOT11_PRIV_INV_TKIP; ++ else if (param->value & IW_AUTH_WPA_VERSION_WPA2) ++ wpa = DOT11_PRIV_INV_AES_CCMP; ++ privinvoked = 1; /* For privacy invoked */ ++ exunencrypt = 1; /* Filter out all unencrypted frames */ ++ dot1x = 0x01; /* To enable eap filter */ ++ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ ++ } ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL; ++ * turn off dot1x when allowing receipt of unencrypted EAPOL ++ * frames, turn on dot1x when receipt should be disallowed ++ */ ++ dot1x = param->value ? 0 : 0x01; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ privinvoked = param->value ? 1 : 0; ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ exunencrypt = param->value ? 1 : 0; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) { ++ /* Only WEP uses _SK and _BOTH */ ++ if (wpa > 0) { ++ ret = -EINVAL; ++ goto out; ++ } ++ authen = DOT11_AUTH_SK; ++ } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { ++ authen = DOT11_AUTH_OS; ++ } else { ++ ret = -EINVAL; ++ goto out; ++ } ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ /* Set all the values */ ++ down(&priv->wpa_sem); ++ priv->wpa = wpa; ++ up(&priv->wpa_sem); ++ ++ sm_drv_oid_set(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ ++ out: ++ return ret; ++} ++ ++static int sm_drv_get_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_param *param = &wrqu->param; ++ u32 authen = 0, dot1x = 0; ++ u32 exunencrypt = 0, privinvoked = 0, wpa = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "GET AUTH\n"); ++ ++ /* first get the flags */ ++ down(&priv->wpa_sem); ++ wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * wpa_supplicant will control these internally ++ */ ++ ret = -EOPNOTSUPP; ++ break; ++ ++ case IW_AUTH_WPA_VERSION: ++ switch (wpa) { ++ case DOT11_PRIV_INV_TKIP: ++ param->value = IW_AUTH_WPA_VERSION_WPA; ++ break; ++ case DOT11_PRIV_INV_AES_CCMP: ++ param->value = IW_AUTH_WPA_VERSION_WPA2; ++ break; ++ default: ++ param->value = IW_AUTH_WPA_VERSION_DISABLED; ++ break; ++ } ++ break; ++ ++ case IW_AUTH_DROP_UNENCRYPTED: ++ ret = sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = exunencrypt > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ if (ret >= 0) { ++ switch (authen) { ++ case DOT11_AUTH_OS: ++ param->value = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case DOT11_AUTH_BOTH: ++ case DOT11_AUTH_SK: ++ param->value = IW_AUTH_ALG_SHARED_KEY; ++ case DOT11_AUTH_NONE: ++ default: ++ param->value = 0; ++ break; ++ } ++ } ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = wpa > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ ret = sm_drv_oid_get(dev, DOT11_OID_DOT1XENABLE, ++ (void *)&dot1x, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = dot1x > 0 ? 1 : 0; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ ret = sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&privinvoked, sizeof(uint32_t)); ++ if (ret >= 0) ++ param->value = privinvoked > 0 ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ return ret; ++} ++ ++#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ ++#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ ++#define KEY_SIZE_TKIP 32 /* TKIP keys */ ++ ++static int sm_drv_set_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, alg = ext->alg, set_key = 1; ++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "SET ENCODEEXT\n"); ++ ++ /* Determine and validate the key index */ ++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if (idx) { ++ if (idx < 0 || idx > 3) ++ return -EINVAL; ++ } else { ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ alg = IW_ENCODE_ALG_NONE; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ /* Only set transmit key index here, actual ++ * key is set below if needed. ++ */ ++ ret = sm_drv_oid_set(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ set_key = ext->key_len > 0 ? 1 : 0; ++ } ++ ++ if (set_key) { ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ break; ++ case IW_ENCODE_ALG_WEP: { ++ struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; ++ memset(key.key, 0, sizeof(key.key)); ++ if (ext->key_len > KEY_SIZE_WEP104) { ++ ret = -EINVAL; ++ goto out; ++ } ++ if (ext->key_len > KEY_SIZE_WEP40) ++ key.length = KEY_SIZE_WEP104; ++ else ++ key.length = KEY_SIZE_WEP40; ++ memcpy(key.key, ext->key, ext->key_len); ++ ret = sm_drv_oid_set(dev, DOT11_OID_DEFKEYID + idx + 1, ++ (void *)&key, ++ sizeof(struct obj_key)); ++ break; ++ } ++ case IW_ENCODE_ALG_TKIP: ++ case IW_ENCODE_ALG_CCMP: { ++ struct obj_stakey key; ++ memset(key.key, 0, sizeof(key.key)); ++ if (alg == IW_ENCODE_ALG_TKIP) ++ key.type = DOT11_PRIV_TKIP; ++ else ++ key.type = DOT11_PRIV_AES_CCMP; ++ memcpy(key.address, ext->addr.sa_data, ETH_ALEN); ++ key.length = ext->key_len; ++ key.keyid = idx; ++ key.ext = 0; ++ memcpy(key.key, ext->key, ext->key_len); ++ ret = sm_drv_oid_set(dev, DOT11_OID_STAKEY, ++ (void *)&key, ++ sizeof(struct obj_stakey)); ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ if (ret < 0) ++ goto out; ++ ++ } ++ ++ /* Read the flags */ ++ if (encoding->flags & IW_ENCODE_DISABLED) { ++ /* Encoding disabled, ++ * authen = DOT11_AUTH_OS; ++ * invoke = 0; ++ * exunencrypt = 0; */ ++ } ++ if (encoding->flags & IW_ENCODE_OPEN) { ++ /* Encode but accept non-encoded packets. No auth */ ++ invoke = 1; ++ } ++ if (encoding->flags & IW_ENCODE_RESTRICTED) { ++ /* Refuse non-encoded packets. Auth */ ++ authen = DOT11_AUTH_BOTH; ++ invoke = 1; ++ exunencrypt = 1; ++ } ++ ++ /* do the change if requested */ ++ if (encoding->flags & IW_ENCODE_MODE) { ++ sm_drv_oid_set(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&invoke, sizeof(uint32_t)); ++ sm_drv_oid_set(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ } ++ ++ out: ++ return ret; ++} ++ ++ ++static int sm_drv_get_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ struct net_local *priv = netdev_priv(dev); ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; ++ int ret = 0; ++ ++ DEBUG(DBG_IOCTL, "GET ENCODEEXT\n"); ++ ++ /* first get the flags */ ++ ret = sm_drv_oid_get(dev, DOT11_OID_AUTHENABLE, ++ (void *)&authen, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_PRIVACYINVOKED, ++ (void *)&invoke, sizeof(uint32_t)); ++ ret |= sm_drv_oid_get(dev, DOT11_OID_EXUNENCRYPTED, ++ (void *)&exunencrypt, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if (idx) { ++ if (idx < 0 || idx > 3) ++ return -EINVAL; ++ } else { ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID, ++ (void *)&idx, sizeof(uint32_t)); ++ if (ret < 0) ++ goto out; ++ } ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ switch (authen) { ++ case DOT11_AUTH_BOTH: ++ case DOT11_AUTH_SK: ++ wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; ++ case DOT11_AUTH_OS: ++ default: ++ wrqu->encoding.flags |= IW_ENCODE_OPEN; ++ break; ++ } ++ ++ down(&priv->wpa_sem); ++ wpa = priv->wpa; ++ up(&priv->wpa_sem); ++ ++ if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { ++ /* No encryption */ ++ ext->alg = IW_ENCODE_ALG_NONE; ++ ext->key_len = 0; ++ wrqu->encoding.flags |= IW_ENCODE_DISABLED; ++ } else { ++ struct obj_key *key; ++ ++ ret = sm_drv_oid_get(dev, DOT11_OID_DEFKEYID + idx + 1, ++ (void *)&key, sizeof(struct obj_key)); ++ if (ret < 0) ++ goto out; ++ if (max_key_len < key->length) { ++ ret = -E2BIG; ++ goto out; ++ } ++ memcpy(ext->key, key->key, key->length); ++ ext->key_len = key->length; ++ ++ switch (key->type) { ++ case DOT11_PRIV_TKIP: ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ break; ++ case DOT11_PRIV_AES_CCMP: ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ break; ++ default: ++ case DOT11_PRIV_WEP: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ break; ++ } ++ wrqu->encoding.flags |= IW_ENCODE_ENABLED; ++ } ++ ++ out: ++ return ret; ++} + + /* Private handlers */ + +@@ -2473,10 +2899,10 @@ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) sm_drv_set_genie, /* SIOCSIWGENIE*/ + (iw_handler) NULL, /* SIOCGIWGENIE */ +- (iw_handler) NULL, /* SIOCSIWAUTH */ +- (iw_handler) NULL, /* SIOCGIWAUTH */ +- (iw_handler) NULL, /* SIOCSIWENCODEEXT */ +- (iw_handler) NULL, /* SIOCGIWENCODEEXT */ ++ (iw_handler) sm_drv_set_auth, /* SIOCSIWAUTH */ ++ (iw_handler) sm_drv_get_auth, /* SIOCGIWAUTH */ ++ (iw_handler) sm_drv_set_encodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) sm_drv_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) sm_drv_set_pmk, /* SIOCSIWPMKSA */ + }; diff --git a/packages/mamona/cx3110x-diablo-2.0.15/fix_old_include.patch b/packages/mamona/cx3110x-diablo-2.0.15/fix_old_include.patch new file mode 100644 index 0000000000..61549fdaff --- /dev/null +++ b/packages/mamona/cx3110x-diablo-2.0.15/fix_old_include.patch @@ -0,0 +1,13 @@ +Index: cx3110x-module-src-2.0.15/src/sm_drv_spi.c +=================================================================== +--- cx3110x-module-src-2.0.15.orig/src/sm_drv_spi.c 2008-08-06 19:55:37.000000000 -0300 ++++ cx3110x-module-src-2.0.15/src/sm_drv_spi.c 2008-08-06 19:56:05.000000000 -0300 +@@ -36,7 +36,7 @@ + #include <linux/platform_device.h> + #include <linux/string.h> + #include <linux/firmware.h> +-#include <linux/config.h> ++#include <linux/autoconf.h> + #if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) + #error No Firmware Loading configured in the kernel ! + #endif |