diff options
Diffstat (limited to 'drivers/net/wimax/cmc7xx/download.c')
-rwxr-xr-x | drivers/net/wimax/cmc7xx/download.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/drivers/net/wimax/cmc7xx/download.c b/drivers/net/wimax/cmc7xx/download.c new file mode 100755 index 0000000..7e9e3bc --- /dev/null +++ b/drivers/net/wimax/cmc7xx/download.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * 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 "headers.h" +#include "download.h" + +#include <linux/firmware.h> +#include <linux/vmalloc.h> + +int load_wimax_image(int mode, struct net_adapter *adapter) +{ + const struct firmware *fw = NULL; + int ret = STATUS_SUCCESS; + struct device *dev; + + if (!adapter || !adapter->func) { + pr_err("%s: device is NULL, can't load firmware\n", __func__); + return STATUS_UNSUCCESSFUL; + } + + dev = &adapter->func->dev; + + if (request_firmware(&fw, (mode == AUTH_MODE) ? + WIMAX_LOADER_PATH : WIMAX_IMAGE_PATH, dev)) { + dev_err(dev, "%s: Can't open firmware file\n", __func__); + return STATUS_UNSUCCESSFUL; + } + + if (adapter->wimax_image.data && adapter->wimax_image.size < fw->size) { + vfree(adapter->wimax_image.data); + adapter->wimax_image.data = NULL; + } + + if (!adapter->wimax_image.data) + adapter->wimax_image.data = vmalloc(fw->size); + + if (!adapter->wimax_image.data) { + dev_err(dev, "%s: Can't allocate %d bytes of memory for " + "firmware\n", __func__, fw->size); + ret = STATUS_UNSUCCESSFUL; + goto err_vmalloc; + } + memcpy(adapter->wimax_image.data, fw->data, fw->size); + + adapter->wimax_image.size = fw->size; + adapter->wimax_image.address = CMC732_WIMAX_ADDRESS; + adapter->wimax_image.offset = 0; + +err_vmalloc: + release_firmware(fw); + return ret; +} + +void unload_wimax_image(struct net_adapter *adapter) +{ + if (adapter->wimax_image.data == NULL) + return; + + pr_debug("Delete the Image Loaded"); + vfree(adapter->wimax_image.data); + adapter->wimax_image.data = NULL; +} + +u8 send_cmd_packet(struct net_adapter *adapter, u16 cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct wimax_msg_header *msg_hdr; + u8 tx_buf[CMD_MSG_TOTAL_LENGTH]; + int status = 0; + u32 offset; + u32 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 */ + pr_debug("hwSdioWrite : crc or data error"); + return status; + } + return status; +} + +u8 send_image_info_packet(struct net_adapter *adapter, u16 cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct wimax_msg_header *msg_hdr; + u32 image_info[4]; + u8 tx_buf[IMAGE_INFO_MSG_TOTAL_LENGTH]; + int status; + u32 offset; + u32 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(adapter->wimax_image.size); + image_info[2] = be32_to_cpu(adapter->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 + */ + pr_debug("hwSdioWrite : crc error"); + return status; + } + return status; +} + +u8 send_image_data_packet(struct net_adapter *adapter, u16 cmd_id) +{ + struct hw_packet_header *pkt_hdr; + struct image_data_payload *pImageDataPayload; + struct wimax_msg_header *msg_hdr; + u8 *tx_buf = NULL; + int status; + u32 len; + u32 offset; + u32 size; + + tx_buf = kmalloc(MAX_IMAGE_DATA_MSG_LENGTH, GFP_KERNEL); + if (tx_buf == NULL) { + pr_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 (adapter->wimax_image.offset < + (adapter->wimax_image.size - MAX_IMAGE_DATA_LENGTH)) + len = MAX_IMAGE_DATA_LENGTH; + else + len = adapter->wimax_image.size - adapter->wimax_image.offset; + + offset += sizeof(struct wimax_msg_header); + pImageDataPayload = (struct image_data_payload *)(tx_buf + offset); + pImageDataPayload->offset = be32_to_cpu(adapter->wimax_image.offset); + pImageDataPayload->size = be32_to_cpu(len); + + memcpy(pImageDataPayload->data, + adapter->wimax_image.data + adapter->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 + */ + pr_debug("hwSdioWrite : crc error"); + kfree(tx_buf); + return status; + } + + adapter->wimax_image.offset += len; + + kfree(tx_buf); + + return status; +} + |