2 * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/uaccess.h>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
18 #include <linux/usb.h>
19 #include <linux/unistd.h>
20 #include <linux/slab.h>
21 #include <linux/firmware.h>
23 #include <asm/byteorder.h>
27 #define DN_KERNEL_MAGIC_NUMBER 0x10760001
28 #define DN_ROOTFS_MAGIC_NUMBER 0x10760002
30 #define DOWNLOAD_SIZE 1024
32 #define MAX_IMG_CNT 16
33 #define FW_DIR "gdm72xx/"
34 #define FW_UIMG "gdmuimg.bin"
35 #define FW_KERN "zImage"
36 #define FW_FS "ramdisk.jffs2"
47 u32 offset
[MAX_IMG_CNT
];
67 static void array_le32_to_cpu(u32
*arr
, int num
)
70 for (i
= 0; i
< num
; i
++, arr
++)
71 *arr
= __le32_to_cpu(*arr
);
76 static int gdm_wibro_send(struct usb_device
*usbdev
, void *data
, int len
)
81 ret
= usb_bulk_msg(usbdev
, usb_sndbulkpipe(usbdev
, 1), data
, len
,
85 printk(KERN_ERR
"Error : usb_bulk_msg ( result = %d )\n", ret
);
91 static int gdm_wibro_recv(struct usb_device
*usbdev
, void *data
, int len
)
96 ret
= usb_bulk_msg(usbdev
, usb_rcvbulkpipe(usbdev
, 2), data
, len
,
100 printk(KERN_ERR
"Error : usb_bulk_msg(recv) ( result = %d )\n",
107 static int download_image(struct usb_device
*usbdev
,
108 const struct firmware
*firm
,
109 loff_t pos
, u32 img_len
, u32 magic_num
)
115 size
= ALIGN(img_len
, DOWNLOAD_SIZE
);
116 h
.magic_num
= __cpu_to_be32(magic_num
);
117 h
.file_size
= __cpu_to_be32(size
);
119 ret
= gdm_wibro_send(usbdev
, &h
, sizeof(h
));
123 while (img_len
> 0) {
124 if (img_len
> DOWNLOAD_SIZE
)
125 size
= DOWNLOAD_SIZE
;
127 size
= img_len
; /* the last chunk of data */
129 memcpy(tx_buf
, firm
->data
+ pos
, size
);
130 ret
= gdm_wibro_send(usbdev
, tx_buf
, size
);
142 int usb_boot(struct usb_device
*usbdev
, u16 pid
)
145 struct img_header hdr
;
146 struct fw_info fw_info
;
148 char *img_name
= FW_DIR FW_UIMG
;
149 const struct firmware
*firm
;
151 ret
= request_firmware(&firm
, img_name
, &usbdev
->dev
);
154 "requesting firmware %s failed with error %d\n",
159 tx_buf
= kmalloc(DOWNLOAD_SIZE
, GFP_KERNEL
);
160 if (tx_buf
== NULL
) {
161 printk(KERN_ERR
"Error: kmalloc\n");
165 if (firm
->size
< sizeof(hdr
)) {
166 printk(KERN_ERR
"gdmwm: Cannot read the image info.\n");
170 memcpy(&hdr
, firm
->data
, sizeof(hdr
));
172 array_le32_to_cpu((u32
*)&hdr
, 19);
174 if (hdr
.magic_code
!= 0x10767fff) {
175 printk(KERN_ERR
"gdmwm: Invalid magic code 0x%08x\n",
181 if (hdr
.count
> MAX_IMG_CNT
) {
182 printk(KERN_ERR
"gdmwm: Too many images. %d\n", hdr
.count
);
187 for (i
= 0; i
< hdr
.count
; i
++) {
188 if (hdr
.offset
[i
] > hdr
.len
) {
189 printk(KERN_ERR
"gdmwm: Invalid offset. "
190 "Entry = %d Offset = 0x%08x "
191 "Image length = 0x%08x\n",
192 i
, hdr
.offset
[i
], hdr
.len
);
198 if (firm
->size
< sizeof(fw_info
) + pos
) {
199 printk(KERN_ERR
"gdmwm: Cannot read the FW info.\n");
203 memcpy(&fw_info
, firm
->data
+ pos
, sizeof(fw_info
));
205 array_le32_to_cpu((u32
*)&fw_info
, 8);
207 if ((fw_info
.id
& 0xfffff000) != 0x10767000) {
208 printk(KERN_ERR
"gdmwm: Invalid FW id. 0x%08x\n",
215 if ((fw_info
.id
& 0xffff) != pid
)
218 pos
= hdr
.offset
[i
] + fw_info
.kernel_offset
;
219 if (firm
->size
< fw_info
.kernel_len
+ pos
) {
220 printk(KERN_ERR
"gdmwm: Kernel FW is too small.\n");
224 ret
= download_image(usbdev
, firm
, pos
,
225 fw_info
.kernel_len
, DN_KERNEL_MAGIC_NUMBER
);
228 printk(KERN_INFO
"GCT: Kernel download success.\n");
230 pos
= hdr
.offset
[i
] + fw_info
.rootfs_offset
;
231 if (firm
->size
< fw_info
.rootfs_len
+ pos
) {
232 printk(KERN_ERR
"gdmwm: Filesystem FW is too small.\n");
235 ret
= download_image(usbdev
, firm
, pos
, fw_info
.rootfs_len
,
236 DN_ROOTFS_MAGIC_NUMBER
);
239 printk(KERN_INFO
"GCT: Filesystem download success.\n");
244 if (i
== hdr
.count
) {
245 printk(KERN_ERR
"Firmware for gsk%x is not installed.\n", pid
);
249 release_firmware(firm
);
254 /*#define GDM7205_PADDING 256 */
255 #define DOWNLOAD_CHUCK 2048
256 #define KERNEL_TYPE_STRING "linux"
257 #define FS_TYPE_STRING "rootfs"
259 static int em_wait_ack(struct usb_device
*usbdev
, int send_zlp
)
266 ret
= gdm_wibro_send(usbdev
, NULL
, 0);
272 ret
= gdm_wibro_recv(usbdev
, &ack
, sizeof(ack
));
279 static int em_download_image(struct usb_device
*usbdev
, const char *img_name
,
287 const struct firmware
*firm
;
288 #if defined(GDM7205_PADDING)
289 const int pad_size
= GDM7205_PADDING
;
291 const int pad_size
= 0;
294 ret
= request_firmware(&firm
, img_name
, &usbdev
->dev
);
297 "requesting firmware %s failed with error %d\n",
302 buf
= kmalloc(DOWNLOAD_CHUCK
+ pad_size
, GFP_KERNEL
);
304 printk(KERN_ERR
"Error: kmalloc\n");
308 strcpy(buf
+pad_size
, type_string
);
309 ret
= gdm_wibro_send(usbdev
, buf
, strlen(type_string
)+pad_size
);
313 img_len
= firm
->size
;
320 while (img_len
> 0) {
321 if (img_len
> DOWNLOAD_CHUCK
)
322 len
= DOWNLOAD_CHUCK
;
324 len
= img_len
; /* the last chunk of data */
326 memcpy(buf
+pad_size
, firm
->data
+ pos
, len
);
327 ret
= gdm_wibro_send(usbdev
, buf
, len
+pad_size
);
332 img_len
-= DOWNLOAD_CHUCK
;
333 pos
+= DOWNLOAD_CHUCK
;
335 ret
= em_wait_ack(usbdev
, ((len
+pad_size
) % 512 == 0));
340 ret
= em_wait_ack(usbdev
, 1);
345 release_firmware(firm
);
351 static int em_fw_reset(struct usb_device
*usbdev
)
356 ret
= gdm_wibro_send(usbdev
, NULL
, 0);
360 int usb_emergency(struct usb_device
*usbdev
)
363 const char *kern_name
= FW_DIR FW_KERN
;
364 const char *fs_name
= FW_DIR FW_FS
;
366 ret
= em_download_image(usbdev
, kern_name
, KERNEL_TYPE_STRING
);
369 printk(KERN_INFO
"GCT Emergency: Kernel download success.\n");
371 ret
= em_download_image(usbdev
, fs_name
, FS_TYPE_STRING
);
374 printk(KERN_INFO
"GCT Emergency: Filesystem download success.\n");
376 ret
= em_fw_reset(usbdev
);
This page took 0.064432 seconds and 5 git commands to generate.