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>
22 #include <asm/byteorder.h>
26 #define DN_KERNEL_MAGIC_NUMBER 0x10760001
27 #define DN_ROOTFS_MAGIC_NUMBER 0x10760002
29 #define DOWNLOAD_SIZE 1024
31 #define DH2B(x) __cpu_to_be32(x)
32 #define DL2H(x) __le32_to_cpu(x)
34 #define MIN(a, b) ((a) > (b) ? (b) : (a))
36 #define MAX_IMG_CNT 16
37 #define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin"
38 #define KERN_PATH "/lib/firmware/gdm72xx/zImage"
39 #define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2"
50 u32 offset
[MAX_IMG_CNT
];
70 static void array_le32_to_cpu(u32
*arr
, int num
)
73 for (i
= 0; i
< num
; i
++, arr
++)
79 static int gdm_wibro_send(struct usb_device
*usbdev
, void *data
, int len
)
84 ret
= usb_bulk_msg(usbdev
, usb_sndbulkpipe(usbdev
, 1), data
, len
,
88 printk(KERN_ERR
"Error : usb_bulk_msg ( result = %d )\n", ret
);
94 static int gdm_wibro_recv(struct usb_device
*usbdev
, void *data
, int len
)
99 ret
= usb_bulk_msg(usbdev
, usb_rcvbulkpipe(usbdev
, 2), data
, len
,
103 printk(KERN_ERR
"Error : usb_bulk_msg(recv) ( result = %d )\n",
110 static int download_image(struct usb_device
*usbdev
, struct file
*filp
,
111 loff_t
*pos
, u32 img_len
, u32 magic_num
)
118 size
= (img_len
+ DOWNLOAD_SIZE
- 1) & ~(DOWNLOAD_SIZE
- 1);
119 h
.magic_num
= DH2B(magic_num
);
120 h
.file_size
= DH2B(size
);
122 ret
= gdm_wibro_send(usbdev
, &h
, sizeof(h
));
127 while ((len
= filp
->f_op
->read(filp
, tx_buf
, DOWNLOAD_SIZE
, pos
))) {
135 ret
= gdm_wibro_send(usbdev
, tx_buf
, DOWNLOAD_SIZE
);
138 if (readn
>= img_len
)
142 if (readn
< img_len
) {
143 printk(KERN_ERR
"gdmwm: Cannot read to the requested size. "
144 "Read = %d Requested = %d\n", readn
, img_len
);
152 int usb_boot(struct usb_device
*usbdev
, u16 pid
)
155 struct file
*filp
= NULL
;
156 struct inode
*inode
= NULL
;
157 static mm_segment_t fs
;
158 struct img_header hdr
;
159 struct fw_info fw_info
;
161 char *img_name
= UIMG_PATH
;
164 tx_buf
= kmalloc(DOWNLOAD_SIZE
, GFP_KERNEL
);
165 if (tx_buf
== NULL
) {
166 printk(KERN_ERR
"Error: kmalloc\n");
173 filp
= filp_open(img_name
, O_RDONLY
| O_LARGEFILE
, 0);
175 printk(KERN_ERR
"Can't find %s.\n", img_name
);
182 inode
= filp
->f_dentry
->d_inode
;
183 if (!inode
|| !S_ISREG(inode
->i_mode
)) {
184 printk(KERN_ERR
"Invalid file type: %s\n", img_name
);
189 len
= filp
->f_op
->read(filp
, (u8
*)&hdr
, sizeof(hdr
), &pos
);
190 if (len
!= sizeof(hdr
)) {
191 printk(KERN_ERR
"gdmwm: Cannot read the image info.\n");
196 array_le32_to_cpu((u32
*)&hdr
, 19);
198 if (hdr
.magic_code
!= 0x10767fff) {
199 printk(KERN_ERR
"gdmwm: Invalid magic code 0x%08x\n",
205 if (hdr
.count
> MAX_IMG_CNT
) {
206 printk(KERN_ERR
"gdmwm: Too many images. %d\n", hdr
.count
);
211 for (i
= 0; i
< hdr
.count
; i
++) {
212 if (hdr
.offset
[i
] > hdr
.len
) {
213 printk(KERN_ERR
"gdmwm: Invalid offset. "
214 "Entry = %d Offset = 0x%08x "
215 "Image length = 0x%08x\n",
216 i
, hdr
.offset
[i
], hdr
.len
);
222 len
= filp
->f_op
->read(filp
, (u8
*)&fw_info
, sizeof(fw_info
),
224 if (len
!= sizeof(fw_info
)) {
225 printk(KERN_ERR
"gdmwm: Cannot read the FW info.\n");
230 array_le32_to_cpu((u32
*)&fw_info
, 8);
232 if ((fw_info
.id
& 0xfffff000) != 0x10767000) {
233 printk(KERN_ERR
"gdmwm: Invalid FW id. 0x%08x\n",
240 if ((fw_info
.id
& 0xffff) != pid
)
243 pos
= hdr
.offset
[i
] + fw_info
.kernel_offset
;
244 ret
= download_image(usbdev
, filp
, &pos
, fw_info
.kernel_len
,
245 DN_KERNEL_MAGIC_NUMBER
);
248 printk(KERN_INFO
"GCT: Kernel download success.\n");
250 pos
= hdr
.offset
[i
] + fw_info
.rootfs_offset
;
251 ret
= download_image(usbdev
, filp
, &pos
, fw_info
.rootfs_len
,
252 DN_ROOTFS_MAGIC_NUMBER
);
255 printk(KERN_INFO
"GCT: Filesystem download success.\n");
260 if (i
== hdr
.count
) {
261 printk(KERN_ERR
"Firmware for gsk%x is not installed.\n", pid
);
265 filp_close(filp
, current
->files
);
273 /*#define GDM7205_PADDING 256 */
274 #define DOWNLOAD_CHUCK 2048
275 #define KERNEL_TYPE_STRING "linux"
276 #define FS_TYPE_STRING "rootfs"
278 static int em_wait_ack(struct usb_device
*usbdev
, int send_zlp
)
285 ret
= gdm_wibro_send(usbdev
, NULL
, 0);
291 ret
= gdm_wibro_recv(usbdev
, &ack
, sizeof(ack
));
298 static int em_download_image(struct usb_device
*usbdev
, char *path
,
303 static mm_segment_t fs
;
308 #if defined(GDM7205_PADDING)
309 const int pad_size
= GDM7205_PADDING
;
311 const int pad_size
= 0;
317 filp
= filp_open(path
, O_RDONLY
| O_LARGEFILE
, 0);
319 printk(KERN_ERR
"Can't find %s.\n", path
);
325 if (filp
->f_dentry
) {
326 inode
= filp
->f_dentry
->d_inode
;
327 if (!inode
|| !S_ISREG(inode
->i_mode
)) {
328 printk(KERN_ERR
"Invalid file type: %s\n", path
);
334 buf
= kmalloc(DOWNLOAD_CHUCK
+ pad_size
, GFP_KERNEL
);
336 printk(KERN_ERR
"Error: kmalloc\n");
340 strcpy(buf
+pad_size
, type_string
);
341 ret
= gdm_wibro_send(usbdev
, buf
, strlen(type_string
)+pad_size
);
345 while ((len
= filp
->f_op
->read(filp
, buf
+pad_size
, DOWNLOAD_CHUCK
,
353 ret
= gdm_wibro_send(usbdev
, buf
, len
+pad_size
);
357 ret
= em_wait_ack(usbdev
, ((len
+pad_size
) % 512 == 0));
362 ret
= em_wait_ack(usbdev
, 1);
367 filp_close(filp
, current
->files
);
377 static int em_fw_reset(struct usb_device
*usbdev
)
382 ret
= gdm_wibro_send(usbdev
, NULL
, 0);
386 int usb_emergency(struct usb_device
*usbdev
)
390 ret
= em_download_image(usbdev
, KERN_PATH
, KERNEL_TYPE_STRING
);
393 printk(KERN_INFO
"GCT Emergency: Kernel download success.\n");
395 ret
= em_download_image(usbdev
, FS_PATH
, FS_TYPE_STRING
);
398 printk(KERN_INFO
"GCT Emergency: Filesystem download success.\n");
400 ret
= em_fw_reset(usbdev
);
This page took 0.061013 seconds and 5 git commands to generate.