Commit 247e9cff authored by Sage Ahn's avatar Sage Ahn Committed by Greg Kroah-Hartman

staging: gdm72xx: Add GCT GDM72xx WiMAX driver.

This patch provides the kernel driver for the GDM72xx WiMAX chips
developed by GCT Semiconductor, Inc., which enables mobile WiMAX
connection on the Linux host.
Signed-off-by: default avatarSage Ahn <syahn@gctsemi.com>
Cc: Ben Chan <benchan@chromium.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 93c66ee1
......@@ -130,4 +130,6 @@ source "drivers/staging/ozwpan/Kconfig"
source "drivers/staging/ipack/Kconfig"
source "drivers/staging/gdm72xx/Kconfig"
endif # STAGING
......@@ -57,3 +57,4 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_RAMSTER) += ramster/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
#
# GCT GDM72xx WiMAX driver configuration
#
menuconfig WIMAX_GDM72XX
tristate "GCT GDM72xx WiMAX support"
help
Support for the GCT GDM72xx WiMAX chip
if WIMAX_GDM72XX
config WIMAX_GDM72XX_QOS
bool "Enable QoS support"
default n
config WIMAX_GDM72XX_K_MODE
bool "Enable K mode"
default n
config WIMAX_GDM72XX_WIMAX2
bool "Enable WIMAX2 support"
default n
choice
prompt "Select interface"
config WIMAX_GDM72XX_USB
bool "USB interface"
depends on USB
config WIMAX_GDM72XX_SDIO
bool "SDIO interface"
depends on MMC
endchoice
if WIMAX_GDM72XX_USB
config WIMAX_GDM72XX_USB_PM
bool "Enable power managerment support"
default n
endif # WIMAX_GDM72XX_USB
endif # WIMAX_GDM72XX
obj-$(CONFIG_WIMAX_GDM72XX) := gdmwm.o
gdmwm-y += gdm_wimax.o netlink_k.o
gdmwm-$(CONFIG_WIMAX_GDM72XX_QOS) += gdm_qos.o
gdmwm-$(CONFIG_WIMAX_GDM72XX_SDIO) += gdm_sdio.o sdio_boot.o
gdmwm-$(CONFIG_WIMAX_GDM72XX_USB) += gdm_usb.o usb_boot.o
TODO:
- Replace kernel_thread with kthread in gdm_usb.c
- Replace hard-coded firmware paths with request_firmware in
sdio_boot.c and usb_boot.c
- Clean up coding style to meet kernel standard.
This diff is collapsed.
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#if !defined(GDM_QOS_H_20090403)
#define GDM_QOS_H_20090403
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/list.h>
#define BOOLEAN u8
#define QOS_MAX 16
#define IPTYPEOFSERVICE 0x8000
#define PROTOCOL 0x4000
#define IPMASKEDSRCADDRESS 0x2000
#define IPMASKEDDSTADDRESS 0x1000
#define PROTOCOLSRCPORTRANGE 0x800
#define PROTOCOLDSTPORTRANGE 0x400
#define DSTMACADDR 0x200
#define SRCMACADDR 0x100
#define ETHERTYPE 0x80
#define IEEE802_1DUSERPRIORITY 0x40
#define IEEE802_1QVLANID 0x10
struct gdm_wimax_csr_s {
/* union{
U16 all;
struct _CS_CLASSIFIER_RULE_ENABLE{
IPTypeOfService:1,
Protocol:1,
IPMaskedSrcAddress:1,
IPMaskedDstAddress:1,
ProtocolSrcPortRange:1,
ProtocolDstPortRange:1,
DstMacAddr:1,
SrcMacAddr:1,
Ethertype:1,
IEEE802_1DUserPriority:1,
IEEE802_1QVLANID:1,
Reserved:5;
} fields;
} */
BOOLEAN Enabled;
u32 SFID;
u8 QoSBufCount;
u16 ClassifierRuleEnable;
u8 IPToSLow;
u8 IPToSHigh;
u8 IPToSMask;
u8 Protocol;
u8 IPSrcAddr[16];
u8 IPSrcAddrMask[16];
u8 IPDstAddr[16];
u8 IPDstAddrMask[16];
u16 SrcPortLow;
u16 SrcPortHigh;
u16 DstPortLow;
u16 DstPortHigh;
};
struct qos_entry_s {
struct list_head list;
struct sk_buff *skb;
struct net_device *dev;
};
struct qos_cb_s {
struct list_head qos_list[QOS_MAX];
u32 qos_list_cnt;
u32 qos_null_idx;
struct gdm_wimax_csr_s csr[QOS_MAX];
spinlock_t qos_lock;
u32 qos_limit_size;
};
void gdm_qos_init(void *nic_ptr);
void gdm_qos_release_list(void *nic_ptr);
int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev);
void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size);
#endif
This diff is collapsed.
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __GDM_SDIO_H__
#define __GDM_SDIO_H__
#include <linux/types.h>
#include <linux/time.h>
#define MAX_NR_SDU_BUF 64
struct sdio_tx {
struct list_head list;
struct tx_cxt *tx_cxt;
u8 *buf;
int len;
void (*callback)(void *cb_data);
void *cb_data;
};
struct tx_cxt {
struct list_head free_list;
struct list_head sdu_list;
struct list_head hci_list;
struct timeval sdu_stamp;
u8 *sdu_buf;
spinlock_t lock;
int can_send;
int stop_sdu_tx;
};
struct sdio_rx {
struct list_head list;
struct rx_cxt *rx_cxt;
void (*callback)(void *cb_data, void *data, int len);
void *cb_data;
};
struct rx_cxt {
struct list_head free_list;
struct list_head req_list;
u8 *rx_buf;
spinlock_t lock;
};
struct sdiowm_dev {
struct sdio_func *func;
struct tx_cxt tx;
struct rx_cxt rx;
struct work_struct ws;
};
#endif /* __GDM_SDIO_H__ */
This diff is collapsed.
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __GDM_USB_H__
#define __GDM_USB_H__
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/list.h>
#define B_DIFF_DL_DRV (1<<4)
#define B_DOWNLOAD (1 << 5)
#define MAX_NR_SDU_BUF 64
struct usb_tx {
struct list_head list;
#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
struct list_head p_list;
#endif
struct tx_cxt *tx_cxt;
struct urb *urb;
u8 *buf;
void (*callback)(void *cb_data);
void *cb_data;
};
struct tx_cxt {
struct list_head free_list;
struct list_head sdu_list;
struct list_head hci_list;
#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
struct list_head pending_list;
#endif
spinlock_t lock;
};
struct usb_rx {
struct list_head list;
struct rx_cxt *rx_cxt;
struct urb *urb;
u8 *buf;
void (*callback)(void *cb_data, void *data, int len);
void *cb_data;
};
struct rx_cxt {
struct list_head free_list;
struct list_head used_list;
spinlock_t lock;
};
struct usbwm_dev {
struct usb_device *usbdev;
#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
struct work_struct pm_ws;
struct usb_interface *intf;
#endif
#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
int bw_switch;
struct list_head list;
#endif
struct tx_cxt tx;
struct rx_cxt rx;
int padding;
};
#endif /* __GDM_USB_H__ */
This diff is collapsed.
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __GDM_WIMAX_H__
#define __GDM_WIMAX_H__
#include <linux/netdevice.h>
#include <linux/version.h>
#include <linux/types.h>
#include "wm_ioctl.h"
#if defined(CONFIG_WIMAX_GDM72XX_QOS)
#include "gdm_qos.h"
#endif
#define DRIVER_VERSION "3.2.3"
/*#define ETH_P_IP 0x0800 */
/*#define ETH_P_ARP 0x0806 */
/*#define ETH_P_IPV6 0x86DD */
#define H2L(x) __cpu_to_le16(x)
#define L2H(x) __le16_to_cpu(x)
#define DH2L(x) __cpu_to_le32(x)
#define DL2H(x) __le32_to_cpu(x)
#define H2B(x) __cpu_to_be16(x)
#define B2H(x) __be16_to_cpu(x)
#define DH2B(x) __cpu_to_be32(x)
#define DB2H(x) __be32_to_cpu(x)
struct phy_dev {
void *priv_dev;
struct net_device *netdev;
int (*send_func)(void *priv_dev, void *data, int len,
void (*cb)(void *cb_data), void *cb_data);
int (*rcv_func)(void *priv_dev,
void (*cb)(void *cb_data, void *data, int len),
void *cb_data);
};
struct nic {
struct net_device *netdev;
struct phy_dev *phy_dev;
struct net_device_stats stats;
struct data_s sdk_data[SIOC_DATA_MAX];
#if defined(CONFIG_WIMAX_GDM72XX_QOS)
struct qos_cb_s qos;
#endif
};
#if 0
#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args)
#else
#define dprintk(...)
#endif
/*#define DEBUG_SDU */
#if defined(DEBUG_SDU)
#define DUMP_SDU_ALL (1<<0)
#define DUMP_SDU_ARP (1<<1)
#define DUMP_SDU_IP (1<<2)
#define DUMP_SDU_IP_TCP (1<<8)
#define DUMP_SDU_IP_UDP (1<<9)
#define DUMP_SDU_IP_ICMP (1<<10)
#define DUMP_PACKET (DUMP_SDU_ALL)
#endif
/*#define DEBUG_HCI */
/*#define LOOPBACK_TEST */
extern int register_wimax_device(struct phy_dev *phy_dev);
extern int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev);
extern void unregister_wimax_device(struct phy_dev *phy_dev);
#endif
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef HCI_H_20080801
#define HCI_H_20080801
#define HCI_HEADER_SIZE 4
#define HCI_VALUE_OFFS (HCI_HEADER_SIZE)
#define HCI_MAX_PACKET 2048
#define HCI_MAX_PARAM (HCI_MAX_PACKET-HCI_HEADER_SIZE)
#define HCI_MAX_TLV 32
/* CMD-EVT */
/* Category 0 */
#define WIMAX_RESET 0x0000
#define WIMAX_SET_INFO 0x0001
#define WIMAX_GET_INFO 0x0002
#define WIMAX_GET_INFO_RESULT 0x8003
#define WIMAX_RADIO_OFF 0x0004
#define WIMAX_RADIO_ON 0x0006
#define WIMAX_WIMAX_RESET 0x0007 /* Is this still here */
/* Category 1 */
#define WIMAX_NET_ENTRY 0x0100
#define WIMAX_NET_DISCONN 0x0102
#define WIMAX_ENTER_SLEEP 0x0103
#define WIMAX_EXIT_SLEEP 0x0104
#define WIMAX_ENTER_IDLE 0x0105
#define WIMAX_EXIT_IDLE 0x0106
#define WIMAX_MODE_CHANGE 0x8108
#define WIMAX_HANDOVER 0x8109 /* obsolete */
#define WIMAX_SCAN 0x010d
#define WIMAX_SCAN_COMPLETE 0x810e
#define WIMAX_SCAN_RESULT 0x810f
#define WIMAX_CONNECT 0x0110
#define WIMAX_CONNECT_START 0x8111
#define WIMAX_CONNECT_COMPLETE 0x8112
#define WIMAX_ASSOC_START 0x8113
#define WIMAX_ASSOC_COMPLETE 0x8114
#define WIMAX_DISCONN_IND 0x8115
#define WIMAX_ENTRY_IND 0x8116
#define WIMAX_HO_START 0x8117
#define WIMAX_HO_COMPLETE 0x8118
#define WIMAX_RADIO_STATE_IND 0x8119
#define WIMAX_IP_RENEW_IND 0x811a
#define WIMAX_DISCOVER_NSP 0x011d
#define WIMAX_DISCOVER_NSP_RESULT 0x811e
#define WIMAX_SDU_TX_FLOW 0x8125
/* Category 2 */
#define WIMAX_TX_EAP 0x0200
#define WIMAX_RX_EAP 0x8201
#define WIMAX_TX_SDU 0x0202
#define WIMAX_RX_SDU 0x8203
#define WIMAX_RX_SDU_AGGR 0x8204
#define WIMAX_TX_SDU_AGGR 0x0205
/* Category 3 */
#define WIMAX_DM_CMD 0x030a
#define WIMAX_DM_RSP 0x830b
#define WIMAX_CLI_CMD 0x030c
#define WIMAX_CLI_RSP 0x830d
#define WIMAX_DL_IMAGE 0x0310
#define WIMAX_DL_IMAGE_STATUS 0x8311
#define WIMAX_UL_IMAGE 0x0312
#define WIMAX_UL_IMAGE_RESULT 0x8313
#define WIMAX_UL_IMAGE_STATUS 0x0314
#define WIMAX_EVT_MODEM_REPORT 0x8325
/* Category 0xF */
#define WIMAX_FSM_UPDATE 0x8F01
#define WIMAX_IF_UPDOWN 0x8F02
#define WIMAX_IF_UP 1
#define WIMAX_IF_DOWN 2
/* WIMAX mode */
#define W_NULL 0
#define W_STANDBY 1
#define W_OOZ 2
#define W_AWAKE 3
#define W_IDLE 4
#define W_SLEEP 5
#define W_WAIT 6
#define W_NET_ENTRY_RNG 0x80
#define W_NET_ENTRY_SBC 0x81
#define W_NET_ENTRY_PKM 0x82
#define W_NET_ENTRY_REG 0x83
#define W_NET_ENTRY_DSX 0x84
#define W_NET_ENTRY_RNG_FAIL 0x1100100
#define W_NET_ENTRY_SBC_FAIL 0x1100200
#define W_NET_ENTRY_PKM_FAIL 0x1102000
#define W_NET_ENTRY_REG_FAIL 0x1103000
#define W_NET_ENTRY_DSX_FAIL 0x1104000
/* Scan Type */
#define W_SCAN_ALL_CHANNEL 0
#define W_SCAN_ALL_SUBSCRIPTION 1
#define W_SCAN_SPECIFIED_SUBSCRIPTION 2
/*
* TLV
*
* [31:31] indicates the type is composite.
* [30:16] is the length of the type. 0 length means length is variable.
* [15:0] is the actual type.
*
*/
#define TLV_L(x) (((x) >> 16) & 0xff)
#define TLV_T(x) ((x) & 0xff)
#define TLV_COMPOSITE(x) ((x) >> 31)
/* GENERAL */
#define T_MAC_ADDRESS (0x00 | (6 << 16))
#define T_BSID (0x01 | (6 << 16))
#define T_MSK (0x02 | (64 << 16))
#define T_RSSI_THRSHLD (0x03 | (1 << 16))
#define T_FREQUENCY (0x04 | (4 << 16))
#define T_CONN_CS_TYPE (0x05 | (1 << 16))
#define T_HOST_IP_VER (0x06 | (1 << 16))
#define T_STBY_SCAN_INTERVAL (0x07 | (4 << 16))
#define T_OOZ_SCAN_INTERVAL (0x08 | (4 << 16))
#define T_IMEI (0x09 | (8 << 16))
#define T_PID (0x0a | (12 << 16))
#define T_CAPABILITY (0x1a | (4 << 16))
#define T_RELEASE_NUMBER (0x1b | (4 << 16))
#define T_DRIVER_REVISION (0x1c | (4 << 16))
#define T_FW_REVISION (0x1d | (4 << 16))
#define T_MAC_HW_REVISION (0x1e | (4 << 16))
#define T_PHY_HW_REVISION (0x1f | (4 << 16))
/* HANDOVER */
#define T_SCAN_INTERVAL (0x20 | (1 << 16))
#define T_RSC_RETAIN_TIME (0x2f | (2 << 16))
/* SLEEP */
#define T_TYPE1_ISW (0x40 | (1 << 16))
#define T_SLP_START_TO (0x4a | (2 << 16))
/* IDLE */
#define T_IDLE_MODE_TO (0x50 | (2 << 16))
#define T_IDLE_START_TO (0x54 | (2 << 16))
/* MONITOR */
#define T_RSSI (0x60 | (1 << 16))
#define T_CINR (0x61 | (1 << 16))
#define T_TX_POWER (0x6a | (1 << 16))
#define T_CUR_FREQ (0x7f | (4 << 16))
/* WIMAX */
#define T_MAX_SUBSCRIPTION (0xa1 | (1 << 16))
#define T_MAX_SF (0xa2 | (1 << 16))
#define T_PHY_TYPE (0xa3 | (1 << 16))
#define T_PKM (0xa4 | (1 << 16))
#define T_AUTH_POLICY (0xa5 | (1 << 16))
#define T_CS_TYPE (0xa6 | (2 << 16))
#define T_VENDOR_NAME (0xa7 | (0 << 16))
#define T_MOD_NAME (0xa8 | (0 << 16))
#define T_PACKET_FILTER (0xa9 | (1 << 16))
#define T_NSP_CHANGE_COUNT (0xaa | (4 << 16))
#define T_RADIO_STATE (0xab | (1 << 16))
#define T_URI_CONTACT_TYPE (0xac | (1 << 16))
#define T_URI_TEXT (0xad | (0 << 16))
#define T_URI (0xae | (0 << 16))
#define T_ENABLE_AUTH (0xaf | (1 << 16))
#define T_TIMEOUT (0xb0 | (2 << 16))
#define T_RUN_MODE (0xb1 | (1 << 16))
#define T_OMADMT_VER (0xb2 | (4 << 16))
/* This is measured in seconds from 00:00:00 GMT January 1, 1970. */
#define T_RTC_TIME (0xb3 | (4 << 16))
#define T_CERT_STATUS (0xb4 | (4 << 16))
#define T_CERT_MASK (0xb5 | (4 << 16))
#define T_EMSK (0xb6 | (64 << 16))
/* Subscription TLV */
#define T_SUBSCRIPTION_LIST (0xd1 | (0 << 16) | (1 << 31))
#define T_H_NSPID (0xd2 | (3 << 16))
#define T_NSP_NAME (0xd3 | (0 << 16))
#define T_SUBSCRIPTION_NAME (0xd4 | (0 << 16))
#define T_SUBSCRIPTION_FLAG (0xd5 | (2 << 16))
#define T_V_NSPID (0xd6 | (3 << 16))
#define T_NAP_ID (0xd7 | (3 << 16))
#define T_PREAMBLES (0xd8 | (15 << 16))
#define T_BW (0xd9 | (4 << 16))
#define T_FFTSIZE (0xda | (4 << 16))
#define T_DUPLEX_MODE (0xdb | (4 << 16))
struct hci_s {
unsigned short cmd_evt;
unsigned short length;
unsigned char data[0];
} __packed;
#endif
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
#include <linux/netlink.h>
#include <asm/byteorder.h>
#include <net/sock.h>
#if !defined(NLMSG_HDRLEN)
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#endif
#define ND_MAX_GROUP 30
#define ND_IFINDEX_LEN sizeof(int)
#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
#define ND_NLMSG_DATA(nlh) \
((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
#define ND_MAX_MSG_LEN 8096
#if defined(DEFINE_MUTEX)
static DEFINE_MUTEX(netlink_mutex);
#else
static struct semaphore netlink_mutex;
#define mutex_lock(x) down(x)
#define mutex_unlock(x) up(x)
#endif
static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
static void netlink_rcv_cb(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
struct net_device *dev;
u32 mlen;
void *msg;
int ifindex;
if (skb->len >= NLMSG_SPACE(0)) {
nlh = (struct nlmsghdr *)skb->data;
if (skb->len < nlh->nlmsg_len ||
nlh->nlmsg_len > ND_MAX_MSG_LEN) {
printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len,
nlh->nlmsg_len);
return;
}
memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
msg = ND_NLMSG_DATA(nlh);
mlen = ND_NLMSG_R_LEN(nlh);
if (rcv_cb) {
dev = dev_get_by_index(&init_net, ifindex);
if (dev) {
rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
dev_put(dev);
} else
printk(KERN_ERR "dev_get_by_index(%d) "
"is not found.\n", ifindex);
} else
printk(KERN_ERR "Unregistered Callback\n");
}
}
static void netlink_rcv(struct sk_buff *skb)
{
mutex_lock(&netlink_mutex);
netlink_rcv_cb(skb);
mutex_unlock(&netlink_mutex);
}
struct sock *netlink_init(int unit, void (*cb)(struct net_device *dev, u16 type,
void *msg, int len))
{
struct sock *sock;
#if !defined(DEFINE_MUTEX)
init_MUTEX(&netlink_mutex);
#endif
sock = netlink_kernel_create(&init_net, unit, 0, netlink_rcv, NULL,
THIS_MODULE);
if (sock)
rcv_cb = cb;
return sock;
}
void netlink_exit(struct sock *sock)
{
sock_release(sock->sk_socket);
}
int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
{
static u32 seq;
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
int ret = 0;
if (group > ND_MAX_GROUP) {
printk(KERN_ERR "Group %d is invalied.\n", group);
printk(KERN_ERR "Valid group is 0 ~ %d.\n", ND_MAX_GROUP);
return -EINVAL;
}
skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "netlink_broadcast ret=%d\n", ret);
return -ENOMEM;
}
seq++;
nlh = NLMSG_PUT(skb, 0, seq, type, len);
memcpy(NLMSG_DATA(nlh), msg, len);
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
if (!ret)
return len;
else {
if (ret != -ESRCH) {
printk(KERN_ERR "netlink_broadcast g=%d, t=%d, l=%d, r=%d\n",
group, type, len, ret);
}
ret = 0;
}
nlmsg_failure:
return ret;
}
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#if !defined(NETLINK_H_20081202)
#define NETLINK_H_20081202
#include <linux/netdevice.h>
#include <net/sock.h>
struct sock *netlink_init(int unit,
void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
void netlink_exit(struct sock *sock);
int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
#endif
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include "gdm_sdio.h"
#define TYPE_A_HEADER_SIZE 4
#define TYPE_A_LOOKAHEAD_SIZE 16
#define YMEM0_SIZE 0x8000 /* 32kbytes */
#define DOWNLOAD_SIZE (YMEM0_SIZE - TYPE_A_HEADER_SIZE)
#define KRN_PATH "/lib/firmware/gdm72xx/gdmskrn.bin"
#define RFS_PATH "/lib/firmware/gdm72xx/gdmsrfs.bin"
static u8 *tx_buf;
static int ack_ready(struct sdio_func *func)
{
unsigned long start = jiffies;
u8 val;
int ret;
while ((jiffies - start) < HZ) {
val = sdio_readb(func, 0x13, &ret);
if (val & 0x01)
return 1;
schedule();
}
return 0;
}
static int download_image(struct sdio_func *func, char *img_name)
{
int ret = 0, len, size, pno;
struct file *filp = NULL;
struct inode *inode = NULL;
u8 *buf = tx_buf;
loff_t pos = 0;
filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
if (IS_ERR(filp)) {
printk(KERN_ERR "Can't find %s.\n", img_name);
return -ENOENT;
}
if (filp->f_dentry)
inode = filp->f_dentry->d_inode;
if (!inode || !S_ISREG(inode->i_mode)) {
printk(KERN_ERR "Invalid file type: %s\n", img_name);
ret = -EINVAL;
goto out;
}
size = i_size_read(inode->i_mapping->host);
if (size <= 0) {
printk(KERN_ERR "Unable to find file size: %s\n", img_name);
ret = size;
goto out;
}
pno = 0;
while ((len = filp->f_op->read(filp, buf + TYPE_A_HEADER_SIZE,
DOWNLOAD_SIZE, &pos))) {
if (len < 0) {
ret = -1;
goto out;
}
buf[0] = len & 0xff;
buf[1] = (len >> 8) & 0xff;
buf[2] = (len >> 16) & 0xff;
if (pos >= size) /* The last packet */
buf[3] = 2;
else
buf[3] = 0;
ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE);
if (ret < 0) {
printk(KERN_ERR "gdmwm: send image error: "
"packet number = %d ret = %d\n", pno, ret);
goto out;
}
if (buf[3] == 2) /* The last packet */
break;
if (!ack_ready(func)) {
ret = -EIO;
printk(KERN_ERR "gdmwm: Ack is not ready.\n");
goto out;
}
ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE);
if (ret < 0) {
printk(KERN_ERR "gdmwm: receive ack error: "
"packet number = %d ret = %d\n", pno, ret);
goto out;
}
sdio_writeb(func, 0x01, 0x13, &ret);
sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */
pno++;
}
out:
filp_close(filp, current->files);
return ret;
}
int sdio_boot(struct sdio_func *func)
{
static mm_segment_t fs;
int ret;
tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL);
if (tx_buf == NULL) {
printk(KERN_ERR "Error: kmalloc: %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
fs = get_fs();
set_fs(get_ds());
ret = download_image(func, KRN_PATH);
if (ret)
goto restore_fs;
printk(KERN_INFO "GCT: Kernel download success.\n");
ret = download_image(func, RFS_PATH);
if (ret)
goto restore_fs;
printk(KERN_INFO "GCT: Filesystem download success.\n");
restore_fs:
set_fs(fs);
kfree(tx_buf);
return ret;
}
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __SDIO_BOOT_H__
#define __SDIO_BOOT_H__
struct sdio_func;
extern int sdio_boot(struct sdio_func *func);
#endif /* __SDIO_BOOT_H__ */
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/usb.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
#include "gdm_usb.h"
#include "usb_boot.h"
#define DN_KERNEL_MAGIC_NUMBER 0x10760001
#define DN_ROOTFS_MAGIC_NUMBER 0x10760002
#define DOWNLOAD_SIZE 1024
#define DH2B(x) __cpu_to_be32(x)
#define DL2H(x) __le32_to_cpu(x)
#define MIN(a, b) ((a) > (b) ? (b) : (a))
#define MAX_IMG_CNT 16
#define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin"
#define KERN_PATH "/lib/firmware/gdm72xx/zImage"
#define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2"
struct dn_header {
u32 magic_num;
u32 file_size;
};
struct img_header {
u32 magic_code;
u32 count;
u32 len;
u32 offset[MAX_IMG_CNT];
char hostname[32];
char date[32];
};
struct fw_info {
u32 id;
u32 len;
u32 kernel_len;
u32 rootfs_len;
u32 kernel_offset;
u32 rootfs_offset;
u32 fw_ver;
u32 mac_ver;
char hostname[32];
char userid[16];
char date[32];
char user_desc[128];
};
static void array_le32_to_cpu(u32 *arr, int num)
{
int i;
for (i = 0; i < num; i++, arr++)
*arr = DL2H(*arr);
}
static u8 *tx_buf;
static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
{
int ret;
int actual;
ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
&actual, 1000);
if (ret < 0) {
printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret);
return ret;
}
return 0;
}
static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
{
int ret;
int actual;
ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
&actual, 5000);
if (ret < 0) {
printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n",
ret);
return ret;
}
return 0;
}
static int download_image(struct usb_device *usbdev, struct file *filp,
loff_t *pos, u32 img_len, u32 magic_num)
{
struct dn_header h;
int ret = 0;
u32 size;
int len, readn;
size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
h.magic_num = DH2B(magic_num);
h.file_size = DH2B(size);
ret = gdm_wibro_send(usbdev, &h, sizeof(h));
if (ret < 0)
goto out;
readn = 0;
while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
if (len < 0) {
ret = -1;
goto out;
}
readn += len;
ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
if (ret < 0)
goto out;
if (readn >= img_len)
break;
}
if (readn < img_len) {
printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
"Read = %d Requested = %d\n", readn, img_len);
ret = -EIO;
}
out:
return ret;
}
int usb_boot(struct usb_device *usbdev, u16 pid)
{
int i, ret = 0;
struct file *filp = NULL;
struct inode *inode = NULL;
static mm_segment_t fs;
struct img_header hdr;
struct fw_info fw_info;
loff_t pos = 0;
char *img_name = UIMG_PATH;
int len;
tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
if (tx_buf == NULL) {
printk(KERN_ERR "Error: kmalloc\n");
return -ENOMEM;
}
fs = get_fs();
set_fs(get_ds());
filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
if (IS_ERR(filp)) {
printk(KERN_ERR "Can't find %s.\n", img_name);
set_fs(fs);
ret = -ENOENT;
goto restore_fs;
}
if (filp->f_dentry)
inode = filp->f_dentry->d_inode;
if (!inode || !S_ISREG(inode->i_mode)) {
printk(KERN_ERR "Invalid file type: %s\n", img_name);
ret = -EINVAL;
goto out;
}
len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
if (len != sizeof(hdr)) {
printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
ret = -EIO;
goto out;
}
array_le32_to_cpu((u32 *)&hdr, 19);
#if 0
if (hdr.magic_code != 0x10767fff) {
printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n",
hdr.magic_code);
ret = -EINVAL;
goto out;
}
#endif
if (hdr.count > MAX_IMG_CNT) {
printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count);
ret = -EINVAL;
goto out;
}
for (i = 0; i < hdr.count; i++) {
if (hdr.offset[i] > hdr.len) {
printk(KERN_ERR "gdmwm: Invalid offset. "
"Entry = %d Offset = 0x%08x "
"Image length = 0x%08x\n",
i, hdr.offset[i], hdr.len);
ret = -EINVAL;
goto out;
}
pos = hdr.offset[i];
len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
&pos);
if (len != sizeof(fw_info)) {
printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
ret = -EIO;
goto out;
}
array_le32_to_cpu((u32 *)&fw_info, 8);
#if 0
if ((fw_info.id & 0xfffff000) != 0x10767000) {
printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n",
fw_info.id);
ret = -EIO;
goto out;
}
#endif
if ((fw_info.id & 0xffff) != pid)
continue;
pos = hdr.offset[i] + fw_info.kernel_offset;
ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
DN_KERNEL_MAGIC_NUMBER);
if (ret < 0)
goto out;
printk(KERN_INFO "GCT: Kernel download success.\n");
pos = hdr.offset[i] + fw_info.rootfs_offset;
ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
DN_ROOTFS_MAGIC_NUMBER);
if (ret < 0)
goto out;
printk(KERN_INFO "GCT: Filesystem download success.\n");
break;
}
if (i == hdr.count) {
printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid);
ret = -EINVAL;
}
out:
filp_close(filp, current->files);
restore_fs:
set_fs(fs);
kfree(tx_buf);
return ret;
}
/*#define GDM7205_PADDING 256 */
#define DOWNLOAD_CHUCK 2048
#define KERNEL_TYPE_STRING "linux"
#define FS_TYPE_STRING "rootfs"
static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
{
int ack;
int ret = -1;
if (send_zlp) {
/*Send ZLP*/
ret = gdm_wibro_send(usbdev, NULL, 0);
if (ret < 0)
goto out;
}
/*Wait for ACK*/
ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
if (ret < 0)
goto out;
out:
return ret;
}
static int em_download_image(struct usb_device *usbdev, char *path,
char *type_string)
{
struct file *filp;
struct inode *inode;
static mm_segment_t fs;
char *buf = NULL;
loff_t pos = 0;
int ret = 0;
int len, readn = 0;
#if defined(GDM7205_PADDING)
const int pad_size = GDM7205_PADDING;
#else
const int pad_size = 0;
#endif
fs = get_fs();
set_fs(get_ds());
filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
if (IS_ERR(filp)) {
printk(KERN_ERR "Can't find %s.\n", path);
set_fs(fs);
ret = -ENOENT;
goto restore_fs;
}
if (filp->f_dentry) {
inode = filp->f_dentry->d_inode;
if (!inode || !S_ISREG(inode->i_mode)) {
printk(KERN_ERR "Invalid file type: %s\n", path);
ret = -EINVAL;
goto out;
}
}
buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
if (buf == NULL) {
printk(KERN_ERR "Error: kmalloc\n");
return -ENOMEM;
}
strcpy(buf+pad_size, type_string);
ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
if (ret < 0)
goto out;
while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
&pos))) {
if (len < 0) {
ret = -1;
goto out;
}
readn += len;
ret = gdm_wibro_send(usbdev, buf, len+pad_size);
if (ret < 0)
goto out;
ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
if (ret < 0)
goto out;
}
ret = em_wait_ack(usbdev, 1);
if (ret < 0)
goto out;
out:
filp_close(filp, current->files);
restore_fs:
set_fs(fs);
kfree(buf);
return ret;
}
static int em_fw_reset(struct usb_device *usbdev)
{
int ret;
/*Send ZLP*/
ret = gdm_wibro_send(usbdev, NULL, 0);
return ret;
}
int usb_emergency(struct usb_device *usbdev)
{
int ret;
ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
if (ret < 0)
goto out;
printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
if (ret < 0)
goto out;
printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
ret = em_fw_reset(usbdev);
out:
return ret;
}
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __USB_BOOT_H__
#define __USB_BOOT_H__
struct usb_device;
extern int usb_boot(struct usb_device *usbdev, u16 pid);
extern int usb_emergency(struct usb_device *usbdev);
#endif /* __USB_BOOT_H__ */
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#ifndef __USB_IDS_H__
#define __USB_IDS_H__
/*You can replace vendor-ID as yours.*/
#define GCT_VID 0x1076
/*You can replace product-ID as yours.*/
#define GCT_PID1 0x7e00
#define GCT_PID2 0x7f00
#define USB_DEVICE_ID_MATCH_DEVICE_INTERFACE \
(USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS)
#define USB_DEVICE_INTF(vend, prod, intf) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_INTERFACE, \
.idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (intf)
#define EMERGENCY_PID 0x720f
#define BL_PID_MASK 0xffc0
#define USB_DEVICE_BOOTLOADER(vid, pid) \
{USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD)}, \
{USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD|B_DIFF_DL_DRV)}
#define USB_DEVICE_CDC_DATA(vid, pid) \
{USB_DEVICE_INTF((vid), (pid), USB_CLASS_CDC_DATA)}
static const struct usb_device_id id_table[] = {
USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID1),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x1),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x2),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x3),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x4),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x5),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x6),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x7),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x8),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x9),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xa),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xb),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xc),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xd),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xe),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xf),
USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID2),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x1),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x2),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x3),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x4),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x5),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x6),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x7),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x8),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x9),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xa),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xb),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xc),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xd),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xe),
USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xf),
{USB_DEVICE(GCT_VID, EMERGENCY_PID)},
{ }
};
#endif /* __USB_IDS_H__ */
/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#if !defined(WM_IOCTL_H_20080714)
#define WM_IOCTL_H_20080714
#if !defined(__KERNEL__)
#include <net/if.h>
#endif
#define NETLINK_WIMAX 31
#define SIOCWMIOCTL SIOCDEVPRIVATE
#define SIOCG_DATA 0x8D10
#define SIOCS_DATA 0x8D11
enum {
SIOC_DATA_FSM,
SIOC_DATA_NETLIST,
SIOC_DATA_CONNNSP,
SIOC_DATA_CONNCOMP,
SIOC_DATA_PROFILEID,
SIOC_DATA_END
};
#define SIOC_DATA_MAX 16
/* FSM */
enum {
M_INIT = 0,
M_OPEN_OFF,
M_OPEN_ON,
M_SCAN,
M_CONNECTING,
M_CONNECTED,
M_FSM_END,
C_INIT = 0,
C_CONNSTART,
C_ASSOCSTART,
C_RNG,
C_SBC,
C_AUTH,
C_REG,
C_DSX,
C_ASSOCCOMPLETE,
C_CONNCOMPLETE,
C_FSM_END,
D_INIT = 0,
D_READY,
D_LISTEN,
D_IPACQUISITION,
END_FSM
};
struct fsm_s {
int m_status; /*main status*/
int c_status; /*connection status*/
int d_status; /*oma-dm status*/
};
struct data_s {
int size;
void *buf;
};
struct wm_req_s {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
unsigned short cmd;
unsigned short data_id;
struct data_s data;
/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */
};
#ifndef ifr_name
#define ifr_name ifr_ifrn.ifrn_name
#endif
#endif
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