diff options
author | Dorian Snyder <dastin1015@gmail.com> | 2013-06-12 02:24:45 -0700 |
---|---|---|
committer | Dorian Snyder <dastin1015@gmail.com> | 2013-06-20 00:06:04 -0700 |
commit | 4b2308ce699b9c599dd6e6acf57ac11f483381d9 (patch) | |
tree | 4c31179b06d094887b1c8ca70264cf8f184a5981 /drivers/net | |
parent | 855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (diff) | |
download | kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.zip kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.gz kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.bz2 |
d710: initial support for the Epic 4G Touch (SPH-D710)
Change-Id: Iafbd9fb45253b02d539ac0ba114f57b3bf9eeed4
Diffstat (limited to 'drivers/net')
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/Kconfig | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/Makefile | 0 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/buffer.h | 75 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/control.c | 264 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/ctl_types.h | 91 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/download.c | 227 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/download.h | 56 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/firmware.c | 25 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/firmware.h | 20 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/hardware.c | 599 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/headers.h | 116 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/hw_types.h | 96 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/receive.c | 301 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/wimax_i2c.c | 167 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/wimax_i2c.h | 1 | ||||
-rwxr-xr-x | drivers/net/wimax_cmc/wimax_plat.h | 36 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/wimax_sdio.c | 108 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/net/wimax_cmc/wimax_sdio.h | 4 |
18 files changed, 2024 insertions, 162 deletions
diff --git a/drivers/net/wimax_cmc/Kconfig b/drivers/net/wimax_cmc/Kconfig index 16efe94..16efe94 100644..100755 --- a/drivers/net/wimax_cmc/Kconfig +++ b/drivers/net/wimax_cmc/Kconfig diff --git a/drivers/net/wimax_cmc/Makefile b/drivers/net/wimax_cmc/Makefile index e49f7fb..e49f7fb 100644..100755 --- a/drivers/net/wimax_cmc/Makefile +++ b/drivers/net/wimax_cmc/Makefile diff --git a/drivers/net/wimax_cmc/buffer.h b/drivers/net/wimax_cmc/buffer.h new file mode 100755 index 0000000..f37d902 --- /dev/null +++ b/drivers/net/wimax_cmc/buffer.h @@ -0,0 +1,75 @@ +/* + * buffer.h + * + * Used q_send for the control and data packet sending, uses the BUFFER_DESCRIPTOR + * q_received used for the control packet receive, data packet sent directly + */ +#ifndef _WIMAX_BUFFER_H +#define _WIMAX_BUFFER_H + +/* structures */ +struct buffer_descriptor { + struct list_head node; /* list node */ + void *buffer; /* allocated buffer: It is used for copying and transfer */ + u_long length; /* current data length */ + u_short type; /* buffer type (used for control buffers) */ +}; + +struct queue_info { + struct list_head head; /* list head */ + spinlock_t lock; /* protection */ +}; + +/****************************************************************************** + * queue_init_list -- Macro which will initialize a queue to NULL. + ******************************************************************************/ +#define queue_init_list(_L) ((_L).next = (_L).prev = NULL) + +/****************************************************************************** + * queue_empty -- Macro which checks to see if a queue is empty. + ******************************************************************************/ +#define queue_empty(_L) (queue_get_head((_L)) == NULL) + +/****************************************************************************** + * queue_get_head -- Macro which returns the head of the queue, but does not + * remove the head from the queue. + ******************************************************************************/ +#define queue_get_head(_L) ((struct list_head *)((_L).next)) + +/****************************************************************************** + * queue_remove_head -- Macro which removes the head of the head of queue. + ******************************************************************************/ +#define queue_remove_head(_L) \ +{ \ + struct list_head *h; \ + if ((h = (struct list_head *)(_L).next)) { /* then fix up our our list to point to next elem */ \ + if (!((_L).next = h->next)) /* rechain list pointer to next link */ \ + /* if the list pointer is null, null out the reverse link */ \ + (_L).prev = NULL; \ + } \ +} + +/****************************************************************************** + * queue_put_tail -- Macro which puts an element at the tail (end) of the queue. + ******************************************************************************/ +#define queue_put_tail(_L,_E) \ +{ \ + if ((_L).prev) { \ + ((struct list_head *)(_L).prev)->next = (struct list_head *)(&(_E)); \ + (_L).prev = (struct list_head *)(&(_E)); \ + } else \ + (_L).next = (_L).prev = (struct list_head *)(&(_E)); \ + (_E).next = NULL; \ +} + +/****************************************************************************** + * queue_pop_head -- Macro which will pop the head off of a queue (list), and + * return it (this differs only from queueremovehead only in the 1st line) + ******************************************************************************/ +#define queue_pop_head(_L) \ +{ \ + (struct list_head *) (_L).next; \ + queue_remove_head(_L); \ +} + +#endif /* _WIMAX_BUFFER_H */ diff --git a/drivers/net/wimax_cmc/control.c b/drivers/net/wimax_cmc/control.c new file mode 100755 index 0000000..b4abd60 --- /dev/null +++ b/drivers/net/wimax_cmc/control.c @@ -0,0 +1,264 @@ +/* + * control.c + * + * send and receive control packet and handle it + */ +#include "headers.h" + +u_int control_init(struct net_adapter *adapter) +{ + queue_init_list(adapter->ctl.q_received.head); + spin_lock_init(&adapter->ctl.q_received.lock); + + queue_init_list(adapter->ctl.apps.process_list); + spin_lock_init(&adapter->ctl.apps.lock); + + adapter->ctl.apps.ready = TRUE; + + return STATUS_SUCCESS; +} + +void control_remove(struct net_adapter *adapter) +{ + struct buffer_descriptor *dsc; + struct process_descriptor *process; + unsigned long flags; + /* Free the received control packets queue */ + while (!queue_empty(adapter->ctl.q_received.head)) { + /* queue is not empty */ + dump_debug("Freeing Control Receive Queue"); + dsc = (struct buffer_descriptor *) + queue_get_head(adapter->ctl.q_received.head); + if (!dsc) { + dump_debug("Fail...node is null"); + continue; + } + queue_remove_head(adapter->ctl.q_received.head); + if (dsc->buffer) + kfree(dsc->buffer); + if (dsc) + kfree(dsc); + } + + /* process list */ + if (adapter->ctl.apps.ready) { + if (!queue_empty(adapter->ctl.apps.process_list)) { + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *)queue_get_head(adapter->ctl.apps.process_list); + spin_lock_irqsave(&adapter->ctl.apps.lock, flags); + while (process != NULL) { + if (process->irp) { + process->irp = FALSE; + wake_up_interruptible(&process->read_wait); + } + process = (struct process_descriptor *)process->node.next; + dump_debug("sangam dbg : waking processes"); + } + spin_unlock_irqrestore(&adapter->ctl.apps.lock, flags); + /* delay for the process release */ + msleep(100); + } + } + adapter->ctl.apps.ready = FALSE; +} + +/* add received packet to pending list */ +static void control_enqueue_buffer(struct net_adapter *adapter, + u_short type, void *buffer, u_long length) +{ + struct buffer_descriptor *dsc; + struct process_descriptor *process; + + /* Queue and wake read only if process exist. */ + process = process_by_type(adapter, type); + if (process) { + dsc = (struct buffer_descriptor *) + kmalloc(sizeof(struct buffer_descriptor), + GFP_ATOMIC); + if (dsc == NULL) { + dump_debug("dsc Memory Alloc Failure *****"); + return; + } + dsc->buffer = kmalloc(length, GFP_ATOMIC); + if (dsc->buffer == NULL) { + kfree(dsc); + dump_debug("dsc->buffer Memory Alloc Failure *****"); + return; + } + + memcpy(dsc->buffer, buffer, length); + /* fill out descriptor */ + dsc->length = length; + dsc->type = type; + /* add to pending list */ + queue_put_tail(adapter->ctl.q_received.head, dsc->node) + + if (process->irp) { + process->irp = FALSE; + wake_up_interruptible(&process->read_wait); + } + } else + dump_debug("Waiting process not found skip the packet"); +} + +/* receive control data */ +void control_recv(struct net_adapter *adapter, void *buffer, u_long length) +{ + struct eth_header *hdr; + + /* dump rx control frame */ + if (adapter->pdata->g_cfg->enable_dump_msg == 1) + dump_buffer("Control Rx", (u_char *)buffer + 12, length - 12); + + /* check halt flag */ + if (adapter->halted) + return; + + hdr = (struct eth_header *)buffer; + + /* not found, add to pending buffers list */ + spin_lock(&adapter->ctl.q_received.lock); + control_enqueue_buffer(adapter, hdr->type, buffer, length); + spin_unlock(&adapter->ctl.q_received.lock); +} + +u_int control_send(struct net_adapter *adapter, void *buffer, u_long length) +{ + if ((length + sizeof(struct hw_packet_header)) >= WIMAX_MAX_TOTAL_SIZE) + return STATUS_RESOURCES; + /* changed from SUCCESS return status */ + + return hw_send_data(adapter, buffer, length, CONTROL_PACKET); + +} + +struct process_descriptor *process_by_id(struct net_adapter *adapter, u_int id) +{ + struct process_descriptor *process; + + if (queue_empty(adapter->ctl.apps.process_list)) { + dump_debug("process_by_id: Empty process list"); + return NULL; + } + + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + while (process != NULL) { + if (process->id == id) /* process found */ + return process; + process = (struct process_descriptor *)process->node.next; + } + dump_debug("process_by_id: process not found"); + + return NULL; +} + +struct process_descriptor *process_by_type(struct net_adapter *adapter, + u_short type) +{ + struct process_descriptor *process; + + if (queue_empty(adapter->ctl.apps.process_list)) { + dump_debug("process_by_type: Empty process list"); + return NULL; + } + + /* first time gethead needed to get the dsc nodes */ + process = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + while (process != NULL) { + if (process->type == type) /* process found */ + return process; + process = (struct process_descriptor *)process->node.next; + } + dump_debug("process_by_type: process not found"); + + return NULL; +} + +void remove_process(struct net_adapter *adapter, u_int id) +{ + struct process_descriptor *curElem; + struct process_descriptor *prevElem = NULL; + + if (queue_empty(adapter->ctl.apps.process_list)) + return; + + /* first time get head needed to get the dsc nodes */ + curElem = (struct process_descriptor *) + queue_get_head(adapter->ctl.apps.process_list); + + for ( ; curElem != NULL; prevElem = curElem, + curElem = (struct process_descriptor *) + curElem->node.next) { + if (curElem->id == id) { /* process found */ + if (prevElem == NULL) { + /* only one node present */ + (adapter->ctl.apps.process_list).next = + (((struct list_head *)curElem)->next); + if (!((adapter->ctl.apps.process_list).next)) { + /*rechain list pointer to next link*/ + dump_debug("sangam dbg first and only process delete"); + (adapter->ctl.apps.process_list).prev = NULL; + } + } else if (((struct list_head *)curElem)->next == + NULL) { + /* last node */ + dump_debug("sangam dbg only last packet"); + ((struct list_head *)prevElem)->next = NULL; + (adapter->ctl.apps.process_list).prev = + (struct list_head *)(prevElem); + } else { + /* middle node */ + dump_debug("sangam dbg middle node"); + ((struct list_head *)prevElem)->next = + ((struct list_head *)curElem)->next; + } + + kfree(curElem); + break; + } + } +} + +/* find buffer by buffer type */ +struct buffer_descriptor *buffer_by_type(struct list_head ListHead, + u_short type) +{ + struct buffer_descriptor *dsc; + + if (queue_empty(ListHead)) + return NULL; + + /* first time gethead needed to get the dsc nodes */ + dsc = (struct buffer_descriptor *)queue_get_head(ListHead); + while (dsc != NULL) { + if (dsc->type == type) /* process found */ + return dsc; + dsc = (struct buffer_descriptor *)dsc->node.next; + } + + return NULL; +} + +void dump_buffer(const char *desc, u_char *buffer, u_int len) +{ + char print_buf[256] = {0}; + char chr[8] = {0}; + int i; + + /* dump packets */ + u_char *b = buffer; + dump_debug("%s (%d) =>", desc, len); + + for (i = 0; i < len; i++) { + sprintf(chr, " %02x", b[i]); + strcat(print_buf, chr); + if (((i + 1) != len) && (i % 16 == 15)) { + dump_debug(print_buf); + memset(print_buf, 0x0, 256); + } + } + dump_debug(print_buf); +} diff --git a/drivers/net/wimax_cmc/ctl_types.h b/drivers/net/wimax_cmc/ctl_types.h new file mode 100755 index 0000000..0c3543e --- /dev/null +++ b/drivers/net/wimax_cmc/ctl_types.h @@ -0,0 +1,91 @@ +/* + * ctl_types.h + * + * Control types and definitions + */ +#ifndef _WIMAX_CTL_TYPES_H +#define _WIMAX_CTL_TYPES_H + +#ifndef FILE_DEVICE_UNKNOWN +#define FILE_DEVICE_UNKNOWN 0x89 +#endif + +/* Macro definition for defining IOCTL */ +#define CTL_CODE( DeviceType, Function, Method, Access ) \ +( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) +/* Define the method codes for how buffers are passed for I/O and FS controls */ +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +/* + Define the access check value for any access + + The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in + ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these + constants *MUST* always be in sync. +*/ +#define FILE_ANY_ACCESS 0 +#define FILE_READ_ACCESS (0x0001) +#define FILE_WRITE_ACCESS (0x0002) + +#define CONTROL_ETH_TYPE_WCM 0x0015 + +#define CONTROL_IOCTL_WRITE_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x820, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_POWER_CTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_MODE_CHANGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x838, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_EEPROM_DOWNLOAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x839, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_SLEEP_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83A, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_WRITE_REV CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83B, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_CHECK_CERT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83C, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define CONTROL_IOCTL_WIMAX_CHECK_CAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x83D, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define MAX_APPLICATION_LEN 50 + +#define ETHERNET_ADDRESS_LENGTH 6 + +/* eth types for control message */ +enum { + ETHERTYPE_HIM = 0x1500, + ETHERTYPE_MC = 0x1501, + ETHERTYPE_DM = 0x1502, + ETHERTYPE_CT = 0x1503, + ETHERTYPE_DL = 0x1504, + ETHERTYPE_VSP = 0x1510, + ETHERTYPE_AUTH = 0x1521 +}; + +/* eth header structure */ +#pragma pack(1) +struct eth_header { + u_char dest[ETHERNET_ADDRESS_LENGTH]; + u_char src[ETHERNET_ADDRESS_LENGTH]; + u_short type; +}; +#pragma pack() + +/* process element managed by control type */ +struct process_descriptor { + struct list_head node; + wait_queue_head_t read_wait; + u_long id; + u_short type; + u_short irp; /* Used for the read thread indication */ +}; + +/* head structure for process element */ +struct ctl_app_descriptor { + struct list_head process_list; /* there could be undefined number of applications */ + spinlock_t lock; + u_char ready; +}; + +struct ctl_info { + struct ctl_app_descriptor apps; /* application device structure */ + struct queue_info q_received; /* pending queue */ +}; + +#endif /* _WIMAX_CTL_TYPES_H */ diff --git a/drivers/net/wimax_cmc/download.c b/drivers/net/wimax_cmc/download.c new file mode 100755 index 0000000..e51b210 --- /dev/null +++ b/drivers/net/wimax_cmc/download.c @@ -0,0 +1,227 @@ +/* + * download.c + * + * Firmware download (host booting) functions and definitions + */ +#include "headers.h" +#include "download.h" +#include "firmware.h" + +#include <linux/vmalloc.h> + +struct image_data g_wimax_image; + +int load_wimax_image(int mode) +{ + struct file *fp; + int read_size = 0; + + if (mode == AUTH_MODE) + fp = klib_fopen(WIMAX_LOADER_PATH, O_RDONLY, 0); /* download mode */ + else + fp = klib_fopen(WIMAX_IMAGE_PATH, O_RDONLY, 0); /* wimax mode */ + + if (fp) { + if (g_wimax_image.data == NULL) { /* check already allocated */ + g_wimax_image.data = (u_char *)vmalloc(MAX_WIMAXFW_SIZE); + + if (!g_wimax_image.data) { + dump_debug("Error: Memory alloc failure"); + klib_fclose(fp); + return STATUS_UNSUCCESSFUL; + } + } + + memset(g_wimax_image.data, 0, MAX_WIMAXFW_SIZE); + read_size = klib_flen_fcopy(g_wimax_image.data, MAX_WIMAXFW_SIZE, fp); + + g_wimax_image.size = read_size; + g_wimax_image.address = CMC732_WIMAX_ADDRESS; + g_wimax_image.offset = 0; + + klib_fclose(fp); + } else { + dump_debug("Error: WiMAX image file open failed"); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} + +void unload_wimax_image(void) +{ + if (g_wimax_image.data != NULL) { + dump_debug("Delete the Image Loaded"); + vfree(g_wimax_image.data); + g_wimax_image.data = NULL; + } +} + +u_char send_cmd_packet(struct net_adapter *adapter, u_short cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct wimax_msg_header *msg_hdr; + u_char tx_buf[CMD_MSG_TOTAL_LENGTH]; + int status = 0; + u_int offset; + u_int size; + + pkt_hdr = (struct hw_packet_header *)tx_buf; + pkt_hdr->id0 = 'W'; + pkt_hdr->id1 = 'C'; + pkt_hdr->length = be16_to_cpu(CMD_MSG_TOTAL_LENGTH); + + offset = sizeof(struct hw_packet_header); + msg_hdr = (struct wimax_msg_header *)(tx_buf + offset); + msg_hdr->type = be16_to_cpu(ETHERTYPE_DL); + msg_hdr->id = be16_to_cpu(cmd_id); + msg_hdr->length = be32_to_cpu(CMD_MSG_LENGTH); + + size = CMD_MSG_TOTAL_LENGTH; + + status = sd_send(adapter, tx_buf, size); + if (status != STATUS_SUCCESS) { + /* crc error or data error - set PCWRT '1' & send current type A packet again */ + dump_debug("hwSdioWrite : crc or data error"); + return status; + } + return status; +} + +u_char send_image_info_packet(struct net_adapter *adapter, u_short cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct wimax_msg_header *msg_hdr; + u_int image_info[4]; + u_char tx_buf[IMAGE_INFO_MSG_TOTAL_LENGTH]; + int status; + u_int offset; + u_int size; + + pkt_hdr = (struct hw_packet_header *)tx_buf; + pkt_hdr->id0 = 'W'; + pkt_hdr->id1 = 'C'; + pkt_hdr->length = be16_to_cpu(IMAGE_INFO_MSG_TOTAL_LENGTH); + + offset = sizeof(struct hw_packet_header); + msg_hdr = (struct wimax_msg_header *)(tx_buf + offset); + msg_hdr->type = be16_to_cpu(ETHERTYPE_DL); + msg_hdr->id = be16_to_cpu(cmd_id); + msg_hdr->length = be32_to_cpu(IMAGE_INFO_MSG_LENGTH); + + image_info[0] = 0; + image_info[1] = be32_to_cpu(g_wimax_image.size); + image_info[2] = be32_to_cpu(g_wimax_image.address); + image_info[3] = 0; + + offset += sizeof(struct wimax_msg_header); + memcpy(&(tx_buf[offset]), image_info, sizeof(image_info)); + + size = IMAGE_INFO_MSG_TOTAL_LENGTH; + status = sd_send(adapter, tx_buf, size); + + if (status != STATUS_SUCCESS) { + /* crc error or data error - set PCWRT '1' & send current type A packet again */ + dump_debug("hwSdioWrite : crc error"); + return status; + } + return status; +} + +u_char send_image_data_packet(struct net_adapter *adapter, u_short cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct image_data_payload *pImageDataPayload; + struct wimax_msg_header *msg_hdr; + u_char *tx_buf = NULL; + int status; + u_int len; + u_int offset; + u_int size; + + tx_buf = (u_char *)kmalloc(MAX_IMAGE_DATA_MSG_LENGTH, GFP_KERNEL); + if (tx_buf == NULL) { + dump_debug("MALLOC FAIL!!"); + return -1; + } + + pkt_hdr = (struct hw_packet_header *)tx_buf; + pkt_hdr->id0 = 'W'; + pkt_hdr->id1 = 'C'; + + offset = sizeof(struct hw_packet_header); + msg_hdr = (struct wimax_msg_header *)(tx_buf + offset); + msg_hdr->type = be16_to_cpu(ETHERTYPE_DL); + msg_hdr->id = be16_to_cpu(cmd_id); + + if (g_wimax_image.offset < (g_wimax_image.size - MAX_IMAGE_DATA_LENGTH)) + len = MAX_IMAGE_DATA_LENGTH; + else + len = g_wimax_image.size - g_wimax_image.offset; + + offset += sizeof(struct wimax_msg_header); + pImageDataPayload = (struct image_data_payload *)(tx_buf + offset); + pImageDataPayload->offset = be32_to_cpu(g_wimax_image.offset); + pImageDataPayload->size = be32_to_cpu(len); + + memcpy(pImageDataPayload->data, g_wimax_image.data + g_wimax_image.offset, len); + + size = len + 8; /* length of Payload offset + length + data */ + pkt_hdr->length = be16_to_cpu(CMD_MSG_TOTAL_LENGTH + size); + msg_hdr->length = be32_to_cpu(size); + + size = CMD_MSG_TOTAL_LENGTH + size; + + status = sd_send(adapter, tx_buf, size); + + if (status != STATUS_SUCCESS) { + /* crc error or data error - set PCWRT '1' & send current type A packet again */ + dump_debug("hwSdioWrite : crc error"); + kfree(tx_buf); + return status; + } + + g_wimax_image.offset += len; + + kfree(tx_buf); + + return status; +} + +/* used only during firmware download */ +u_int sd_send(struct net_adapter *adapter, u_char *buffer, u_int len) +{ + int nRet = 0; + + int nWriteIdx; + + len += (len & 1) ? 1 : 0; + + if (adapter->halted || adapter->removed) { + dump_debug("Halted Already"); + return STATUS_UNSUCCESSFUL; + } + + sdio_claim_host(adapter->func); + hwSdioWriteBankIndex(adapter, &nWriteIdx, &nRet); + + if(nRet || (nWriteIdx < 0) ) + return STATUS_UNSUCCESSFUL; + + sdio_writeb(adapter->func, (nWriteIdx + 1) % 15, SDIO_H2C_WP_REG, NULL); + + nRet = sdio_memcpy_toio(adapter->func, SDIO_TX_BANK_ADDR+(SDIO_BANK_SIZE * nWriteIdx)+4, buffer, len); + + if (nRet < 0) { + dump_debug("sd_send : error in sending packet!! nRet = %d",nRet); + } + + nRet = sdio_memcpy_toio(adapter->func, SDIO_TX_BANK_ADDR + (SDIO_BANK_SIZE * nWriteIdx), &len, 4); + + if (nRet < 0) { + dump_debug("sd_send : error in writing bank length!! nRet = %d",nRet); + } + sdio_release_host(adapter->func); + + return nRet; +} diff --git a/drivers/net/wimax_cmc/download.h b/drivers/net/wimax_cmc/download.h new file mode 100755 index 0000000..d46e6b6 --- /dev/null +++ b/drivers/net/wimax_cmc/download.h @@ -0,0 +1,56 @@ +/* + * download.h + * + * Firmware download (host booting) functions and definitions + */ +#ifndef _WIMAX_DOWNLOAD_H__ +#define _WIMAX_DOWNLOAD_H__ + +#define CMC732_RAM_START 0xC0000000 +#define CMC732_WIMAX_ADDRESS CMC732_RAM_START + +#define CMD_MSG_TOTAL_LENGTH 12 +#define IMAGE_INFO_MSG_TOTAL_LENGTH 28 +#define CMD_MSG_LENGTH 0 +#define IMAGE_INFO_MSG_LENGTH 16 +#define MAX_IMAGE_DATA_LENGTH 3564 +#define MAX_IMAGE_DATA_MSG_LENGTH 4096 + +#define FWDOWNLOAD_TIMEOUT 12000 +#define MAX_WIMAXFW_SIZE 2100000 + +/* used for host boot (firmware download) */ +enum { + MSG_DRIVER_OK_REQ = 0x5010, + MSG_DRIVER_OK_RESP = 0x6010, + MSG_IMAGE_INFO_REQ = 0x3021, + MSG_IMAGE_INFO_RESP = 0x4021, + MSG_IMAGE_DATA_REQ = 0x3022, + MSG_IMAGE_DATA_RESP = 0x4022, + MSG_RUN_REQ = 0x5014, + MSG_RUN_RESP = 0x6014 +}; + +struct image_data { + u_int size; + u_int address; + u_int offset; + struct mutex lock; + u_char *data; +}; + +struct image_data_payload { + u_int offset; + u_int size; + u_char data[MAX_IMAGE_DATA_LENGTH]; +}; + +int load_wimax_image(int mode); +void unload_wimax_image(void); + +u_char send_image_info_packet(struct net_adapter *adapter, u_short cmd_id); +u_char send_image_data_packet(struct net_adapter *adapter, u_short cmd_id); +u_char send_cmd_packet(struct net_adapter *adapter, u_short cmd_id); +u_int sd_send(struct net_adapter *adapter, u_char *buffer, u_int len); + +#endif /* _WIMAX_DOWNLOAD_H__ */ diff --git a/drivers/net/wimax_cmc/firmware.c b/drivers/net/wimax_cmc/firmware.c index d31eb8c..f4b6c9b 100644..100755 --- a/drivers/net/wimax_cmc/firmware.c +++ b/drivers/net/wimax_cmc/firmware.c @@ -5,7 +5,6 @@ * Firmware binary file is on the filesystem, read fild and send it through SDIO */ #include "firmware.h" -#include <linux/wimax/samsung/wimax732.h> #define SEEK_SET 0 #define SEEK_CUR 1 @@ -27,12 +26,8 @@ *************************************************************************/ struct file *klib_fopen( const char *filename, /*!< filename to open */ - /*!< O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, - O_EXCL, O_TRUNC, O_APPEND, O_NONBLOCK, O_SYNC,...*/ - int flags, - /*!< file creation permisstion. S_IRxxx - S_IWxxx S_IXxxx (xxx=USR,GRP,OTH), S_IRWXx(x=U,G,O)*/ - int mode + int flags, /*!< O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_NONBLOCK, O_SYNC, ... */ + int mode /*!< file creation permisstion. S_IRxxx S_IWxxx S_IXxxx (xxx=USR,GRP,OTH), S_IRWXx(x=U,G,O) */ ) { struct file *filp = filp_open(filename, flags, mode); @@ -83,8 +78,7 @@ int klib_fseek( if (pos < 0) pos = 0; - filp->f_pos = pos; - return pos; + return (filp->f_pos = pos); } else return -ENOENT; } @@ -110,17 +104,17 @@ klib_fread( mm_segment_t oldfs; if (filp == NULL) { - printk(KERN_INFO "filp == NULL\n"); + printk(" filp == NULL\n"); return -ENOENT; } if (filp->f_op->read == NULL) { - printk(KERN_INFO "filp->f_op->read == NULL\n"); + printk(" filp->f_op->read == NULL\n"); return -ENOSYS; } if (((filp->f_flags & O_ACCMODE) & O_RDONLY) != 0) { - printk(KERN_INFO "((filp->f_flags & O_ACCMODE) & O_RDONLY) != 0\n"); + printk(" ((filp->f_flags & O_ACCMODE) & O_RDONLY) != 0\n"); return -EACCES; } @@ -214,12 +208,12 @@ int klib_fwrite( mm_segment_t oldfs; if (filp == NULL) { - printk(KERN_INFO "filp == NULL\n"); + printk(" filp == NULL\n"); return -ENOENT; } if (filp->f_op->write == NULL) { - printk(KERN_INFO "filp->f_op->write == NULL\n"); + printk(" filp->f_op->write == NULL\n"); return -ENOSYS; } @@ -238,10 +232,9 @@ void s3c_bat_use_wimax(int onoff) if (!fp) pr_err("open fail"); - if (onoff) + if (onoff) klib_fwrite("1", 1, fp); else klib_fwrite("0", 1, fp); klib_fclose(fp); } -EXPORT_SYMBOL(s3c_bat_use_wimax); diff --git a/drivers/net/wimax_cmc/firmware.h b/drivers/net/wimax_cmc/firmware.h index 862d0d8..9629344 100644..100755 --- a/drivers/net/wimax_cmc/firmware.h +++ b/drivers/net/wimax_cmc/firmware.h @@ -9,7 +9,7 @@ #include <linux/fs.h> #include <linux/file.h> -#include <linux/uaccess.h> +#include <asm/uaccess.h> #define SEEK_SET 0 #define SEEK_CUR 1 @@ -18,12 +18,14 @@ /****************************************************************************** * Function Prototypes ******************************************************************************/ -struct file *klib_fopen(const char *filename, int flags, int mode); -void klib_fclose(struct file *filp); -int klib_fseek(struct file *filp, int offset, int whence); -int klib_fread(char *buf, int len, struct file *filp); -int klib_fgetc(struct file *filp); -int klib_flength(struct file *filp); -int klib_flen_fcopy(char *buf, int len, struct file *filp); -int klib_fwrite(char *buf, int len, struct file *filp); +struct file *klib_fopen (const char *filename, int flags, int mode); +void klib_fclose (struct file *filp); +int klib_fseek (struct file *filp, int offset, int whence); +int klib_fread (char *buf, int len, struct file *filp); +int klib_fgetc (struct file *filp); +int klib_flength (struct file *filp); +int klib_flen_fcopy (char *buf, int len, struct file *filp); +int klib_fwrite (char *buf, int len, struct file *filp); + +void s3c_bat_use_wimax(int onoff); #endif /* _WIMAX_FIRMWARE_H */ diff --git a/drivers/net/wimax_cmc/hardware.c b/drivers/net/wimax_cmc/hardware.c new file mode 100755 index 0000000..7540584 --- /dev/null +++ b/drivers/net/wimax_cmc/hardware.c @@ -0,0 +1,599 @@ +/* + * hardware.c + * + * gpio control functions (power on/off, init/deinit gpios) + * data tx and tx thread implemented. + */ +#include "headers.h" +#include "download.h" +#include "wimax_plat.h" + +#include <mach/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/hardware.h> +#include <plat/sdhci.h> +#include <plat/devs.h> +#include <linux/spinlock.h> + +#define WIMAX_POWER_SUCCESS 0 +#define WIMAX_ALREADY_POWER_ON -1 +#define WIMAX_PROBE_FAIL -2 +#define WIMAX_ALREADY_POWER_OFF -3 + + +static void wimax_hostwake_task(unsigned long data) +{ + struct net_adapter *adapter = (struct net_adapter *)data; + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + + wake_lock_timeout(&g_cfg->wimax_wake_lock, 1 * HZ); + +} + +static irqreturn_t wimax_hostwake_isr(int irq, void *dev) +{ + struct net_adapter *adapter = (struct net_adapter *)dev; + tasklet_schedule(&adapter->hostwake_task); + return IRQ_HANDLED; +} +static int cmc732_setup_wake_irq(struct net_adapter *adapter) +{ + int rc = -EIO; + int irq; + + rc = gpio_request(WIMAX_INT, "gpio_wimax_int"); + if (rc < 0) { + dump_debug("%s: gpio %d request failed (%d)\n", + __func__, WIMAX_INT, rc); + return rc; + } + + rc = gpio_direction_input(WIMAX_INT); + if (rc < 0) { + dump_debug("%s: failed to set gpio %d as input (%d)\n", + __func__, WIMAX_INT, rc); + goto err_gpio_direction_input; + } + + irq = gpio_to_irq(WIMAX_INT); + + rc = request_irq(irq, wimax_hostwake_isr, IRQF_TRIGGER_FALLING, + "wimax_int", adapter); + if (rc < 0) { + dump_debug("%s: request_irq(%d) failed for gpio %d (%d)\n", + __func__, irq, + WIMAX_INT, rc); + goto err_request_irq; + } + + rc = enable_irq_wake(irq); + + if (rc < 0) { + dump_debug("%s: enable_irq_wake(%d) failed for gpio %d (%d)\n", + __func__, irq, + WIMAX_INT, rc); + goto err_enable_irq_wake; + } + + adapter->wake_irq = irq; + + tasklet_init(&adapter->hostwake_task, + wimax_hostwake_task, (unsigned long)adapter); + + goto done; +err_enable_irq_wake: + free_irq(irq, adapter); +err_request_irq: +err_gpio_direction_input: + gpio_free(WIMAX_INT); +done: + return rc; + +} +void cmc732_release_wake_irq(struct net_adapter *adapter) +{ + if (adapter->wake_irq) { + disable_irq_wake(adapter->wake_irq); + free_irq(adapter->wake_irq, adapter); + gpio_free(WIMAX_INT); + tasklet_kill(&adapter->hostwake_task); + } +} + + + +int hw_start(struct net_adapter *adapter) +{ + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + + if (load_wimax_image(g_cfg->wimax_mode)) + return STATUS_UNSUCCESSFUL; + + adapter->download_complete = FALSE; + + if (adapter->downloading) { + sdio_claim_host(adapter->func); + send_cmd_packet(adapter, MSG_DRIVER_OK_REQ); + sdio_release_host(adapter->func); + switch (wait_event_interruptible_timeout + (adapter->download_event, + (adapter->download_complete == TRUE), + msecs_to_jiffies(FWDOWNLOAD_TIMEOUT))) { + case 0: + /* timeout */ + dump_debug("Error hw_start :" + "F/W Download timeout failed"); + adapter->halted = TRUE; + return STATUS_UNSUCCESSFUL; + case -ERESTARTSYS: + /* Interrupted by signal */ + dump_debug("Error hw_start : -ERESTARTSYS retry"); + return STATUS_UNSUCCESSFUL; + default: + /* normal condition check */ + if (adapter->removed == TRUE + || adapter->halted == TRUE) { + dump_debug("Error hw_start : " + " F/W Download surprise removed"); + return STATUS_UNSUCCESSFUL; + } + + /*Setup hostwake interrupt*/ + + if (cmc732_setup_wake_irq(adapter) < 0) + dump_debug("hw_start : " + " Error setting up wimax_int"); + + + break; + } + adapter->downloading = FALSE; + } + + return STATUS_SUCCESS; +} + +int hw_stop(struct net_adapter *adapter) +{ + adapter->halted = TRUE; + + + /* Stop Sdio Interface */ + sdio_claim_host(adapter->func); + sdio_release_irq(adapter->func); + sdio_disable_func(adapter->func); + sdio_release_host(adapter->func); + + /*Remove wakeup interrupt*/ + cmc732_release_wake_irq(adapter); + + return STATUS_SUCCESS; +} + +int hw_init(struct net_adapter *adapter) +{ + + /* set WIMAX_WAKEUP & WIMAX_IF_MODE0 */ + adapter->pdata->set_mode(); + + /* initilize hardware info structure */ + memset(&adapter->hw, 0x0, sizeof(struct hardware_info)); + + /* allocate sdio receive buffer once */ + if (adapter->hw.receive_buffer == NULL) { + dump_debug("Alloc ReceiveBuffer"); + /* the extra 8 bytes space required to copy ethernet header */ + adapter->hw.receive_buffer = kmalloc(SDIO_BUFFER_SIZE + 8, + GFP_ATOMIC | GFP_DMA); + if (adapter->hw.receive_buffer == NULL) { + dump_debug("kmalloc fail!!"); + return -ENOMEM; + } + } + + /* initialize sdio receive buffer */ + memset(adapter->hw.receive_buffer, 0x0, SDIO_BUFFER_SIZE + 8); + + /* For sending data and control packets */ + queue_init_list(adapter->hw.q_send.head); + spin_lock_init(&adapter->hw.q_send.lock); + + init_waitqueue_head(&adapter->download_event); + + return STATUS_SUCCESS; +} + +void hw_remove(struct net_adapter *adapter) +{ + struct buffer_descriptor *dsc; + + /* Free the pending data packets and control packets */ + spin_lock(&adapter->hw.q_send.lock); + while (!queue_empty(adapter->hw.q_send.head)) { + dump_debug("Freeing q_send"); + dsc = (struct buffer_descriptor *) + queue_get_head(adapter->hw.q_send.head); + if (!dsc) { + dump_debug("Fail...node is null"); + continue; + } + queue_remove_head(adapter->hw.q_send.head); + kfree(dsc->buffer); + kfree(dsc); + } + spin_unlock(&adapter->hw.q_send.lock); + +} + +int con0_poll_thread(void *data) +{ + struct net_adapter *adapter = (struct net_adapter *)data; + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + int prev_val = 0; + int curr_val = 0; + + wake_lock(&g_cfg->wimax_tx_lock); + + while ((!adapter->halted)) { + curr_val = gpio_get_value(GPIO_WIMAX_CON0); + if ((prev_val && (!curr_val)) || (curr_val == GPIO_LEVEL_LOW)) { + adapter->pdata->restore_uart_path(); + break; + } + prev_val = curr_val; + msleep(40); + } + wake_unlock(&g_cfg->wimax_tx_lock); + do_exit(0); + return 0; +} + + + + + +/* get MAC address from device */ +void hw_get_mac_address(void *data) +{ + struct net_adapter *adapter = (struct net_adapter *)data; + struct hw_private_packet req; + int nResult = 0; + int retry = 5; + req.id0 = 'W'; + req.id1 = 'P'; + req.code = HwCodeMacRequest; + req.value = 0; + do { + if (adapter == NULL) + break; + + if (retry == 2) //odb backup takes 5.8sec + msleep(6000); + + sdio_claim_host(adapter->func); + nResult = sd_send(adapter, (u_char *)&req, + sizeof(struct hw_private_packet)); + sdio_release_host(adapter->func); + + if (nResult != STATUS_SUCCESS) + dump_debug("hw_get_mac_address: sd_send fail!!"); + msleep(300); + retry--; + /*in case we dont get MAC we need + to release power lock and probe finsh */ + if (!retry) { + adapter->download_complete = TRUE; + wake_up_interruptible(&adapter->download_event); + msleep(100); + + } + } while ((!adapter->mac_ready) && (!adapter->halted) && retry); + + adapter->pdata->g_cfg->powerup_done = true ; + dump_debug("MAC thread exit"); + return; +} + +u_int hw_send_data(struct net_adapter *adapter, + void *buffer , u_long length, bool control) +{ + struct buffer_descriptor *dsc; + struct hw_packet_header *hdr; + struct net_device *net = adapter->net; + u_char *ptr; + unsigned long flags ; + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + + spin_lock_irqsave(&adapter->hw.q_send.lock, flags); + + dsc = (struct buffer_descriptor *)kmalloc( + sizeof(struct buffer_descriptor), GFP_ATOMIC | GFP_DMA); + if (dsc == NULL) + return STATUS_RESOURCES; + + dsc->buffer = kmalloc(BUFFER_DATA_SIZE , GFP_ATOMIC | GFP_DMA); + if (dsc->buffer == NULL) { + kfree(dsc); + return STATUS_RESOURCES; + } + + ptr = dsc->buffer; + + /* shift data pointer */ + ptr += sizeof(struct hw_packet_header); +#ifdef HARDWARE_USE_ALIGN_HEADER + ptr += 2; +#endif + hdr = (struct hw_packet_header *)dsc->buffer; + + if (control) { + memcpy(ptr, buffer + (ETHERNET_ADDRESS_LENGTH * 2), + length - (ETHERNET_ADDRESS_LENGTH * 2)); + + /* add packet header */ + hdr->id0 = 'W'; + hdr->id1 = 'C'; + hdr->length = (u_short)length - (ETHERNET_ADDRESS_LENGTH * 2); + + /* set length */ + dsc->length = (u_short)length - (ETHERNET_ADDRESS_LENGTH * 2) + + sizeof(struct hw_packet_header); + #ifdef HARDWARE_USE_ALIGN_HEADER + dsc->length += 2; + #endif + + /* dump control packet for debug */ + if (g_cfg->enable_dump_msg == 1) + dump_buffer("Control Tx", + (u_char *)dsc->buffer + 6, dsc->length - 6); + } else { + + length -= (ETHERNET_ADDRESS_LENGTH * 2); + buffer += (ETHERNET_ADDRESS_LENGTH * 2); + + memcpy(ptr, buffer, length); + + hdr->id0 = 'W'; + hdr->id1 = 'D'; + hdr->length = (u_short)length; + + dsc->length = length + sizeof(struct hw_packet_header); + #ifdef HARDWARE_USE_ALIGN_HEADER + dsc->length += 2; + #endif + adapter->netstats.tx_packets++; + adapter->netstats.tx_bytes += dsc->length; + + /* add statistics */ + if (!netif_running(net)) + dump_debug("!netif_running"); + + } + + + queue_put_tail(adapter->hw.q_send.head, dsc->node); + spin_unlock_irqrestore(&adapter->hw.q_send.lock, flags); + + queue_work(adapter->wimax_workqueue, &adapter->transmit_work); + return STATUS_SUCCESS; +} + +u_int sd_send_data(struct net_adapter *adapter, struct buffer_descriptor *dsc) +{ + int nRet = 0; + int nWriteIdx; + dsc->length += (dsc->length & 1) ? 1 : 0; + +#ifdef HARDWARE_USE_ALIGN_HEADER + if (dsc->length > SDIO_MAX_BYTE_SIZE) + dsc->length = (dsc->length + SDIO_MAX_BYTE_SIZE) + & ~(SDIO_MAX_BYTE_SIZE); +#endif + + if (adapter->halted) { + dump_debug("Halted Already"); + return STATUS_UNSUCCESSFUL; + } + hwSdioWriteBankIndex(adapter, &nWriteIdx, &nRet); + + if (nRet || (nWriteIdx < 0)) { + dump_debug("sd_send_data : " + " error fetch bank index!! nRet = %d", nRet); + return STATUS_UNSUCCESSFUL; + } + + sdio_writeb(adapter->func, (nWriteIdx + 1) % 15, + SDIO_H2C_WP_REG, NULL); + + nRet = sdio_memcpy_toio(adapter->func, + SDIO_TX_BANK_ADDR+(SDIO_BANK_SIZE * nWriteIdx)+4, + dsc->buffer, dsc->length); + + if (nRet < 0) + dump_debug("sd_send_data :" + " error writing dsc packet!! nRet = %d", nRet); + nRet = sdio_memcpy_toio(adapter->func, + SDIO_TX_BANK_ADDR + (SDIO_BANK_SIZE * nWriteIdx), + &(dsc->length), 4); + + if (nRet < 0) + dump_debug("sd_send_data :" + "error writing bank length info!! nRet = %d", nRet); + return nRet; +} + +/* Return packet for packet buffer freeing */ +void hw_return_packet(struct net_adapter *adapter, u_short type) +{ + struct buffer_descriptor *curElem; + struct buffer_descriptor *prevElem = NULL; + + if (queue_empty(adapter->ctl.q_received.head)) + return; + + /* first time get head needed to get the dsc nodes */ + curElem = (struct buffer_descriptor *) + queue_get_head(adapter->ctl.q_received.head); + + for ( ; curElem != NULL; prevElem = curElem, + curElem = (struct buffer_descriptor *)curElem->node.next) { + if (curElem->type == type) { + /* process found*/ + if (prevElem == NULL) { + /* First node or only + one node present to delete */ + adapter->ctl.q_received.head.next = + ((struct list_head *)curElem)->next; + if (!((adapter->ctl.q_received.head).next)) { + /* rechain list pointer to next link */ + /* if the list pointer is null, + null out the reverse link */ + (adapter->ctl.q_received.head).prev = + NULL; + } + } else if (((struct list_head *)curElem)->next + == NULL) { + /* last node */ + ((struct list_head *)prevElem)->next = NULL; + (adapter->ctl.q_received.head).prev = + (struct list_head *)(&prevElem); + } else { + /* middle node */ + ((struct list_head *)prevElem)->next = + ((struct list_head *)curElem)->next; + } + + kfree(curElem->buffer); + kfree(curElem); + break; + } + } +} + +int hw_device_wakeup(struct net_adapter *adapter) +{ + int rc = 0; + + adapter->pdata->wakeup_assert(1); + + while (!adapter->pdata->is_modem_awake()) { + if (rc == 0) + dump_debug("hw_device_wakeup (CON0 status):" + " waiting for modem awake"); + rc++; + if (rc > WAKEUP_MAX_TRY) { + dump_debug("hw_device_wakeup (CON0 status):" + " modem wake up time out!!"); + return -1; + } + msleep(WAKEUP_TIMEOUT/2); + adapter->pdata->wakeup_assert(0); + msleep(WAKEUP_TIMEOUT/2); + adapter->pdata->wakeup_assert(1); + s3c_bat_use_wimax(1); + } + if (rc != 0) + dump_debug("hw_device_wakeup (CON0 status): modem awake"); + adapter->pdata->wakeup_assert(0); + + return 0; +} + +/* +This Work is responsible for Transmiting Both Control And Data packet +*/ + +void hw_transmit_thread(struct work_struct *work) +{ + struct buffer_descriptor *dsc; + struct hw_private_packet hdr; + struct net_adapter *adapter; + int nRet = 0; + int modem_reset = false; + struct wimax_cfg *g_cfg; + + adapter = container_of(work, struct net_adapter, transmit_work); + g_cfg = adapter->pdata->g_cfg; + wake_lock(&g_cfg->wimax_tx_lock); + + if (!gpio_get_value(WIMAX_EN)) { + dump_debug("WiMAX Power OFF!! (TX)"); + goto exit; + } + + mutex_lock(&adapter->rx_lock); + + while (!queue_empty(adapter->hw.q_send.head)) { + if (adapter->halted) { + /* send stop message */ + hdr.id0 = 'W'; + hdr.id1 = 'P'; + hdr.code = HwCodeHaltedIndication; + hdr.value = 0; + + if (sd_send(adapter, (unsigned char *)&hdr, + sizeof(struct hw_private_packet))) + dump_debug("halted," + " send HaltIndication to FW err"); + modem_reset = true; + break; + } + + if (!g_cfg->modem_reset_flag) { + dump_debug("modem_reset_flag is not set"); + break; + } + + if(hw_device_wakeup(adapter)) { + modem_reset = true; + break; + } + + dsc = (struct buffer_descriptor *) + queue_get_head(adapter->hw.q_send.head); + + if (!dsc->buffer) { + dump_debug("dsc->buffer is NULL"); + break; + } + + if (!dsc) { + dump_debug("Fail...node is null"); + break; + } + + sdio_claim_host(adapter->func); + nRet = sd_send_data(adapter, dsc); + sdio_release_host(adapter->func); + queue_remove_head(adapter->hw.q_send.head); + kfree(dsc->buffer); + kfree(dsc); + if (nRet != STATUS_SUCCESS) { + sdio_claim_host(adapter->func); + sdio_release_irq(adapter->func); + sdio_release_host(adapter->func); + ++adapter->XmitErr; + dump_debug("SendData Fail******"); + if (nRet == -ENOMEDIUM || nRet == /*-ETIMEOUT*/-110) { + dump_debug("%s: No medium or timeout error", __func__); + // adapter->halted = TRUE; + } + modem_reset = true; + break; + } + } + + if(modem_reset) { + while (!g_cfg->modem_reset_flag) { + dump_debug("Waiting for PM_POST_SUSPEND notifier"); + msleep(100); + } + adapter->pdata->power(0); + dump_debug("Modem reset done"); + } + + mutex_unlock(&adapter->rx_lock); +exit: + wake_unlock(&g_cfg->wimax_tx_lock); + return ; +} diff --git a/drivers/net/wimax_cmc/headers.h b/drivers/net/wimax_cmc/headers.h new file mode 100755 index 0000000..f6a5b84 --- /dev/null +++ b/drivers/net/wimax_cmc/headers.h @@ -0,0 +1,116 @@ +/* + * headers.h + * + * Global definitions and fynctions + */ +#ifndef _WIMAX_HEADERS_H +#define _WIMAX_HEADERS_H + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/proc_fs.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio_func.h> +#include <asm/byteorder.h> +#include <asm/uaccess.h> +#include <linux/wakelock.h> +#include <linux/wimax/samsung/wimax732.h> +#include "buffer.h" +#include "wimax_sdio.h" + +#define WIMAXMAC_TXT_PATH "/efs/WiMAXMAC.txt" +#define WIMAX_IMAGE_PATH "/system/etc/wimaxfw.bin" +#define WIMAX_LOADER_PATH "/system/etc/wimaxloader.bin" +#define WIMAX_BOOTIMAGE_PATH "/system/etc/wimax_boot.bin" + +#define STATUS_SUCCESS ((u_long)0x00000000L) +#define STATUS_PENDING ((u_long)0x00000103L) /* The operation that was requested is pending completion */ +#define STATUS_RESOURCES ((u_long)0x00001003L) +#define STATUS_RESET_IN_PROGRESS ((u_long)0xc001000dL) +#define STATUS_DEVICE_FAILED ((u_long)0xc0010008L) +#define STATUS_NOT_ACCEPTED ((u_long)0x00010003L) +#define STATUS_FAILURE ((u_long)0xC0000001L) +#define STATUS_UNSUCCESSFUL ((u_long)0xC0000002L) /* The requested operation was unsuccessful */ +#define STATUS_CANCELLED ((u_long)0xC0000003L) + +#ifndef TRUE_FALSE_ +#define TRUE_FALSE_ +enum BOOL { + FALSE, + TRUE +}; +#endif + +#define HARDWARE_USE_ALIGN_HEADER + +#define dump_debug(args...) \ +{ \ + printk(KERN_ALERT"\x1b[1;33m[WiMAX] "); \ + printk(args); \ + printk("\x1b[0m\n"); \ +} + + +/* external functions & variables */ +extern void set_wimax_pm(void(*suspend)(void), void(*resume)(void)); +extern void unset_wimax_pm(void); +extern int cmc732_sdio_reset_comm(struct mmc_card *card); +extern u_int system_rev; + +/* receive.c functions */ +u_int process_sdio_data(struct net_adapter *adapter, void *buffer, u_long length, long Timeout); + +/* control.c functions */ +u_int control_send(struct net_adapter *adapter, void *buffer, u_long length); +void control_recv(struct net_adapter *adapter, void *buffer, u_long length); +u_int control_init(struct net_adapter *adapter); +void control_remove(struct net_adapter *adapter); + +struct process_descriptor *process_by_id(struct net_adapter *adapter, u_int id); +struct process_descriptor *process_by_type(struct net_adapter *adapter, u_short type); +void remove_process(struct net_adapter *adapter, u_int id); + +u_long buffer_count(struct list_head ListHead); +struct buffer_descriptor *buffer_by_type(struct list_head ListHead, u_short type); +void dump_buffer(const char *desc, u_char *buffer, u_int len); + +/* hardware.c functions */ +void switch_eeprom_ap(void); +void switch_eeprom_wimax(void); +void switch_usb_ap(void); +void switch_usb_wimax(void); +void display_gpios(void); /* display GPIO status used by WiMAX module */ +void switch_uart_ap(void); +void switch_uart_wimax(void); +void hw_init_gpios(void); +void hw_deinit_gpios(void); + +u_int sd_send(struct net_adapter *adapter, u_char *buffer, u_int len); +u_int sd_send_data(struct net_adapter *adapter, struct buffer_descriptor *dsc); +u_int hw_send_data(struct net_adapter *adapter, void *buffer, u_long length,bool); +void hw_return_packet(struct net_adapter *adapter, u_short type); + +void s3c_bat_use_wimax(int onoff); + +int gpio_wimax_poweron (void); +int gpio_wimax_poweroff (void); + +int hw_start(struct net_adapter *adapter); +int hw_stop(struct net_adapter *adapter); +int hw_init(struct net_adapter *adapter); +void hw_remove(struct net_adapter *adapter); +void hw_get_mac_address(void *data); +int con0_poll_thread(void *data); +void hw_transmit_thread(struct work_struct *work); +void adapter_interrupt(struct sdio_func *func); +/* structures for global access */ +extern struct net_adapter *g_adapter; + +#endif /* _WIMAX_HEADERS_H */ diff --git a/drivers/net/wimax_cmc/hw_types.h b/drivers/net/wimax_cmc/hw_types.h new file mode 100755 index 0000000..3a1606c --- /dev/null +++ b/drivers/net/wimax_cmc/hw_types.h @@ -0,0 +1,96 @@ +/** + * hw_types.h + * + * Hardware types and definitions + */ +#ifndef _WIMAX_HW_TYPES_H +#define _WIMAX_HW_TYPES_H + +#include "ctl_types.h" + +/* private protocol defines */ +#define HW_PROT_VALUE_LINK_DOWN 0x00 +#define HW_PROT_VALUE_LINK_UP 0xff + +/* SDIO general defines */ +#define SDIO_BANK_SIZE 4096 /* size of a bank in cmc's rx and tx buffers */ +#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size (SDIO) */ +#define SDIO_MAX_BYTE_SIZE 511 /* maximum size in byte mode */ +#define SDIO_BUFFER_SIZE SDIO_MAX_BLOCK_SIZE +/* + *We need the HEADER_MANIPULATION_OFFSET because + *we now use only one buffer while receiving data. + *since the ehternet header is larger than the hardware packet header, + *we need to keep some space at the beginning of the buffer to accomodate the + *ethernet header. 8 bytes is enough for this purpose. + */ +#define HEADER_MANIPULATION_OFFSET 8 +/* SDIO function addresses */ +#define SDIO_TX_BANK_ADDR 0x1000 +#define SDIO_RX_BANK_ADDR 0x10000 +#define SDIO_INT_STATUS_REG 0xC0 +#define SDIO_INT_STATUS_CLR_REG 0xC4 + +#define SDIO_C2H_WP_REG 0xE4 +#define SDIO_C2H_RP_REG 0xE8 +#define SDIO_H2C_WP_REG 0xEC +#define SDIO_H2C_RP_REG 0xF0 + +/* SDIO function registers */ +#define SDIO_INT_DATA_READY 0x01 +#define SDIO_INT_ERROR 0x02 + +#define WAKEUP_MAX_TRY 20 +#define WAKEUP_TIMEOUT 300 +#define CONTROL_PACKET 1 +#define DATA_PACKET 0 + +/* packet types */ +enum { + HwPktTypeNone = 0xff00, + HwPktTypePrivate, + HwPktTypeControl, + HwPktTypeData, + HwPktTypeTimeout +}; + +/* private packet opcodes */ +enum { + HwCodeMacRequest = 0x01, + HwCodeMacResponse, + HwCodeLinkIndication, + HwCodeRxReadyIndication, + HwCodeHaltedIndication, + HwCodeIdleNtfy, + HwCodeWakeUpNtfy +}; + + +#pragma pack(1) +struct hw_packet_header { + char id0; /* packet ID */ + char id1; + u_short length; /* packet length */ +}; + +struct hw_private_packet { + char id0; /* packet ID */ + char id1; + u_char code; /* command code */ + u_char value; /* command value */ +}; +#pragma pack() + +struct wimax_msg_header { + u_short type; + u_short id; + u_int length; +}; + +struct hardware_info { + void *receive_buffer; + u_char eth_header[ETHERNET_ADDRESS_LENGTH * 2]; /* ethernet header */ + struct queue_info q_send; /* send pending queue */ +}; + +#endif /* _WIMAX_HW_TYPES_H */ diff --git a/drivers/net/wimax_cmc/receive.c b/drivers/net/wimax_cmc/receive.c new file mode 100755 index 0000000..a0e43d1 --- /dev/null +++ b/drivers/net/wimax_cmc/receive.c @@ -0,0 +1,301 @@ +/* + * receive.c + * + * handle download packet, private cmd and control/data packet + */ +#include "headers.h" +#include "wimax_plat.h" +#include "firmware.h" +#include "download.h" + +#include <plat/sdhci.h> +#include <plat/devs.h> +#include <linux/mmc/host.h> +#include <linux/kthread.h> +extern struct image_data g_wimax_image; + +void process_indicate_packet(struct net_adapter *adapter, u_char *buffer) +{ + struct wimax_msg_header *packet; + char *tmp_byte; + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + + packet = (struct wimax_msg_header *)buffer; + + if (packet->type == be16_to_cpu(ETHERTYPE_DL)) { + switch (be16_to_cpu(packet->id)) { + case MSG_DRIVER_OK_RESP: + dump_debug("process_indicate_packet: MSG_DRIVER_OK_RESP"); + send_image_info_packet(adapter, MSG_IMAGE_INFO_REQ); + break; + case MSG_IMAGE_INFO_RESP: + dump_debug("process_indicate_packet: MSG_IMAGE_INFO_RESP"); + send_image_data_packet(adapter, MSG_IMAGE_DATA_REQ); + break; + case MSG_IMAGE_DATA_RESP: + if (g_wimax_image.offset == g_wimax_image.size) { + dump_debug("process_indicate_packet: Image Download Complete"); + send_cmd_packet(adapter, MSG_RUN_REQ); /* Run Message Send */ + } else + send_image_data_packet(adapter, MSG_IMAGE_DATA_REQ); + break; + case MSG_RUN_RESP: + tmp_byte = (char *)(buffer + sizeof(struct wimax_msg_header)); + + if (*tmp_byte == 0x01) { + dump_debug("process_indicate_packet: MSG_RUN_RESP"); + + if (g_cfg->wimax_mode == SDIO_MODE || g_cfg->wimax_mode == DM_MODE + || g_cfg->wimax_mode == USB_MODE + || g_cfg->wimax_mode == USIM_RELAY_MODE) { + + dump_debug("%s: F/W Download Complete and Running ",__func__); + dump_debug("Wait for SDIO ready..."); + msleep(1200); /* IMPORTANT!! wait for cmc730 can handle mac req packet */ + + kernel_thread((int (*)(void *))hw_get_mac_address, adapter, 0); + } else if (g_cfg->wimax_mode == WTM_MODE) { + adapter->download_complete = TRUE; + wake_up_interruptible(&adapter->download_event); + adapter->pdata->g_cfg->powerup_done = true ; + adapter->wtm_task = kthread_create( + con0_poll_thread, adapter, "%s", + "wimax_con0_poll_thread"); + if (adapter->wtm_task) + wake_up_process( + adapter->wtm_task); + } else if (g_cfg->wimax_mode == AUTH_MODE) { + adapter->download_complete = TRUE; + wake_up_interruptible(&adapter->download_event); + adapter->pdata->g_cfg->powerup_done = true ; + } + } + break; + default: + dump_debug("process_indicate_packet: Unkown type"); + break; + } + } + else + dump_debug("process_indicate_packet - is not download pakcet"); +} + +u_long process_private_cmd(struct net_adapter *adapter, void *buffer) +{ + struct hw_private_packet *cmd; + u_char *bufp; + struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; + cmd = (struct hw_private_packet *)buffer; + + switch (cmd->code) { + case HwCodeMacResponse: { + u_char mac_addr[ETHERNET_ADDRESS_LENGTH]; + bufp = (u_char *)buffer; + + /* processing for mac_req request */ + #ifndef PRODUCT_SHIP + dump_debug("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", + bufp[3], bufp[4], bufp[5], bufp[6], bufp[7], bufp[8]); + #endif + memcpy(mac_addr, bufp + 3, ETHERNET_ADDRESS_LENGTH); + + /* create ethernet header */ + memcpy(adapter->hw.eth_header, mac_addr, ETHERNET_ADDRESS_LENGTH); + memcpy(adapter->hw.eth_header + ETHERNET_ADDRESS_LENGTH, mac_addr, ETHERNET_ADDRESS_LENGTH); + adapter->hw.eth_header[(ETHERNET_ADDRESS_LENGTH * 2) - 1] += 1; + + memcpy(adapter->net->dev_addr, bufp + 3, ETHERNET_ADDRESS_LENGTH); + adapter->mac_ready = TRUE; + + if (adapter->downloading) { + adapter->download_complete = TRUE; + wake_up_interruptible(&adapter->download_event); + } + return (sizeof(struct hw_private_packet) + ETHERNET_ADDRESS_LENGTH - sizeof(u_char)); + } + case HwCodeLinkIndication: { + if ((cmd->value == HW_PROT_VALUE_LINK_DOWN) + && (adapter->media_state != MEDIA_DISCONNECTED)) { + dump_debug("LINK_DOWN_INDICATION"); + s3c_bat_use_wimax(0); + + /* set values */ + adapter->media_state = MEDIA_DISCONNECTED; + + /* indicate link down */ + netif_stop_queue(adapter->net); + netif_carrier_off(adapter->net); + } else if ((cmd->value == HW_PROT_VALUE_LINK_UP) + && (adapter->media_state != MEDIA_CONNECTED)) { + dump_debug("LINK_UP_INDICATION"); + + s3c_bat_use_wimax(1); + /* set values */ + adapter->media_state = MEDIA_CONNECTED; + adapter->net->mtu = WIMAX_MTU_SIZE; + + /* indicate link up */ + netif_start_queue(adapter->net); + netif_carrier_on(adapter->net); + } + break; + } + case HwCodeHaltedIndication: { + dump_debug("Device is about to reset, stop driver"); + break; + } + case HwCodeRxReadyIndication: { + dump_debug("Device RxReady"); + /* to start the data packet send queue again after stopping in xmit */ + if (adapter->media_state == MEDIA_CONNECTED) + netif_wake_queue(adapter->net); + break; + } + case HwCodeIdleNtfy: { + /* set idle / vi */ + + dump_debug("process_private_cmd: HwCodeIdleNtfy"); + + s3c_bat_use_wimax(0); + break; + } + case HwCodeWakeUpNtfy: { + /* IMPORTANT!! at least 4 sec is required after modem waked up */ + wake_lock_timeout(&g_cfg->wimax_wake_lock, 4 * HZ); + dump_debug("process_private_cmd: HwCodeWakeUpNtfy"); + s3c_bat_use_wimax(1); + break; + } + default: + dump_debug("Command = %04x", cmd->code); + break; + } + + return sizeof(struct hw_private_packet); +} + +u_int process_sdio_data(struct net_adapter *adapter, + void *buffer, u_long length, long Timeout) +{ + struct hw_packet_header *hdr; + struct net_device *net = adapter->net; + u_char *ofs = (u_char *)buffer; + int res = 0; + u_int machdrlen = (ETHERNET_ADDRESS_LENGTH * 2); + u_int rlen = length; + u_long type; + u_short data_len; + struct sk_buff *skb; + while ((int)rlen > 0) { + hdr = (struct hw_packet_header *)ofs; + type = HwPktTypeNone; + + if (unlikely(hdr->id0 != 'W')) { /* "WD", "WC", "WP" or "WE" */ + if (rlen > 4) { + dump_debug("Wrong packet ID (%02x %02x)", hdr->id0, hdr->id1); + dump_buffer("Wrong packet", (u_char *)ofs, rlen); + } + /* skip rest of packets */ + return 0; + } + + /* check packet type */ + switch (hdr->id1) { + case 'P': { + u_long l = 0; + type = HwPktTypePrivate; + + /* process packet */ + l = process_private_cmd(adapter, ofs); + + /* shift */ + ofs += l; + rlen -= l; + + /* process next packet */ + continue; + } + case 'C': + type = HwPktTypeControl; + break; + case 'D': + type = HwPktTypeData; + break; + case 'E': + /* skip rest of buffer */ + return 0; + default: + dump_debug("hwParseReceivedData : Wrong packet ID [%02x %02x]", + hdr->id0, hdr->id1); + /* skip rest of buffer */ + return 0; + } + + if (likely(!adapter->downloading)) { + if (unlikely(hdr->length > WIMAX_MAX_TOTAL_SIZE + || ((hdr->length + sizeof(struct hw_packet_header)) > rlen))) { + dump_debug("Packet length is too big (%d)", hdr->length); + /* skip rest of packets */ + return 0; + } + } + + /* change offset */ + ofs += sizeof(struct hw_packet_header); + rlen -= sizeof(struct hw_packet_header); + + /* process download packet, data and control packet */ + if (likely(!adapter->downloading)) + { +#ifdef HARDWARE_USE_ALIGN_HEADER + ofs += 2; + rlen -= 2; +#endif + /* store the packet length */ + /* because we will overwrite the hardware packet header */ + data_len = hdr->length; + /* copy the MAC to ofs buffer */ + memcpy((u_char *)ofs - machdrlen, adapter->hw.eth_header, machdrlen); + + if (unlikely(type == HwPktTypeControl)) + control_recv(adapter, (u_char *)ofs -machdrlen, + data_len + machdrlen); + else { + + skb = dev_alloc_skb(data_len + machdrlen + 2); + if(!skb) + { + dump_debug("MEMORY PINCH: unable to allocate skb"); + return -ENOMEM; + } + skb_reserve(skb, 2); + memcpy(skb_put(skb, (data_len + machdrlen)), + (u_char *)ofs -machdrlen, + (data_len + machdrlen)); + skb->dev = net; + skb->protocol = eth_type_trans(skb, net); + skb->ip_summed = CHECKSUM_UNNECESSARY; + res = netif_rx(skb); + + adapter->netstats.rx_packets++; + adapter->netstats.rx_bytes += (data_len + machdrlen); + + + } + /* restore the hardware packet length information */ + hdr->length = data_len; + } else { + hdr->length -= sizeof(struct hw_packet_header); + process_indicate_packet(adapter, ofs); + } + /* + * If the packet is unreasonably long, quietly drop it rather than + * kernel panicing by calling skb_put. + */ + /* shift */ + ofs += hdr->length; + rlen-= hdr->length; + } + + return 0; +} diff --git a/drivers/net/wimax_cmc/wimax_i2c.c b/drivers/net/wimax_cmc/wimax_i2c.c index 018bfd3..474688a 100644..100755 --- a/drivers/net/wimax_cmc/wimax_i2c.c +++ b/drivers/net/wimax_cmc/wimax_i2c.c @@ -3,6 +3,7 @@ * * EEPROM access functions */ +//#include "download.h" #include "wimax_i2c.h" #include "firmware.h" #include <linux/i2c.h> @@ -28,7 +29,7 @@ struct boot_image_data g_wimax_image; -static void wimax_i2c_reset(void); +void wimax_i2c_reset(void); void dump_buffer(const char *desc, u_char *buffer, u_int len) { @@ -62,9 +63,8 @@ void eeprom_poweron(void) gpio_set_value(EEPROM_SCL, GPIO_LEVEL_HIGH); gpio_set_value(EEPROM_SDA, GPIO_LEVEL_HIGH); - /* SEL = 1 to switch i2c-eeprom path to AP */ - gpio_set_value(I2C_SEL, GPIO_LEVEL_HIGH); - usleep_range(10000, 10000); + gpio_set_value(I2C_SEL, GPIO_LEVEL_HIGH); // SEL = 1 to switch i2c-eeprom path to AP + msleep(10); /* power on */ @@ -73,7 +73,7 @@ void eeprom_poweron(void) msleep(100); wimax_i2c_reset(); - usleep_range(10000, 10000); + msleep(10); } void eeprom_poweroff(void) @@ -81,8 +81,7 @@ void eeprom_poweroff(void) /* power off */ gpio_set_value(WIMAX_EN, GPIO_LEVEL_LOW); - /* SEL = 0 to switch i2c-eeprom path to wimax */ - gpio_set_value(I2C_SEL, GPIO_LEVEL_LOW); + gpio_set_value(I2C_SEL, GPIO_LEVEL_LOW); // SEL = 0 to switch i2c-eeprom path to wimax msleep(100); @@ -145,8 +144,7 @@ void wimax_i2c_init(void) gpio_set_value(EEPROM_SDA, GPIO_LEVEL_LOW); udelay(2); - /* send 7 bits address */ - wimax_i2c_write_byte(DEVICE_ADDRESS, 7); + wimax_i2c_write_byte(DEVICE_ADDRESS, 7); /* send 7 bits address */ } void wimax_i2c_deinit(void) @@ -284,7 +282,7 @@ int wimax_i2c_eeprom_address(short addr) /* send 2 bytes address */ wimax_i2c_write_byte(buf[1], 8); - if (wimax_i2c_check_ack()) + if(wimax_i2c_check_ack()) return -1; wimax_i2c_write_byte(buf[0], 8); return wimax_i2c_check_ack(); @@ -292,8 +290,9 @@ int wimax_i2c_eeprom_address(short addr) int wimax_i2c_write_buffer(char *data, int len) { - int i; - for (i = 0; i < len; i++) { + int i; + + for(i = 0; i < len; i++) { wimax_i2c_write_byte(data[i], 8); /* 1 byte data */ if (wimax_i2c_check_ack()) return -1; @@ -352,19 +351,19 @@ int wimax_i2c_write(u_short addr, u_char *data, int length) struct i2c_msg msg; data_buffer[0] = (unsigned char)((addr >> 8) & 0xff); data_buffer[1] = (unsigned char)(addr & 0xff); - while (length) { - len = (length > MAX_BOOT_WRITE_LENGTH) ? - MAX_BOOT_WRITE_LENGTH : length ; + while(length) + { + len = (length > MAX_BOOT_WRITE_LENGTH)? MAX_BOOT_WRITE_LENGTH : length ; memcpy(data_buffer+WIMAX_EEPROM_ADDRLEN, data, len); msg.addr = pclient->addr; - msg.flags = 0; /*write*/ + msg.flags = 0; //write msg.len = (u16)length+WIMAX_EEPROM_ADDRLEN; msg.buf = data_buffer; rc = i2c_transfer(pclient->adapter, &msg, 1); if (rc < 0) return rc; - length -= len; - data += len; + length-=len; + data+=len; } return 0; } @@ -376,11 +375,11 @@ int wimax_i2c_read(u_short addr, u_char *data, int length) data_buffer[0] = (unsigned char)((addr >> 8) & 0xff); data_buffer[1] = (unsigned char)(addr & 0xff); msgs[0].addr = pclient->addr; - msgs[0].flags = 0; /*write*/ + msgs[0].flags = 0; //write msgs[0].len = WIMAX_EEPROM_ADDRLEN; msgs[0].buf = data_buffer; msgs[1].addr = pclient->addr; - msgs[1].flags = I2C_M_RD; /*read*/ + msgs[1].flags = I2C_M_RD; //read msgs[1].len = length; msgs[1].buf = data; return i2c_transfer(pclient->adapter, msgs, 2); @@ -398,9 +397,8 @@ static ssize_t eeprom_show(struct device *dev, } -static ssize_t eeprom_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) { +static ssize_t eeprom_store(struct device *dev, + struct device_attribute *attr, const char *buffer, size_t count) { if (strncmp(buffer, "wb00", 4) == 0) { pr_debug("Write EEPROM!!"); @@ -426,7 +424,7 @@ static ssize_t eeprom_store(struct device *dev, } else if (strncmp(buffer, "wrev", 4) == 0) { pr_debug("Write Rev!!"); eeprom_write_rev(); - } else + } else pr_debug("Wrong option"); return count; @@ -465,8 +463,8 @@ int wmxeeprom_remove(struct i2c_client *client) return 0; } -const struct i2c_device_id wmxeeprom_id[] = { - { "wmxeeprom", 0 }, +const struct i2c_device_id wmxeeprom_id[]={ + { "wmxeeprom",0 }, { } }; @@ -499,7 +497,7 @@ int load_wimax_boot(void) if (fp) { pr_debug("LoadWiMAXBootImage .."); - g_wimax_image.data = vmalloc(MAX_WIMAXBOOTIMAGE_SIZE); + g_wimax_image.data = (u_char *)vmalloc(MAX_WIMAXBOOTIMAGE_SIZE); if (!g_wimax_image.data) { pr_debug("Error: Memory alloc failure."); klib_fclose(fp); @@ -507,8 +505,7 @@ int load_wimax_boot(void) } memset(g_wimax_image.data, 0, MAX_WIMAXBOOTIMAGE_SIZE); - read_size = klib_flen_fcopy(g_wimax_image.data, - MAX_WIMAXBOOTIMAGE_SIZE, fp); + read_size = klib_flen_fcopy(g_wimax_image.data, MAX_WIMAXBOOTIMAGE_SIZE, fp); g_wimax_image.size = read_size; g_wimax_image.address = 0; g_wimax_image.offset = 0; @@ -534,10 +531,12 @@ int write_rev(void) /* swap */ val = be32_to_cpu(system_rev); - do { + do + { err = wimax_i2c_write(0x7080, (char *)(&val), 4); - } while (err < 0 ? ((retry--) > 0) : 0); - if (retry < 0) + } + while(err<0?((retry--)>0):0); + if(retry<0) pr_debug("eeprom error"); return err ; } @@ -549,10 +548,12 @@ void erase_cert(void) int retry = 100; int err; - do { + do + { err = wimax_i2c_write(0x5800, buf, len); - } while (err < 0 ? ((retry--) > 0) : 0); - if (retry < 0) + } + while(err<0?((retry--)>0):0); + if(retry<0) pr_debug("eeprom error"); } @@ -563,17 +564,18 @@ int check_cert(void) int retry = 100; int err; - do { + do + { err = wimax_i2c_read(0x5800, buf, len); - } while (err < 0 ? ((retry--) > 0) : 0); - if (retry < 0) + } + while(err<0?((retry--)>0):0); + if(retry<0) pr_debug("eeprom error"); dump_buffer("Certification", (u_char *)buf, (u_int)len); /* check "Cert" */ - if (buf[0] == 0x43 && buf[1] == 0x65 && - buf[2] == 0x72 && buf[3] == 0x74) + if (buf[0] == 0x43 && buf[1] == 0x65 && buf[2] == 0x72 && buf[3] == 0x74) return 0; return -1; @@ -587,10 +589,12 @@ int check_cal(void) int retry = 100; int err; - do { + do + { err = wimax_i2c_read(0x5400, buf, len); - } while (err < 0 ? ((retry--) > 0) : 0); - if (retry < 0) + } + while(err<0?((retry--)>0):0); + if(retry<0) pr_debug("eeprom error"); dump_buffer("Calibration", (u_char *)buf, (u_int)len); @@ -616,7 +620,7 @@ void eeprom_read_boot() eeprom_poweron(); - buf = kmalloc(4096, GFP_KERNEL); + buf = (char *)kmalloc(4096, GFP_KERNEL); if (buf == NULL) { pr_debug("eeprom_read_boot: MALLOC FAIL!!"); return; @@ -625,12 +629,12 @@ void eeprom_read_boot() addr = 0x0; for (j = 0; j < 1; j++) { /* read 4K */ len = 4096; - do { + do + { err = wimax_i2c_read(addr, buf, len); - } while (err < 0 ? ((retry--) > 0) : 0); - - { - /* dump boot data */ + } + while(err<0?((retry--)>0):0); + { /* dump boot data */ char print_buf[256] = {0}; char chr[8] = {0}; @@ -657,7 +661,7 @@ void eeprom_read_boot() kfree(buf); eeprom_poweroff(); - if (retry < 0) + if(retry<0) pr_debug("eeprom error"); } @@ -674,23 +678,22 @@ void eeprom_read_all() eeprom_poweron(); /* allocate 4K buffer */ - buf = kmalloc(4096, GFP_KERNEL); + buf = (char *)kmalloc(4096, GFP_KERNEL); if (buf == NULL) { pr_debug("eeprom_read_all: MALLOC FAIL!!"); return; } addr = 0x0; - - /* read 64K */ - for (j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) /* read 64K */ + { len = 4096; - do { + do + { err = wimax_i2c_read(addr, buf, len); - } while (err < 0 ? ((retry--) > 0) : 0); - - { - /* dump EEPROM */ + } + while(err<0?((retry--)>0):0); + { /* dump EEPROM */ char print_buf[256] = {0}; char chr[8] = {0}; @@ -718,7 +721,7 @@ void eeprom_read_all() kfree(buf); eeprom_poweroff(); - if (retry < 0) + if(retry<0) pr_debug("eeprom error"); } @@ -734,13 +737,15 @@ void eeprom_erase_all() memset(buf, 0xff, 128); for (i = 0; i < 512; i++) { /* clear all EEPROM */ pr_debug("ERASE [0x%04x]\n", i * 128); - do { + do + { err = wimax_i2c_write(128 * i, buf, 128); - } while (err < 0 ? ((retry--) > 0) : 0); + } + while(err<0?((retry--)>0):0); } eeprom_poweroff(); - if (retry < 0) + if(retry<0) pr_debug("eeprom error"); } @@ -762,28 +767,28 @@ int eeprom_write_boot(void) g_wimax_image.offset = 0; while (g_wimax_image.size > g_wimax_image.offset) { - buffer = (u_char *)(g_wimax_image.data + g_wimax_image.offset); + buffer =(u_char *)(g_wimax_image.data + g_wimax_image.offset); ucsize = MAX_BOOT_WRITE_LENGTH; /* write buffer */ - do { - err = wimax_i2c_write( - (u_short)g_wimax_image.offset, buffer, ucsize); - } while (err < 0 ? ((retry--) > 0) : 0); + do + { + err = wimax_i2c_write((u_short)g_wimax_image.offset, buffer, ucsize); + } + while(err<0?((retry--)>0):0); g_wimax_image.offset += MAX_BOOT_WRITE_LENGTH; - if ((g_wimax_image.size - g_wimax_image.offset) - < MAX_BOOT_WRITE_LENGTH) { - buffer = (u_char *)(g_wimax_image.data + - g_wimax_image.offset); + if ((g_wimax_image.size - g_wimax_image.offset) < MAX_BOOT_WRITE_LENGTH) { + buffer = (u_char *)(g_wimax_image.data + g_wimax_image.offset); ucsize = g_wimax_image.size - g_wimax_image.offset; /* write last data */ - do { - err = wimax_i2c_write( - (u_short)g_wimax_image.offset, buffer, ucsize); - } while (err < 0 ? ((retry--) > 0) : 0); + do + { + err = wimax_i2c_write((u_short)g_wimax_image.offset, buffer, ucsize); + } + while(err<0?((retry--)>0):0); g_wimax_image.offset += MAX_BOOT_WRITE_LENGTH; } @@ -796,12 +801,12 @@ int eeprom_write_boot(void) vfree(g_wimax_image.data); g_wimax_image.data = NULL; } - - if (retry < 0) + if(retry<0) + { pr_debug("eeprom error"); - else - pr_debug("EEPROM WRITING DONE."); - + }else{ + pr_debug("EEPROM WRITING DONE."); +} return err; } diff --git a/drivers/net/wimax_cmc/wimax_i2c.h b/drivers/net/wimax_cmc/wimax_i2c.h index cadd762..dc4fd3b 100644..100755 --- a/drivers/net/wimax_cmc/wimax_i2c.h +++ b/drivers/net/wimax_cmc/wimax_i2c.h @@ -5,6 +5,7 @@ */ #ifndef __WIMAX_I2C_H__ #define __WIMAX_I2C_H__ +//#define DRIVER_BIT_BANG #include <linux/mutex.h> #define WIMAX_BOOTIMAGE_PATH "/system/etc/wimax_boot.bin" diff --git a/drivers/net/wimax_cmc/wimax_plat.h b/drivers/net/wimax_cmc/wimax_plat.h new file mode 100755 index 0000000..b71f055 --- /dev/null +++ b/drivers/net/wimax_cmc/wimax_plat.h @@ -0,0 +1,36 @@ +/** + * wimax_plat.h + * + * GPIO settings for specific HW + */ +#ifndef __WIMAX_PLAT_H__ +#define __WIMAX_PLAT_H__ + +#define WIMAX_EN GPIO_WIMAX_EN +#define WIMAX_RESET GPIO_WIMAX_RESET_N +#define WIMAX_USB_EN GPIO_WIMAX_USB_EN + +#define DEVICE_HSMMC s3c_device_hsmmc3 + +#define WIMAX_WAKEUP GPIO_WIMAX_WAKEUP +#define WIMAX_IF_MODE0 GPIO_WIMAX_IF_MODE0 +#define WIMAX_IF_MODE1 GPIO_WIMAX_IF_MODE1 +#define WIMAX_CON0 GPIO_WIMAX_CON0 +#define WIMAX_CON1 GPIO_WIMAX_CON1 +#define WIMAX_CON2 GPIO_WIMAX_CON2 +#define WIMAX_INT GPIO_WIMAX_INT + +#define I2C_SEL GPIO_WIMAX_I2C_CON +#define EEPROM_SCL GPIO_CMC_SCL_18V +#define EEPROM_SDA GPIO_CMC_SDA_18V + +#define UART_SEL1 GPIO_UART_SEL1 +#define UART_SEL GPIO_UART_SEL +#if defined(CONFIG_MACH_C1_REV02) +#define USB_SEL GPIO_USB_SW_EN_WIMAX +#endif /* CONFIG_MACH_C1_REV02 */ +#define DBGEN GPIO_WIMAX_DBGEN_28V//TBD +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 +#define GPIO_LEVEL_NONE 2 +#endif /* __WIMAX_PLAT_H__ */ diff --git a/drivers/net/wimax_cmc/wimax_sdio.c b/drivers/net/wimax_cmc/wimax_sdio.c index ece4b04..7e57a29 100644..100755 --- a/drivers/net/wimax_cmc/wimax_sdio.c +++ b/drivers/net/wimax_cmc/wimax_sdio.c @@ -370,58 +370,60 @@ void control_recv(struct net_adapter *adapter, void *buffer, u32 length) mutex_unlock(&adapter->control_lock); } -void prepare_skb(struct net_adapter *adapter, struct sk_buff *rx_skb) +void prepare_skb(struct net_adapter *adapter, struct sk_buff *rx_skb ) { - skb_reserve(rx_skb, - (ETHERNET_ADDRESS_LENGTH * 2) + - NET_IP_ALIGN); + skb_reserve(rx_skb, + (ETHERNET_ADDRESS_LENGTH * 2) + + NET_IP_ALIGN); - memcpy(skb_push(rx_skb, - (ETHERNET_ADDRESS_LENGTH * 2)), - adapter->eth_header, - (ETHERNET_ADDRESS_LENGTH * 2)); + memcpy(skb_push(rx_skb, + (ETHERNET_ADDRESS_LENGTH * 2)), + adapter->eth_header, + (ETHERNET_ADDRESS_LENGTH * 2)); - rx_skb->dev = adapter->net; - rx_skb->ip_summed = CHECKSUM_UNNECESSARY; + rx_skb->dev = adapter->net; + rx_skb->ip_summed = CHECKSUM_UNNECESSARY; } void flush_skb(struct net_adapter *adapter) { - if (adapter->rx_skb) { - dev_kfree_skb(adapter->rx_skb); - adapter->rx_skb = NULL; - } + if (adapter->rx_skb) { + dev_kfree_skb(adapter->rx_skb); + adapter->rx_skb = NULL; + } } struct sk_buff *fetch_skb(struct net_adapter *adapter) { - struct sk_buff *ret_skb; - if (adapter->rx_skb) { - ret_skb = adapter->rx_skb; - adapter->rx_skb = NULL; - return ret_skb; - } - ret_skb = dev_alloc_skb(WIMAX_MTU_SIZE+2+ - (ETHERNET_ADDRESS_LENGTH * 2) + - NET_IP_ALIGN); - if (!ret_skb) { - pr_debug("unable to allocate skb"); - return NULL; - } - prepare_skb(adapter, ret_skb); - return ret_skb; + struct sk_buff *ret_skb; + if (adapter->rx_skb) + { + ret_skb = adapter->rx_skb; + adapter->rx_skb = NULL; + return ret_skb; + } + ret_skb = dev_alloc_skb(WIMAX_MTU_SIZE+2+ + (ETHERNET_ADDRESS_LENGTH * 2) + + NET_IP_ALIGN); + if (!ret_skb) { + pr_debug("unable to allocate skb"); + return NULL; + } + prepare_skb(adapter, ret_skb); + return ret_skb; } void pull_skb(struct net_adapter *adapter) { - struct sk_buff *t_skb; - if (adapter->rx_skb == NULL) { - t_skb = dev_alloc_skb(WIMAX_MTU_SIZE+2+ - (ETHERNET_ADDRESS_LENGTH * 2) + - NET_IP_ALIGN); - if (!t_skb) { - pr_debug("unable to allocate skb"); - return; - } - prepare_skb(adapter, t_skb); - adapter->rx_skb = t_skb; + struct sk_buff *t_skb; + if (adapter->rx_skb == NULL) + { + t_skb = dev_alloc_skb(WIMAX_MTU_SIZE+2+ + (ETHERNET_ADDRESS_LENGTH * 2) + + NET_IP_ALIGN); + if (!t_skb) { + pr_debug("unable to allocate skb"); + return; + } + prepare_skb(adapter, t_skb); + adapter->rx_skb = t_skb; } } @@ -497,8 +499,7 @@ static void adapter_rx_packet(struct net_adapter *adapter) } } else { rx_skb = dev_alloc_skb(hdr->length + - (ETHERNET_ADDRESS_LENGTH * 2) + - NET_IP_ALIGN); + (ETHERNET_ADDRESS_LENGTH * 2) + NET_IP_ALIGN); if (!rx_skb) { pr_err("unable to allocate skb"); break; @@ -1087,7 +1088,7 @@ int con0_poll_thread(void *data) wake_lock(&g_cfg->wimax_driver_lock); - while ((g_cfg->power_state != CMC_POWERING_OFF) && + while ((g_cfg->power_state != CMC_POWERING_OFF) && (g_cfg->power_state != CMC_POWER_OFF)) { curr_val = adapter->pdata->is_modem_awake(); if ((prev_val && (!curr_val)) || (!curr_val)) { @@ -1096,9 +1097,8 @@ int con0_poll_thread(void *data) } prev_val = curr_val; wait_event_interruptible_timeout(adapter->con0_poll, - (g_cfg->power_state == CMC_POWERING_OFF) || - (g_cfg->power_state == CMC_POWER_OFF), - msecs_to_jiffies(40)); + (g_cfg->power_state == CMC_POWERING_OFF) || + (g_cfg->power_state == CMC_POWER_OFF), msecs_to_jiffies(40)); } wake_unlock(&g_cfg->wimax_driver_lock); do_exit(0); @@ -1227,9 +1227,8 @@ static int wimax_power_on(struct wimax732_platform_data *pdata) init_waitqueue_head(&adapter->modem_resp_event); count = 0; - while (!adapter->modem_resp) { - /*This command will start the - firmware download sequence through sdio*/ + while(!adapter->modem_resp) { + /*This command will start the firmware download sequence through sdio*/ send_cmd_packet(adapter, MSG_DRIVER_OK_REQ); ret = wait_event_interruptible_timeout( adapter->modem_resp_event, @@ -1282,7 +1281,7 @@ static int wimax_power_on(struct wimax732_platform_data *pdata) goto mac_request_fail; ret = wait_for_completion_interruptible_timeout( &adapter->mac, - msecs_to_jiffies((MAC_RETRY_COUNT - count) * + msecs_to_jiffies((MAC_RETRY_COUNT - count) * MAC_RETRY_INTERVAL)); if (ret == -ERESTARTSYS) { pr_err("-ERESTARTSYS MAC request fail"); @@ -1297,7 +1296,7 @@ static int wimax_power_on(struct wimax732_platform_data *pdata) adapter->wtm_task = kthread_create(con0_poll_thread, adapter, "%s", "wimax_con0_poll_thread"); if (adapter->wtm_task) - wake_up_process(adapter->wtm_task); + wake_up_process(adapter->wtm_task); } #endif adapter->uwibro_dev.minor = MISC_DYNAMIC_MINOR; @@ -1436,8 +1435,9 @@ static int wimax_power_off(struct wimax732_platform_data *pdata) adapter = (struct net_adapter *) pdata->adapter_data; g_cfg->power_state = CMC_POWERING_OFF; #ifdef WIMAX_CON0_POLL - if (g_cfg->wimax_mode == WTM_MODE) + if (g_cfg->wimax_mode == WTM_MODE) { wake_up_interruptible(&adapter->con0_poll); + } #endif cmc732_release_wake_irq(adapter); @@ -1565,14 +1565,14 @@ static long swmxdev_ioctl(struct file *file, u32 cmd, ret = eeprom_write_rev(); break; } - case CONTROL_IOCTL_WIMAX_CHECK_CERT: { + case CONTROL_IOCTL_WIMAX_CHECK_CERT: { pr_debug("CONTROL_IOCTL_WIMAX_CHECK_CERT"); wimax_power_off(gpdata); ret = eeprom_check_cert(); break; } case CONTROL_IOCTL_WIMAX_CHECK_CAL: { - pr_debug("CONTROL_IOCTL_WIMAX_CHECK_CAL"); + pr_debug("CONTROL_IOCTL_WIMAX_CHECK_CAL"); wimax_power_off(gpdata); ret = eeprom_check_cal(); break; diff --git a/drivers/net/wimax_cmc/wimax_sdio.h b/drivers/net/wimax_cmc/wimax_sdio.h index 998c695..46e81cb 100644..100755 --- a/drivers/net/wimax_cmc/wimax_sdio.h +++ b/drivers/net/wimax_cmc/wimax_sdio.h @@ -246,8 +246,8 @@ struct net_adapter { struct task_struct *wtm_task; #endif struct sk_buff *rx_skb; - u8 *receive_buffer; - u32 buff_len; + u8 *receive_buffer; + u32 buff_len; u32 image_offset; u32 msg_enable; s32 wake_irq; |