ramips: add support for Fon FON2601
FON2601 is a wireless router.
Specification:
- SoC: Mediatek MT7620A (580MHz)
- RAM: 128 MiB
- ROM: 16 MiB SPI Flash
- Wireless:
   for 11b/g/n (upto 300 Mbps):  MT7620A built-in WMAC
   for 11a/n/ac (upto 867 Mbps): MT7662E
- Ethernet LAN: 1 port, upto 100 Mbps
- Ethernet WAN: 1 port, upto 1000 Mbps
- USB: 1 port (USB 2.0 host)
- LEDs: 4 (all can be controlled by SoC's GPIO)
- buttons: 1 (Displayed as "WPS" on enclosure)
- serial port: 57600n8
 pins: Vcc(3.3V), Rx, Tx, GND
(left to right, viewed from outside of board)
Installation (only available via UART):
  1. download sysupgrade binary image by wget command
  2. write sysupgrade binary image to Flash
     command is:
       mtd write sysupgrade.bin firmware
  3. reboot
Important Notice:
  Only one button is displayed as "WPS" on enclosure.
  However, it is configured as "reset" (factory resetting feature).
Signed-off-by: NOGUCHI Hiroshi <drvlabo@gmail.com>
[removed unrelated openwrt-keyring revert, missing -Wall for uimage_padhdr]
Signed-off-by: Petr Štetiar <ynezz@true.cz>
			
			
This commit is contained in:
		 NOGUCHI Hiroshi
					NOGUCHI Hiroshi
				
			
				
					committed by
					
						 Petr Štetiar
						Petr Štetiar
					
				
			
			
				
	
			
			
			 Petr Štetiar
						Petr Štetiar
					
				
			
						parent
						
							5cf897779e
						
					
				
				
					commit
					a1c6a316d2
				
			| @@ -24,9 +24,9 @@ | |||||||
|  |  | ||||||
| /* | /* | ||||||
|  * uimage_header itself is only 64B, but it may be prepended with another data. |  * uimage_header itself is only 64B, but it may be prepended with another data. | ||||||
|  * Currently the biggest size is for Edimax devices: 20B + 64B |  * Currently the biggest size is for Fon(Foxconn) devices: 64B + 32B | ||||||
|  */ |  */ | ||||||
| #define MAX_HEADER_LEN		84 | #define MAX_HEADER_LEN		96 | ||||||
|  |  | ||||||
| #define IH_MAGIC	0x27051956	/* Image Magic Number		*/ | #define IH_MAGIC	0x27051956	/* Image Magic Number		*/ | ||||||
| #define IH_NMLEN		32	/* Image Name Length		*/ | #define IH_NMLEN		32	/* Image Name Length		*/ | ||||||
| @@ -80,12 +80,12 @@ read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, | |||||||
|  * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts |  * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts | ||||||
|  * |  * | ||||||
|  * @find_header: function to call for a block of data that will return offset |  * @find_header: function to call for a block of data that will return offset | ||||||
|  *      of a valid uImage header if found |  *      and tail padding length of a valid uImage header if found | ||||||
|  */ |  */ | ||||||
| static int __mtdsplit_parse_uimage(struct mtd_info *master, | static int __mtdsplit_parse_uimage(struct mtd_info *master, | ||||||
| 		   const struct mtd_partition **pparts, | 		   const struct mtd_partition **pparts, | ||||||
| 		   struct mtd_part_parser_data *data, | 		   struct mtd_part_parser_data *data, | ||||||
| 				   ssize_t (*find_header)(u_char *buf, size_t len)) | 		   ssize_t (*find_header)(u_char *buf, size_t len, int *extralen)) | ||||||
| { | { | ||||||
| 	struct mtd_partition *parts; | 	struct mtd_partition *parts; | ||||||
| 	u_char *buf; | 	u_char *buf; | ||||||
| @@ -97,6 +97,7 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, | |||||||
| 	size_t rootfs_size = 0; | 	size_t rootfs_size = 0; | ||||||
| 	int uimage_part, rf_part; | 	int uimage_part, rf_part; | ||||||
| 	int ret; | 	int ret; | ||||||
|  | 	int extralen; | ||||||
| 	enum mtdsplit_part_type type; | 	enum mtdsplit_part_type type; | ||||||
|  |  | ||||||
| 	nr_parts = 2; | 	nr_parts = 2; | ||||||
| @@ -120,7 +121,8 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, | |||||||
| 		if (ret) | 		if (ret) | ||||||
| 			continue; | 			continue; | ||||||
|  |  | ||||||
| 		ret = find_header(buf, MAX_HEADER_LEN); | 		extralen = 0; | ||||||
|  | 		ret = find_header(buf, MAX_HEADER_LEN, &extralen); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			pr_debug("no valid uImage found in \"%s\" at offset %llx\n", | 			pr_debug("no valid uImage found in \"%s\" at offset %llx\n", | ||||||
| 				 master->name, (unsigned long long) offset); | 				 master->name, (unsigned long long) offset); | ||||||
| @@ -128,7 +130,9 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, | |||||||
| 		} | 		} | ||||||
| 		header = (struct uimage_header *)(buf + ret); | 		header = (struct uimage_header *)(buf + ret); | ||||||
|  |  | ||||||
| 		uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size) + ret; | 		uimage_size = sizeof(*header) + | ||||||
|  | 				be32_to_cpu(header->ih_size) + ret + extralen; | ||||||
|  |  | ||||||
| 		if ((offset + uimage_size) > master->size) { | 		if ((offset + uimage_size) > master->size) { | ||||||
| 			pr_debug("uImage exceeds MTD device \"%s\"\n", | 			pr_debug("uImage exceeds MTD device \"%s\"\n", | ||||||
| 				 master->name); | 				 master->name); | ||||||
| @@ -206,7 +210,7 @@ err_free_parts: | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
| static ssize_t uimage_verify_default(u_char *buf, size_t len) | static ssize_t uimage_verify_default(u_char *buf, size_t len, int *extralen) | ||||||
| { | { | ||||||
| 	struct uimage_header *header = (struct uimage_header *)buf; | 	struct uimage_header *header = (struct uimage_header *)buf; | ||||||
|  |  | ||||||
| @@ -269,7 +273,7 @@ static struct mtd_part_parser uimage_generic_parser = { | |||||||
| #define FW_MAGIC_WNDR3700V2	0x33373031 | #define FW_MAGIC_WNDR3700V2	0x33373031 | ||||||
| #define FW_MAGIC_WPN824N	0x31313030 | #define FW_MAGIC_WPN824N	0x31313030 | ||||||
|  |  | ||||||
| static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len) | static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len, int *extralen) | ||||||
| { | { | ||||||
| 	struct uimage_header *header = (struct uimage_header *)buf; | 	struct uimage_header *header = (struct uimage_header *)buf; | ||||||
| 	uint8_t expected_type = IH_TYPE_FILESYSTEM; | 	uint8_t expected_type = IH_TYPE_FILESYSTEM; | ||||||
| @@ -332,7 +336,7 @@ static struct mtd_part_parser uimage_netgear_parser = { | |||||||
| #define FW_EDIMAX_OFFSET	20 | #define FW_EDIMAX_OFFSET	20 | ||||||
| #define FW_MAGIC_EDIMAX		0x43535953 | #define FW_MAGIC_EDIMAX		0x43535953 | ||||||
|  |  | ||||||
| static ssize_t uimage_find_edimax(u_char *buf, size_t len) | static ssize_t uimage_find_edimax(u_char *buf, size_t len, int *extralen) | ||||||
| { | { | ||||||
| 	u32 *magic; | 	u32 *magic; | ||||||
|  |  | ||||||
| @@ -345,7 +349,7 @@ static ssize_t uimage_find_edimax(u_char *buf, size_t len) | |||||||
| 	if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX) | 	if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  |  | ||||||
| 	if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len)) | 	if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len, extralen)) | ||||||
| 		return FW_EDIMAX_OFFSET; | 		return FW_EDIMAX_OFFSET; | ||||||
|  |  | ||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| @@ -377,6 +381,49 @@ static struct mtd_part_parser uimage_edimax_parser = { | |||||||
| 	.type = MTD_PARSER_TYPE_FIRMWARE, | 	.type = MTD_PARSER_TYPE_FIRMWARE, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /************************************************** | ||||||
|  |  * Fon(Foxconn) | ||||||
|  |  **************************************************/ | ||||||
|  |  | ||||||
|  | #define FONFXC_PAD_LEN		32 | ||||||
|  |  | ||||||
|  | static ssize_t uimage_find_fonfxc(u_char *buf, size_t len, int *extralen) | ||||||
|  | { | ||||||
|  | 	if (uimage_verify_default(buf, len, extralen) < 0) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	*extralen = FONFXC_PAD_LEN; | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | mtdsplit_uimage_parse_fonfxc(struct mtd_info *master, | ||||||
|  | 			      const struct mtd_partition **pparts, | ||||||
|  | 			      struct mtd_part_parser_data *data) | ||||||
|  | { | ||||||
|  | 	return __mtdsplit_parse_uimage(master, pparts, data, | ||||||
|  | 				       uimage_find_fonfxc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) | ||||||
|  | static const struct of_device_id mtdsplit_uimage_fonfxc_of_match_table[] = { | ||||||
|  | 	{ .compatible = "fonfxc,uimage" }, | ||||||
|  | 	{}, | ||||||
|  | }; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static struct mtd_part_parser uimage_fonfxc_parser = { | ||||||
|  | 	.owner = THIS_MODULE, | ||||||
|  | 	.name = "fonfxc-fw", | ||||||
|  | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) | ||||||
|  | 	.of_match_table = mtdsplit_uimage_fonfxc_of_match_table, | ||||||
|  | #endif | ||||||
|  | 	.parse_fn = mtdsplit_uimage_parse_fonfxc, | ||||||
|  | 	.type = MTD_PARSER_TYPE_FIRMWARE, | ||||||
|  | }; | ||||||
|  |  | ||||||
| /************************************************** | /************************************************** | ||||||
|  * Init |  * Init | ||||||
|  **************************************************/ |  **************************************************/ | ||||||
| @@ -386,6 +433,7 @@ static int __init mtdsplit_uimage_init(void) | |||||||
| 	register_mtd_parser(&uimage_generic_parser); | 	register_mtd_parser(&uimage_generic_parser); | ||||||
| 	register_mtd_parser(&uimage_netgear_parser); | 	register_mtd_parser(&uimage_netgear_parser); | ||||||
| 	register_mtd_parser(&uimage_edimax_parser); | 	register_mtd_parser(&uimage_edimax_parser); | ||||||
|  | 	register_mtd_parser(&uimage_fonfxc_parser); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -329,6 +329,10 @@ ramips_setup_interfaces() | |||||||
| 		ucidef_add_switch "switch1" \ | 		ucidef_add_switch "switch1" \ | ||||||
| 			"1:lan" "2:lan" "3:lan" "4:lan" "0:wan" "6@eth0" | 			"1:lan" "2:lan" "3:lan" "4:lan" "0:wan" "6@eth0" | ||||||
| 		;; | 		;; | ||||||
|  | 	fon,fon2601) | ||||||
|  | 		ucidef_add_switch "switch0" \ | ||||||
|  | 			"0:lan" "4:wan" "6@eth0" | ||||||
|  | 		;; | ||||||
| 	gehua,ghl-r-001) | 	gehua,ghl-r-001) | ||||||
| 		ucidef_add_switch "switch0" \ | 		ucidef_add_switch "switch0" \ | ||||||
| 			"0:lan" "1:lan" "2:lan" "4:wan" "6@eth0" | 			"0:lan" "1:lan" "2:lan" "4:wan" "6@eth0" | ||||||
|   | |||||||
							
								
								
									
										166
									
								
								target/linux/ramips/dts/mt7620a_fon_fon2601.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								target/linux/ramips/dts/mt7620a_fon_fon2601.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,166 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0 | ||||||
|  | /dts-v1/; | ||||||
|  |  | ||||||
|  | #include "mt7620a.dtsi" | ||||||
|  |  | ||||||
|  | #include <dt-bindings/gpio/gpio.h> | ||||||
|  | #include <dt-bindings/input/input.h> | ||||||
|  |  | ||||||
|  | / { | ||||||
|  | 	compatible = "fon,fon2601", "ralink,mt7620a-soc"; | ||||||
|  | 	model = "Fon FON2601"; | ||||||
|  |  | ||||||
|  | 	aliases { | ||||||
|  | 		led-boot = &led_power; | ||||||
|  | 		led-failsafe = &led_power; | ||||||
|  | 		led-running = &led_power; | ||||||
|  | 		led-upgrade = &led_power; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	leds { | ||||||
|  | 		compatible = "gpio-leds"; | ||||||
|  |  | ||||||
|  | 		led_power: power_r { | ||||||
|  | 			label = "fon2601:red:power"; | ||||||
|  | 			gpios = <&gpio0 9 GPIO_ACTIVE_LOW>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		internet_g { | ||||||
|  | 			label = "fon2601:green:internet"; | ||||||
|  | 			gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		net_g { | ||||||
|  | 			label = "fon2601:green:net"; | ||||||
|  | 			gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		wifi_g { | ||||||
|  | 			label = "fon2601:green:wifi"; | ||||||
|  | 			gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	keys { | ||||||
|  | 		compatible = "gpio-keys"; | ||||||
|  |  | ||||||
|  | 		reset { | ||||||
|  | 			label = "reset"; | ||||||
|  | 			gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; | ||||||
|  | 			linux,code = <KEY_RESTART>; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &spi0 { | ||||||
|  | 	status = "okay"; | ||||||
|  |  | ||||||
|  | 	flash@0 { | ||||||
|  | 		compatible = "jedec,spi-nor"; | ||||||
|  | 		reg = <0>; | ||||||
|  | 		spi-max-frequency = <10000000>; | ||||||
|  |  | ||||||
|  | 		partitions { | ||||||
|  | 			compatible = "fixed-partitions"; | ||||||
|  | 			#address-cells = <1>; | ||||||
|  | 			#size-cells = <1>; | ||||||
|  |  | ||||||
|  | 			partition@0 { | ||||||
|  | 				label = "u-boot"; | ||||||
|  | 				reg = <0x0 0x30000>; | ||||||
|  | 				read-only; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			partition@30000 { | ||||||
|  | 				label = "u-boot-env"; | ||||||
|  | 				reg = <0x30000 0x10000>; | ||||||
|  | 				read-only; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			factory: partition@40000 { | ||||||
|  | 				label = "factory"; | ||||||
|  | 				reg = <0x40000 0x10000>; | ||||||
|  | 				read-only; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			partition@50000 { | ||||||
|  | 				compatible = "fonfxc,uimage"; | ||||||
|  | 				label = "firmware"; | ||||||
|  | 				reg = <0x50000 0xf90000>; | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			partition@fe0000 { | ||||||
|  | 				label = "board_data"; | ||||||
|  | 				reg = <0xfe0000 0x20000>; | ||||||
|  | 				read-only; | ||||||
|  | 			}; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &state_default { | ||||||
|  | 	gpio { | ||||||
|  | 		ralink,group = "i2c", "uartf"; | ||||||
|  | 		ralink,function = "gpio"; | ||||||
|  | 	}; | ||||||
|  | 	nd_sd { | ||||||
|  | 		ralink,group = "nd_sd"; | ||||||
|  | 		ralink,function = "sd"; | ||||||
|  | 	}; | ||||||
|  | 	spi_cs { | ||||||
|  | 		ralink,group = "spi refclk"; | ||||||
|  | 		ralink,function = "spi refclk"; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ðernet { | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	pinctrl-0 = <&rgmii2_pins &mdio_pins>; | ||||||
|  |  | ||||||
|  | 	mtd-mac-address = <&factory 0x4>; | ||||||
|  |  | ||||||
|  | 	port@4 { | ||||||
|  | 		status = "okay"; | ||||||
|  | 		phy-handle = <&phy4>; | ||||||
|  | 		phy-mode = "rgmii"; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	mdio-bus { | ||||||
|  | 		status = "okay"; | ||||||
|  |  | ||||||
|  | 		phy4: ethernet-phy@4 { | ||||||
|  | 			reg = <4>; | ||||||
|  | 			phy-mode = "rgmii"; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &gsw { | ||||||
|  | 	mediatek,port4 = "gmac"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &wmac { | ||||||
|  | 	ralink,mtd-eeprom = <&factory 0>; | ||||||
|  | 	pinctrl-names = "default"; | ||||||
|  | 	pinctrl-0 = <&pa_pins>, <&wled_pins>; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &pcie { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  | &pcie0 { | ||||||
|  | 	wifi@0,0 { | ||||||
|  | 		compatible = "pci14c3,7662"; | ||||||
|  | 		reg = <0x0000 0 0 0 0>; | ||||||
|  | 		mediatek,mtd-eeprom = <&factory 0x8000>; | ||||||
|  | 		ieee80211-freq-limit = <5000000 6000000>; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &ehci { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | &ohci { | ||||||
|  | 	status = "okay"; | ||||||
|  | }; | ||||||
| @@ -147,6 +147,11 @@ define Build/sercom-footer | |||||||
| 	$(call Build/sercom-seal,-f) | 	$(call Build/sercom-seal,-f) | ||||||
| endef | endef | ||||||
|  |  | ||||||
|  | define Build/fonfxcimage | ||||||
|  | 	uimage_padhdr -i $@ -o $@.new | ||||||
|  | 	mv $@.new $@ | ||||||
|  | endef | ||||||
|  |  | ||||||
| ifeq ($(SUBTARGET),rt288x) | ifeq ($(SUBTARGET),rt288x) | ||||||
| include rt288x.mk | include rt288x.mk | ||||||
| endif | endif | ||||||
|   | |||||||
| @@ -372,6 +372,19 @@ define Device/elecom_wrh-300cr | |||||||
| endef | endef | ||||||
| TARGET_DEVICES += elecom_wrh-300cr | TARGET_DEVICES += elecom_wrh-300cr | ||||||
|  |  | ||||||
|  | define Device/fon_fon2601 | ||||||
|  |   MTK_SOC := mt7620a | ||||||
|  |   IMAGE_SIZE := 15936k | ||||||
|  |   DEVICE_VENDOR := Fon | ||||||
|  |   DEVICE_MODEL := FON2601 | ||||||
|  |   DEVICE_PACKAGES := kmod-mt76x2 kmod-usb2 kmod-usb-ohci | ||||||
|  |   KERNEL_INITRAMFS := $$(KERNEL) | fonfxcimage | ||||||
|  |   IMAGE/sysupgrade.bin := append-kernel | append-rootfs |\ | ||||||
|  | 			fonfxcimage |\ | ||||||
|  | 			pad-rootfs | append-metadata | check-size $$$$(IMAGE_SIZE) | ||||||
|  | endef | ||||||
|  | TARGET_DEVICES += fon_fon2601 | ||||||
|  |  | ||||||
| define Device/glinet_gl-mt300a | define Device/glinet_gl-mt300a | ||||||
|   MTK_SOC := mt7620a |   MTK_SOC := mt7620a | ||||||
|   IMAGE_SIZE := 15872k |   IMAGE_SIZE := 15872k | ||||||
|   | |||||||
| @@ -92,6 +92,7 @@ define Host/Compile | |||||||
| 	$(call cc,dns313-header, -Wall) | 	$(call cc,dns313-header, -Wall) | ||||||
| 	$(call cc,mksercommfw, -Wall) | 	$(call cc,mksercommfw, -Wall) | ||||||
| 	$(call cc,nec-enc, -Wall --std=gnu99) | 	$(call cc,nec-enc, -Wall --std=gnu99) | ||||||
|  | 	$(call cc,uimage_padhdr, -Wall -lz) | ||||||
| endef | endef | ||||||
|  |  | ||||||
| define Host/Install | define Host/Install | ||||||
|   | |||||||
							
								
								
									
										157
									
								
								tools/firmware-utils/src/uimage_padhdr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								tools/firmware-utils/src/uimage_padhdr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | |||||||
|  | /* | ||||||
|  |  * uimage_padhdr.c : add zero paddings after the tail of uimage header | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2019 NOGUCHI Hiroshi <drvlabo@gmail.com> | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU General Public License, | ||||||
|  |  * version 2 as published by the Free Software Foundation. | ||||||
|  |  * | ||||||
|  |  * 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 <stdio.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <arpa/inet.h> | ||||||
|  | #include <zlib.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* from u-boot/include/image.h */ | ||||||
|  | #define IH_MAGIC	0x27051956	/* Image Magic Number		*/ | ||||||
|  | #define IH_NMLEN		32	/* Image Name Length		*/ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Legacy format image header, | ||||||
|  |  * all data in network byte order (aka natural aka bigendian). | ||||||
|  |  */ | ||||||
|  | typedef struct image_header { | ||||||
|  | 	uint32_t	ih_magic;	/* Image Header Magic Number	*/ | ||||||
|  | 	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/ | ||||||
|  | 	uint32_t	ih_time;	/* Image Creation Timestamp	*/ | ||||||
|  | 	uint32_t	ih_size;	/* Image Data Size		*/ | ||||||
|  | 	uint32_t	ih_load;	/* Data	 Load  Address		*/ | ||||||
|  | 	uint32_t	ih_ep;		/* Entry Point Address		*/ | ||||||
|  | 	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/ | ||||||
|  | 	uint8_t		ih_os;		/* Operating System		*/ | ||||||
|  | 	uint8_t		ih_arch;	/* CPU architecture		*/ | ||||||
|  | 	uint8_t		ih_type;	/* Image Type			*/ | ||||||
|  | 	uint8_t		ih_comp;	/* Compression Type		*/ | ||||||
|  | 	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/ | ||||||
|  | } image_header_t; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* default padding size */ | ||||||
|  | #define	IH_PAD_BYTES		(32) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void usage(char *prog) | ||||||
|  | { | ||||||
|  | 	fprintf(stderr, | ||||||
|  | 		"%s -i <input_uimage_file> -o <output_file> [-l <padding bytes>]\n", | ||||||
|  | 		prog); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	struct stat statbuf; | ||||||
|  | 	u_int8_t *filebuf; | ||||||
|  | 	int ifd; | ||||||
|  | 	int ofd; | ||||||
|  | 	ssize_t rsz; | ||||||
|  | 	u_int32_t crc_recalc; | ||||||
|  | 	image_header_t *imgh; | ||||||
|  | 	int opt; | ||||||
|  | 	char *infname = NULL; | ||||||
|  | 	char *outfname = NULL; | ||||||
|  | 	int padsz = IH_PAD_BYTES; | ||||||
|  | 	int ltmp; | ||||||
|  |  | ||||||
|  | 	while ((opt = getopt(argc, argv, "i:o:l:")) != -1) { | ||||||
|  | 		switch (opt) { | ||||||
|  | 		case 'i': | ||||||
|  | 			infname = optarg; | ||||||
|  | 			break; | ||||||
|  | 		case 'o': | ||||||
|  | 			outfname = optarg; | ||||||
|  | 			break; | ||||||
|  | 		case 'l': | ||||||
|  | 			ltmp = strtol(optarg, NULL, 0); | ||||||
|  | 			if (ltmp > 0) | ||||||
|  | 				padsz = ltmp; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!infname || !outfname) { | ||||||
|  | 		usage(argv[0]); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (stat(infname, &statbuf) < 0) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not find input file. (errno = %d)\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	filebuf = malloc(statbuf.st_size + padsz); | ||||||
|  | 	if (!filebuf) { | ||||||
|  | 		fprintf(stderr, "buffer allocation failed\n"); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ifd = open(infname, O_RDONLY); | ||||||
|  | 	if (ifd < 0) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not open input file. (errno = %d)\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ofd = open(outfname, O_WRONLY | O_CREAT, 0644); | ||||||
|  | 	if (ofd < 0) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not open output file. (errno = %d)\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rsz = read(ifd, filebuf, sizeof(*imgh)); | ||||||
|  | 	if (rsz != sizeof(*imgh)) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not read input file (errno = %d).\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	memset(&(filebuf[sizeof(*imgh)]), 0, padsz); | ||||||
|  |  | ||||||
|  | 	rsz = read(ifd, &(filebuf[sizeof(*imgh) + padsz]), | ||||||
|  | 				statbuf.st_size - sizeof(*imgh)); | ||||||
|  | 	if (rsz != (int32_t)(statbuf.st_size - sizeof(*imgh))) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not read input file (errno = %d).\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	imgh = (image_header_t *)filebuf; | ||||||
|  |  | ||||||
|  | 	imgh->ih_hcrc = 0; | ||||||
|  | 	crc_recalc = crc32(0, filebuf, sizeof(*imgh) + padsz); | ||||||
|  | 	imgh->ih_hcrc = htonl(crc_recalc); | ||||||
|  |  | ||||||
|  | 	rsz = write(ofd, filebuf, statbuf.st_size + padsz); | ||||||
|  | 	if (rsz != (int32_t)statbuf.st_size + padsz) { | ||||||
|  | 		fprintf(stderr, | ||||||
|  | 			"could not write output file (errnor = %d).\n", errno); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user