├── src ├── debian │ ├── compat │ ├── source │ │ └── format │ ├── snander.dirs │ ├── snander.substvars │ ├── rules │ ├── control │ └── changelog ├── res.h ├── snander.ico ├── 40-persistent-ch341a.rules ├── timer.h ├── snander.rc ├── types.h ├── snorcmd_api.h ├── mw_eeprom_api.h ├── i2c_eeprom_api.h ├── spi_eeprom_api.h ├── ch341a_gpio.h ├── nandcmd_api.h ├── flashcmd_api.h ├── ch347_spi.h ├── timer.c ├── spi_eeprom.h ├── Makefile ├── spi_controller.c ├── bitbang_microwire.h ├── flashcmd_api.c ├── ch341a_gpio.c ├── i2c_eeprom.c ├── mw_eeprom.c ├── spi_controller.h ├── spi_eeprom.c ├── bitbang_microwire.c ├── spi_nand_flash.h ├── main.c ├── ch347_i2c.c ├── ch347_i2c.h └── ch347_spi.c ├── drivers ├── zadig.md └── CH341PAR.EXE ├── photos ├── foto1.png ├── foto2.png ├── photo1.jpg ├── photo2.jpg ├── photo3.jpg ├── photo4.jpg ├── usage.png ├── spi_i2c_usb_ch341a.jpg └── ch347-nextProgrammer.jpg ├── schematics ├── schematic_1.jpg ├── schematic_2.jpg ├── schematic_2.png ├── schematic_3.jpg └── schematic_SPI25_to_93CXX.png ├── .gitmodules ├── INSTALL.txt ├── Makefile ├── README.md └── LICENSE /src/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /src/res.h: -------------------------------------------------------------------------------- 1 | #define snander 128 2 | -------------------------------------------------------------------------------- /drivers/zadig.md: -------------------------------------------------------------------------------- 1 | https://zadig.akeo.ie/ 2 | -------------------------------------------------------------------------------- /src/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /src/debian/snander.dirs: -------------------------------------------------------------------------------- 1 | usr/bin 2 | etc/udev/rules.d 3 | -------------------------------------------------------------------------------- /src/snander.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/src/snander.ico -------------------------------------------------------------------------------- /photos/foto1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/foto1.png -------------------------------------------------------------------------------- /photos/foto2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/foto2.png -------------------------------------------------------------------------------- /photos/photo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/photo1.jpg -------------------------------------------------------------------------------- /photos/photo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/photo2.jpg -------------------------------------------------------------------------------- /photos/photo3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/photo3.jpg -------------------------------------------------------------------------------- /photos/photo4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/photo4.jpg -------------------------------------------------------------------------------- /photos/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/usage.png -------------------------------------------------------------------------------- /drivers/CH341PAR.EXE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/drivers/CH341PAR.EXE -------------------------------------------------------------------------------- /schematics/schematic_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/schematics/schematic_1.jpg -------------------------------------------------------------------------------- /schematics/schematic_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/schematics/schematic_2.jpg -------------------------------------------------------------------------------- /schematics/schematic_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/schematics/schematic_2.png -------------------------------------------------------------------------------- /schematics/schematic_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/schematics/schematic_3.jpg -------------------------------------------------------------------------------- /photos/spi_i2c_usb_ch341a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/spi_i2c_usb_ch341a.jpg -------------------------------------------------------------------------------- /photos/ch347-nextProgrammer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/photos/ch347-nextProgrammer.jpg -------------------------------------------------------------------------------- /src/debian/snander.substvars: -------------------------------------------------------------------------------- 1 | shlibs:Depends=libc6 (>= 2.4), libusb-1.0-0 (>= 2:1.0.8) 2 | misc:Depends= 3 | misc:Pre-Depends= 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SPI_to_MW_Adapter"] 2 | path = SPI_to_MW_Adapter 3 | url = https://github.com/Droid-MAX/SPI_to_MW_Adapter 4 | -------------------------------------------------------------------------------- /schematics/schematic_SPI25_to_93CXX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhiyuanYuanNJ/SNANDer/HEAD/schematics/schematic_SPI25_to_93CXX.png -------------------------------------------------------------------------------- /src/40-persistent-ch341a.rules: -------------------------------------------------------------------------------- 1 | ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1a86", ATTR{idProduct}=="5512", MODE:="0666" 2 | ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1a86", ATTR{idProduct}=="7523", MODE:="0666" 3 | -------------------------------------------------------------------------------- /src/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export DEB_CFLAGS_SET = -std=gnu99 -Wall -O2 -D_FILE_OFFSET_BITS=64 4 | export DEB_LDFLAGS_SET = -pthread 5 | 6 | %: 7 | dh $@ 8 | 9 | override_dh_auto_install: 10 | $(MAKE) install DESTDIR=$(PWD)/debian/snander prefix=/usr 11 | 12 | override_dh_usrlocal: 13 | 14 | -------------------------------------------------------------------------------- /src/debian/control: -------------------------------------------------------------------------------- 1 | Source: snander 2 | Priority: optional 3 | Maintainer: McMCC 4 | Build-Depends: debhelper (>= 9) 5 | Standards-Version: 1.7.8 6 | Section: electronics 7 | Vcs-Git: https://github.com/McMCCRU/SNANDer.git 8 | Vcs-Browser: https://github.com/McMCCRU/SNANDer 9 | 10 | Package: snander 11 | Architecture: any 12 | Depends: ${shlibs:Depends}, ${misc:Depends} 13 | Description: SNANDer - Serial Nor/nAND/Eeprom programmeR (based on CH341A) 14 | 15 | -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | Windows-10 64bit: 2 | 3 | 1. Insert USB Programmer based on chip CH341A in port USB. 4 | 2. Download and Run zadig-2.8.exe. Select device ID 1a86:5512 and push INSTALL. 5 | 3. Use SNANDer.exe in console mode(cmd)... 6 | 7 | Linux Ubuntu 64bit: 8 | 9 | 1. Copy SNANDer in directory /usr/local/bin. 10 | 2. Copy 40-persistent-ch341a.rules in directory /etc/udev/rules.d. 11 | 3. Restart udev service as udevadm control --reload-rules. 12 | 4. Use SNANDer in console mode. 13 | -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * timer.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __TIMER_H__ 16 | #define __TIMER_H__ 17 | 18 | void timer_start(void); 19 | void timer_end(void); 20 | int timer_progress(void); 21 | 22 | #endif /* __TIMER_H__ */ 23 | /* End of [timer.h] package */ 24 | -------------------------------------------------------------------------------- /src/snander.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "res.h" 3 | 4 | VS_VERSION_INFO VERSIONINFO 5 | FILEVERSION 1, 7, 8, 0 6 | PRODUCTVERSION 1, 7, 8, 0 7 | FILEOS VOS_NT_WINDOWS32 8 | FILETYPE VFT_APP 9 | FILESUBTYPE 0 10 | BEGIN 11 | BLOCK "StringFileInfo" 12 | BEGIN 13 | BLOCK "040904E4" 14 | BEGIN 15 | VALUE "FileDescription", "SNANDer - Serial Nor/nAND/Eeprom programmeR\0" 16 | VALUE "OriginalFilename", "SNANDer.exe\0" 17 | VALUE "CompanyName", "-= (c) 2018-2024 Igor Mokrushin aka McMCC =-\0" 18 | VALUE "FileVersion", "1.7.8.0\0" 19 | VALUE "InternalName", "SNANDer\0" 20 | VALUE "LegalCopyright", "Copyright (c) 2018-2024 by McMCC \0" 21 | VALUE "ProductName","SNANDer\0" 22 | VALUE "ProductVersion","1.7.8.0\0" 23 | END 24 | END 25 | BLOCK "VarFileInfo" 26 | BEGIN 27 | VALUE "Translation", 0x0409, 1252 28 | END 29 | END 30 | 31 | snander ICON DISCARDABLE "snander.ico" 32 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * types.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __TYPES_H__ 16 | #define __TYPES_H__ 17 | 18 | typedef unsigned char u8; 19 | typedef unsigned short u16; 20 | typedef unsigned int u32; 21 | typedef unsigned long long u64; 22 | typedef u16 __le16; 23 | typedef u16 __be16; 24 | typedef u32 __le32; 25 | typedef u32 __be32; 26 | 27 | #endif /* __TYPES_H__ */ 28 | /* End of [types.h] package */ 29 | -------------------------------------------------------------------------------- /src/snorcmd_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * snorcmd_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __SNORCMD_API_H__ 16 | #define __SNORCMD_API_H__ 17 | 18 | int snor_read(unsigned char *buf, unsigned long from, unsigned long len); 19 | int snor_erase(unsigned long offs, unsigned long len); 20 | int snor_write(unsigned char *buf, unsigned long to, unsigned long len); 21 | long snor_init(void); 22 | void support_snor_list(void); 23 | 24 | #endif /* __SNORCMD_API_H__ */ 25 | /* End of [snorcmd_api.h] package */ 26 | -------------------------------------------------------------------------------- /src/mw_eeprom_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * mw_eeprom_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __MW_EEPROM_API_H__ 16 | #define __MW_EEPROM_API_H__ 17 | 18 | int mw_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len); 19 | int mw_eeprom_erase(unsigned long offs, unsigned long len); 20 | int mw_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len); 21 | long mw_init(void); 22 | void support_mw_eeprom_list(void); 23 | 24 | #endif /* __MW_EEPROM_API_H__ */ 25 | /* End of [mw_eeprom_api.h] package */ 26 | -------------------------------------------------------------------------------- /src/i2c_eeprom_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * i2c_eeprom_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __I2C_EEPROM_API_H__ 16 | #define __I2C_EEPROM_API_H__ 17 | 18 | int i2c_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len); 19 | int i2c_eeprom_erase(unsigned long offs, unsigned long len); 20 | int i2c_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len); 21 | long i2c_init(void); 22 | void support_i2c_eeprom_list(void); 23 | 24 | #endif /* __I2C_EEPROM_API_H__ */ 25 | /* End of [i2c_eeprom_api.h] package */ 26 | -------------------------------------------------------------------------------- /src/spi_eeprom_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 McMCC 3 | * spi_eeprom_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __SPI_EEPROM_API_H__ 16 | #define __SPI_EEPROM_API_H__ 17 | 18 | int spi_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len); 19 | int spi_eeprom_erase(unsigned long offs, unsigned long len); 20 | int spi_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len); 21 | long spi_eeprom_init(void); 22 | void support_spi_eeprom_list(void); 23 | 24 | #endif /* __SPI_EEPROM_API_H__ */ 25 | /* End of [spi_eeprom_api.h] package */ 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | PKG_NAME:=snander 4 | PKG_VERSION:=1.7.8 5 | PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) 6 | PKG_BUILD_DEPENDS:=libpthread libusb-1.0 7 | PKG_MAINTAINER:=McMCC 8 | PKG_LICENSE:=GPLv2.0 9 | PKG_LICENSE_FILES:=LICENSE 10 | 11 | include $(INCLUDE_DIR)/package.mk 12 | 13 | define Package/$(PKG_NAME) 14 | SECTION:=utils 15 | CATEGORY:=Utilities 16 | TITLE:=Serial Nor/nAND/Eeprom programmeR (based on CH341A) 17 | MAINTAINER:=McMCC 18 | URL:=https://github.com/McMCCRU/SNANDer 19 | DEPENDS:=+libpthread +libusb-1.0 20 | TARGET_CFLAGS:=-std=gnu99 -Wall -O2 -D_FILE_OFFSET_BITS=64 21 | TARGET_LDFLAGS:=-ldl -lpthread 22 | endef 23 | 24 | define Package/$(PKG_NAME)/description 25 | Serial Nor/nAND/Eeprom programmeR (based on CH341A) 26 | endef 27 | 28 | define Build/Prepare 29 | mkdir -p $(PKG_BUILD_DIR) 30 | cp -r src/* $(PKG_BUILD_DIR) 31 | endef 32 | 33 | define Package/$(PKG_NAME)/install 34 | $(INSTALL_DIR) $(1)/usr/bin 35 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/snander $(1)/usr/bin 36 | endef 37 | 38 | $(eval $(call BuildPackage,$(PKG_NAME))) 39 | -------------------------------------------------------------------------------- /src/ch341a_gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * ch341a_gpio.h 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | #ifndef __CH341A_GPIO_H__ 20 | #define __CH341A_GPIO_H__ 21 | 22 | #include 23 | 24 | int ch341a_gpio_setdir(void); 25 | int ch341a_gpio_setbits(uint8_t bits); 26 | int ch341a_gpio_getbits(uint8_t *data); 27 | 28 | #endif /* __CH341A_GPIO_H__ */ 29 | /* End of [ch341a_gpio.h] package */ 30 | -------------------------------------------------------------------------------- /src/nandcmd_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * nandcmd_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __NANDCMD_API_H__ 16 | #define __NANDCMD_API_H__ 17 | 18 | int snand_read(unsigned char *buf, unsigned long from, unsigned long len); 19 | int snand_erase(unsigned long offs, unsigned long len); 20 | int snand_write(unsigned char *buf, unsigned long to, unsigned long len); 21 | long snand_init(void); 22 | void support_snand_list(void); 23 | 24 | extern int ECC_fcheck; 25 | extern int ECC_ignore; 26 | extern int OOB_size; 27 | extern int Skip_BAD_page; 28 | extern unsigned char _ondie_ecc_flag; 29 | 30 | #endif /* __NANDCMD_API_H__ */ 31 | /* End of [nandcmd_api.h] package */ 32 | -------------------------------------------------------------------------------- /src/flashcmd_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * flashcmd_api.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __FLASHCMD_API_H__ 16 | #define __FLASHCMD_API_H__ 17 | 18 | #include "nandcmd_api.h" 19 | #include "snorcmd_api.h" 20 | #ifdef EEPROM_SUPPORT 21 | #include "i2c_eeprom_api.h" 22 | #include "mw_eeprom_api.h" 23 | #include "spi_eeprom_api.h" 24 | #endif 25 | 26 | struct flash_cmd { 27 | int (*flash_read)(unsigned char *buf, unsigned long from, unsigned long len); 28 | int (*flash_erase)(unsigned long offs, unsigned long len); 29 | int (*flash_write)(unsigned char *buf, unsigned long to, unsigned long len); 30 | }; 31 | 32 | long flash_cmd_init(struct flash_cmd *cmd); 33 | void support_flash_list(void); 34 | 35 | #endif /* __FLASHCMD_API_H__ */ 36 | /* End of [flashcmd_api.h] package */ 37 | -------------------------------------------------------------------------------- /src/ch347_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | #ifndef __CH341_SPI_H__ 19 | #define __CH341_SPI_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #define min(a,b) (((a)<(b))?(a):(b)) 26 | #define max(a,b) (((a)>(b))?(a):(b)) 27 | 28 | int ch347_spi_init(void); 29 | int ch347_spi_shutdown(void); 30 | int ch347_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); 31 | int enable_pins(bool enable); 32 | int config_stream(unsigned int speed); 33 | 34 | #endif /* __CH341_SPI_H__ */ 35 | /* End of [ch347_spi.h] package */ 36 | -------------------------------------------------------------------------------- /src/debian/changelog: -------------------------------------------------------------------------------- 1 | snander (1.7.8-1) UNRELEASED; urgency=medium 2 | 3 | * Update libusb version to v1.0.27. 4 | * Add GD25F256F SPI NOR Flash support. 5 | * Add W25Q64JVIM SPI NOR Flash support. 6 | * Add MX25L4005A SPI NOR Flash support. 7 | * Add MX25U Series SPI NOR Flash support. 8 | * Add -k option to skip BAD blocks or pages when reading and writing NAND flash. 9 | * Add M25P05/M25P10/M25P20/M25P40/M25P80/M25P32/M25P64/N25Q016A/N25Q512A SPI NOR Flash support. 10 | * Add P25D05H/P25D10H/P25D20H/P25D40H/P25D80H/PY25Q128HA SPI NOR Flash support. 11 | * Add some SPI NOR Flash from EXCELSEMI/ONSEMI/ZETTA/PCT Manufacturers. 12 | * Add MXIC MX35LF2G14AC/MX35UF1GE4AD/MX35UF2GE4AD/MX35UF4GE4AD SPI NAND Flash support. 13 | * Add MXIC MX35LF1G24AD/MX35LF2G24AD/MX35LF4G24AD SPI NAND Flash support. 14 | * Add GigaDevice GD5F2GQ5UE/GD5F2GQ5RE SPI NAND Flash support. 15 | * Add WINBOND W25N01GW/W25N04KV SPI NAND Flash support. 16 | * Add FORESEE FS35ND01GS1Y2 SPI NAND Flash support. 17 | * Add DS DS35M1GA/DS35M2GA SPI NAND Flash support. 18 | * Add ESMT F50D1G41LB(2M) SPI NAND Flash support. 19 | * Add XTX XT26G02C SPI NAND Flash support. 20 | * Add FM FM25S02A SPI NAND Flash support. 21 | * Fix Warning: dangling pointer to 'tmp' may be used. 22 | * Fix print size in KB when size is less than 1MB. 23 | * Fix when SPI_NAND_FLASH_DEBUG is enabled. 24 | 25 | -- McMCC Fri, 21 Jun 2024 17:16:31 +0800 26 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * timer.c 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #include "timer.h" 20 | 21 | static time_t start_time = 0; 22 | static time_t print_time = 0; 23 | 24 | void timer_start(void) 25 | { 26 | start_time = time(0); 27 | } 28 | 29 | void timer_end(void) 30 | { 31 | time_t end_time = 0, elapsed_seconds = 0; 32 | 33 | time(&end_time); 34 | elapsed_seconds = difftime(end_time, start_time); 35 | printf("Elapsed time: %d seconds\n", (int)elapsed_seconds); 36 | print_time = 0; 37 | } 38 | 39 | int timer_progress(void) 40 | { 41 | time_t end_time = 0; 42 | int elapsed_seconds = 0; 43 | 44 | if (!print_time) 45 | print_time = time(0); 46 | 47 | time(&end_time); 48 | 49 | elapsed_seconds = (int)difftime(end_time, print_time); 50 | 51 | if (elapsed_seconds == 1) { 52 | print_time = 0; 53 | return 1; 54 | } 55 | return 0; 56 | } 57 | /* End of [timer.c] package */ 58 | -------------------------------------------------------------------------------- /src/spi_eeprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 McMCC 3 | * spi_eeprom.h 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #ifndef __SPI_EEPROM_H__ 16 | #define __SPI_EEPROM_H__ 17 | 18 | #define SEEP_WREN_CMD 0x06 /* Set Write Enable Instruction */ 19 | #define SEEP_WRDI_CMD 0x04 /* Reset Write Enable Instruction */ 20 | #define SEEP_RDSR_CMD 0x05 /* Read Status Register */ 21 | #define SEEP_WRSR_CMD 0x01 /* Write Status Register */ 22 | #define SEEP_READ_CMD 0x03 /* Read Data from Memory Array */ 23 | #define SEEP_WRITE_CMD 0x02 /* Write Data to Memory Array */ 24 | 25 | struct spi_eeprom 26 | { 27 | char *name; 28 | uint32_t total_bytes; /* EEPROM total memory size */ 29 | uint8_t addr_bits; /* Number of address bit */ 30 | }; 31 | 32 | const static struct spi_eeprom seepromlist[] = { 33 | { "25010", 128, 7 }, 34 | { "25020", 256, 8 }, 35 | { "25040", 512, 9 }, 36 | { "25080", 1024, 10 }, 37 | { "25160", 2048, 11 }, 38 | { "25320", 4096, 12 }, 39 | { "25640", 8192, 13 }, 40 | { "25128", 16384, 14 }, 41 | { "25256", 32768, 15 }, 42 | { "25512", 65536, 16 }, 43 | { "251024", 131072, 17 }, 44 | { 0, 0, 0 } 45 | }; 46 | 47 | #define MAX_SEEP_SIZE 131072 48 | #define MAX_SEEP_PSIZE 1024 49 | 50 | int32_t parseSEEPsize(char *seepromname, struct spi_eeprom *seeprom); 51 | 52 | #endif /* __SPI_EEPROM_H__ */ 53 | /* End of [spi_eeprom.h] package */ 54 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = snander 2 | PKG = $(TARGET) 3 | VERSION = 1.7.8-1 4 | 5 | CC ?= gcc 6 | STRIP ?= strip 7 | INSTALL ?= install 8 | WINDRES ?= windres 9 | PREFIX ?= /usr 10 | BINDIR ?= $(PREFIX)/bin 11 | CFLAGS ?= -std=gnu99 -Wall -O2 -D_FILE_OFFSET_BITS=64 12 | LDFLAGS ?= -pthread 13 | RES ?= res.bin 14 | 15 | EEPROM_SUPPORT = yes 16 | 17 | SRCS = flashcmd_api.c spi_controller.c spi_nand_flash.c spi_nor_flash.c ch347_spi.c timer.c main.c 18 | 19 | ifdef LIBS_BASE 20 | CFLAGS += -I$(LIBS_BASE)/include 21 | LDFLAGS += -L$(LIBS_BASE)/lib -Wl,-rpath -Wl,$(LIBS_BASE)/lib 22 | endif 23 | 24 | ifeq ($(CONFIG_STATIC), yes) 25 | LDFLAGS += -static 26 | endif 27 | 28 | ifeq ($(EEPROM_SUPPORT), yes) 29 | CFLAGS += -DEEPROM_SUPPORT 30 | SRCS += i2c_eeprom.c spi_eeprom.c bitbang_microwire.c mw_eeprom.c ch341a_gpio.c ch347_i2c.c 31 | endif 32 | 33 | ifeq ($(TARGET_OS), MinGW) 34 | EXEC_SUFFIX := .exe 35 | SRCS += $(RES) 36 | CFLAGS += -posix 37 | CFLAGS += -Dffs=__builtin_ffs 38 | CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 39 | endif 40 | 41 | ifeq ($(TARGET_OS), Darwin) 42 | CFLAGS += -Wno-gnu-designator 43 | LDFLAGS += -lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-framework,Security 44 | endif 45 | 46 | $(PKG): $(TARGET)$(EXEC_SUFFIX) 47 | 48 | $(TARGET)$(EXEC_SUFFIX): $(SRCS) 49 | $(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -lusb-1.0 -o $@ 50 | 51 | $(RES): 52 | $(WINDRES) -i $(TARGET).rc -o $@ 53 | 54 | clean: 55 | rm -f $(TARGET)$(EXEC_SUFFIX) $(RES) 56 | 57 | strip: $(TARGET)$(EXEC_SUFFIX) 58 | $(STRIP) $(TARGET)$(EXEC_SUFFIX) 59 | 60 | install: $(TARGET) 61 | mkdir -p $(DESTDIR)$(BINDIR) 62 | mkdir -p $(DESTDIR)/etc/udev/rules.d 63 | $(INSTALL) -m 0755 $(TARGET) $(DESTDIR)$(BINDIR) 64 | $(INSTALL) -m 0664 40-persistent-ch341a.rules $(DESTDIR)/etc/udev/rules.d/40-persistent-ch341a.rules 65 | 66 | install-udev-rule: 67 | cp 40-persistent-ch341a.rules /etc/udev/rules.d/ 68 | udevadm control --reload-rules 69 | .PHONY: clean install-udev-rule 70 | 71 | debian/changelog: 72 | dch --create -v $(VERSION) --package $(PKG) 73 | 74 | deb: 75 | dpkg-buildpackage -b -us -uc 76 | .PHONY: install debian/changelog deb 77 | -------------------------------------------------------------------------------- /src/spi_controller.c: -------------------------------------------------------------------------------- 1 | /*====================================================================================== 2 | * MODULE NAME: spi 3 | * FILE NAME: spi_controller.c 4 | * 5 | * FUNCTIONS 6 | * 7 | * SPI_CONTROLLER_Enable_Manual_Mode To provide interface for Enable SPI Controller Manual Mode. 8 | * SPI_CONTROLLER_Write_One_Byte To provide interface for write one byte to SPI bus. 9 | * SPI_CONTROLLER_Write_NByte To provide interface for write N bytes to SPI bus. 10 | * SPI_CONTROLLER_Read_NByte To provide interface for read N bytes from SPI bus. 11 | * SPI_CONTROLLER_Chip_Select_Low To provide interface for set chip select low in SPI bus. 12 | * SPI_CONTROLLER_Chip_Select_High To provide interface for set chip select high in SPI bus. 13 | * 14 | * DEPENDENCIES 15 | * 16 | * * $History: $ 17 | * MODIFICTION HISTORY: 18 | * 19 | *====================================================================================== 20 | */ 21 | #include "ch347_spi.h" 22 | #include "spi_controller.h" 23 | 24 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Enable_Manual_Mode( void ) 25 | { 26 | return 0; 27 | } 28 | 29 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_One_Byte( u8 data ) 30 | { 31 | return (SPI_CONTROLLER_RTN_T)ch347_spi_send_command(1, 0, &data, NULL); 32 | } 33 | 34 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_High( void ) 35 | { 36 | return (SPI_CONTROLLER_RTN_T)enable_pins(false); 37 | } 38 | 39 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_Low( void ) 40 | { 41 | return (SPI_CONTROLLER_RTN_T)enable_pins(true); 42 | } 43 | 44 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Read_NByte( u8 *ptr_rtn_data, u32 len, SPI_CONTROLLER_SPEED_T speed ) 45 | { 46 | return (SPI_CONTROLLER_RTN_T)ch347_spi_send_command(0, len, NULL, ptr_rtn_data); 47 | } 48 | 49 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_NByte( u8 *ptr_data, u32 len, SPI_CONTROLLER_SPEED_T speed ) 50 | { 51 | return (SPI_CONTROLLER_RTN_T)ch347_spi_send_command(len, 0, ptr_data, NULL); 52 | } 53 | 54 | #if 0 55 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Xfer_NByte( u8 *ptr_data_in, u32 len_in, u8 *ptr_data_out, u32 len_out, SPI_CONTROLLER_SPEED_T speed ) 56 | { 57 | return (SPI_CONTROLLER_RTN_T)ch347_spi_send_command(len_out, len_in, ptr_data_out, ptr_data_in); 58 | } 59 | #endif 60 | /* End of [spi_controller.c] package */ 61 | -------------------------------------------------------------------------------- /src/bitbang_microwire.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2005-2021 Mokrushin I.V. aka McMCC mcmcc@mail.ru 2 | A simple bitbang protocol for Microwire 8-pin serial EEPROMs 3 | (93XX devices). Support organization 8bit and 16bit(8bit emulation). 4 | 5 | bitbang_microwire.h 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 20 | /* ------------------------------------------------------------------------- */ 21 | 22 | #ifndef _BITBANG_MICROWIRE_H 23 | #define _BITBANG_MICROWIRE_H 24 | 25 | #if 0 26 | extern unsigned char ORG; /* organization 0 = 8 bit and 1 = 16 bit */ 27 | #endif 28 | extern unsigned char CLK; 29 | extern unsigned char DO; 30 | extern unsigned char DI; 31 | extern unsigned char CSEL; 32 | 33 | extern int org; 34 | extern int mw_eepromsize; 35 | extern int fix_addr_len; 36 | 37 | struct MW_EEPROM { 38 | char *name; 39 | unsigned int size; 40 | }; 41 | 42 | struct gpio_cmd { 43 | int (*gpio_setdir)(void); 44 | int (*gpio_setbits)(unsigned char bit); 45 | int (*gpio_getbits)(unsigned char *data); 46 | }; 47 | 48 | void Erase_EEPROM_3wire(int size_eeprom); 49 | int Read_EEPROM_3wire(unsigned char *buffer, int size_eeprom); 50 | int Write_EEPROM_3wire(unsigned char *buffer, int size_eeprom); 51 | int deviceSize_3wire(char *eepromname); 52 | 53 | const static struct MW_EEPROM mw_eepromlist[] = { 54 | { "93c06", 32 }, 55 | { "93c16", 64 }, 56 | { "93c46", 128 }, 57 | { "93c56", 256 }, 58 | { "93c66", 512 }, 59 | { "93c76", 1024 }, 60 | { "93c86", 2048 }, 61 | { "93c96", 4096 }, 62 | { 0, 0 } 63 | }; 64 | 65 | #define MAX_MW_EEPROM_SIZE 4096 66 | 67 | #endif /* _BITBANG_MICROWIRE_H */ 68 | /* End of [bitbang_microwire.h] package */ 69 | -------------------------------------------------------------------------------- /src/flashcmd_api.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2021 McMCC 3 | * flashcmd_api.c 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include 17 | #include "flashcmd_api.h" 18 | 19 | #ifdef EEPROM_SUPPORT 20 | #define __EEPROM___ "or EEPROM" 21 | extern int eepromsize; 22 | extern int mw_eepromsize; 23 | extern int seepromsize; 24 | #else 25 | #define __EEPROM___ "" 26 | #endif 27 | 28 | long flash_cmd_init(struct flash_cmd *cmd) 29 | { 30 | long flen = -1; 31 | 32 | #ifdef EEPROM_SUPPORT 33 | if ((eepromsize <= 0) && (mw_eepromsize <= 0) && (seepromsize <= 0)) { 34 | #endif 35 | if ((flen = snor_init()) > 0) { 36 | cmd->flash_erase = snor_erase; 37 | cmd->flash_write = snor_write; 38 | cmd->flash_read = snor_read; 39 | } else if ((flen = snand_init()) > 0) { 40 | cmd->flash_erase = snand_erase; 41 | cmd->flash_write = snand_write; 42 | cmd->flash_read = snand_read; 43 | } 44 | #ifdef EEPROM_SUPPORT 45 | } else if ((eepromsize > 0) || (mw_eepromsize > 0) || (seepromsize > 0)) { 46 | if ((eepromsize > 0) && (flen = i2c_init()) > 0) { 47 | cmd->flash_erase = i2c_eeprom_erase; 48 | cmd->flash_write = i2c_eeprom_write; 49 | cmd->flash_read = i2c_eeprom_read; 50 | } else if ((mw_eepromsize > 0) && (flen = mw_init()) > 0) { 51 | cmd->flash_erase = mw_eeprom_erase; 52 | cmd->flash_write = mw_eeprom_write; 53 | cmd->flash_read = mw_eeprom_read; 54 | } else if ((seepromsize > 0) && (flen = spi_eeprom_init()) > 0) { 55 | cmd->flash_erase = spi_eeprom_erase; 56 | cmd->flash_write = spi_eeprom_write; 57 | cmd->flash_read = spi_eeprom_read; 58 | } 59 | } 60 | #endif 61 | else 62 | printf("\nFlash" __EEPROM___ " not found!!!!\n\n"); 63 | 64 | return flen; 65 | } 66 | 67 | void support_flash_list(void) 68 | { 69 | support_snand_list(); 70 | printf("\n"); 71 | support_snor_list(); 72 | #ifdef EEPROM_SUPPORT 73 | printf("\n"); 74 | support_i2c_eeprom_list(); 75 | printf("\n"); 76 | support_mw_eeprom_list(); 77 | printf("\n"); 78 | support_spi_eeprom_list(); 79 | #endif 80 | } 81 | /* End of [flashcmd.c] package */ 82 | -------------------------------------------------------------------------------- /src/ch341a_gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * ch341a_gpio.c 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define DEFAULT_TIMEOUT 1000 28 | #define BULK_WRITE_ENDPOINT 0x02 29 | #define BULK_READ_ENDPOINT 0x82 30 | 31 | #define CH341A_CMD_UIO_STREAM 0xAB 32 | #define CH341A_CMD_UIO_STM_IN 0x00 33 | #define CH341A_CMD_UIO_STM_DIR 0x40 34 | #define CH341A_CMD_UIO_STM_OUT 0x80 35 | #define CH341A_CMD_UIO_STM_US 0xC0 36 | #define CH341A_CMD_UIO_STM_END 0x20 37 | 38 | #define DIR_MASK 0x3F /* D6,D7 - input, D0-D5 - output */ 39 | 40 | extern struct libusb_device_handle *devHandle; 41 | 42 | static int usb_transf(const char *func, uint8_t type, uint8_t *buf, int len) 43 | { 44 | int ret, actuallen = 0; 45 | 46 | if (devHandle == NULL) 47 | return -1; 48 | 49 | ret = libusb_bulk_transfer(devHandle, type, buf, len, &actuallen, DEFAULT_TIMEOUT); 50 | if (ret < 0) { 51 | printf("%s: Failed to %s %d bytes '%s'\n", func, 52 | (type == BULK_WRITE_ENDPOINT) ? "write" : "read", len, strerror(-ret)); 53 | return -1; 54 | } 55 | 56 | return actuallen; 57 | } 58 | 59 | int ch341a_gpio_setdir(void) 60 | { 61 | uint8_t buf[] = { 62 | CH341A_CMD_UIO_STREAM, 63 | CH341A_CMD_UIO_STM_DIR | DIR_MASK, 64 | CH341A_CMD_UIO_STM_END 65 | }; 66 | 67 | return usb_transf(__func__, BULK_WRITE_ENDPOINT, buf, 3); 68 | } 69 | 70 | int ch341a_gpio_setbits(uint8_t bits) 71 | { 72 | uint8_t buf[] = { 73 | CH341A_CMD_UIO_STREAM, 74 | CH341A_CMD_UIO_STM_OUT | bits, 75 | CH341A_CMD_UIO_STM_END 76 | }; 77 | 78 | return usb_transf(__func__, BULK_WRITE_ENDPOINT, buf, 3); 79 | } 80 | 81 | int ch341a_gpio_getbits(uint8_t *data) 82 | { 83 | int ret; 84 | uint8_t buf[] = { 85 | CH341A_CMD_UIO_STREAM, 86 | CH341A_CMD_UIO_STM_IN, 87 | CH341A_CMD_UIO_STM_END 88 | }; 89 | 90 | ret = usb_transf(__func__, BULK_WRITE_ENDPOINT, buf, 3); 91 | if (ret < 0) 92 | return -1; 93 | 94 | ret = usb_transf(__func__, BULK_READ_ENDPOINT, buf, 1); 95 | if (ret < 0) 96 | return -1; 97 | 98 | *data = buf[0]; 99 | 100 | return ret; 101 | } 102 | /* End of [ch341a_gpio.c] package */ 103 | -------------------------------------------------------------------------------- /src/i2c_eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * i2c_eeprom.c 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "ch347_spi.h" 17 | #include "ch347_i2c.h" 18 | #include "timer.h" 19 | 20 | extern unsigned int bsize; 21 | struct EEPROM eeprom_info; 22 | char eepromname[12]; 23 | int eepromsize = 0; 24 | 25 | int i2c_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len) 26 | { 27 | unsigned char *pbuf, ebuf[MAX_EEPROM_SIZE]; 28 | 29 | if (len == 0) 30 | return -1; 31 | 32 | timer_start(); 33 | memset(ebuf, 0, sizeof(ebuf)); 34 | pbuf = ebuf; 35 | 36 | if (ch347readEEPROM(pbuf, eepromsize, &eeprom_info) < 0) { 37 | printf("Couldn't read [%d] bytes from [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, from); 38 | return -1; 39 | } 40 | 41 | memcpy(buf, pbuf + from, len); 42 | 43 | printf("Read [%d] bytes from [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, from); 44 | timer_end(); 45 | 46 | return (int)len; 47 | } 48 | 49 | int i2c_eeprom_erase(unsigned long offs, unsigned long len) 50 | { 51 | unsigned char *pbuf, ebuf[MAX_EEPROM_SIZE]; 52 | 53 | if (len == 0) 54 | return -1; 55 | 56 | timer_start(); 57 | memset(ebuf, 0xff, sizeof(ebuf)); 58 | pbuf = ebuf; 59 | 60 | if (offs || len < eepromsize) { 61 | if (ch347readEEPROM(pbuf, eepromsize, &eeprom_info) < 0) { 62 | printf("Couldn't read [%d] bytes from [%s] EEPROM\n", eepromsize, eepromname); 63 | return -1; 64 | } 65 | memset(pbuf + offs, 0xff, len); 66 | } 67 | 68 | if(ch347writeEEPROM(pbuf, eepromsize, &eeprom_info) < 0) { 69 | printf("Failed to erase [%d] bytes of [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, offs); 70 | return -1; 71 | } 72 | 73 | printf("Erased [%d] bytes of [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, offs); 74 | timer_end(); 75 | 76 | return 0; 77 | } 78 | 79 | int i2c_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len) 80 | { 81 | unsigned char *pbuf, ebuf[MAX_EEPROM_SIZE]; 82 | 83 | if (len == 0) 84 | return -1; 85 | 86 | timer_start(); 87 | memset(ebuf, 0xff, sizeof(ebuf)); 88 | pbuf = ebuf; 89 | 90 | if (to || len < eepromsize) { 91 | if (ch347readEEPROM(pbuf, eepromsize, &eeprom_info) < 0) { 92 | printf("Couldn't read [%d] bytes from [%s] EEPROM\n", (int)len, eepromname); 93 | return -1; 94 | } 95 | } 96 | memcpy(pbuf + to, buf, len); 97 | 98 | if(ch347writeEEPROM(pbuf, eepromsize, &eeprom_info) < 0) { 99 | printf("Failed to write [%d] bytes of [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, to); 100 | return -1; 101 | } 102 | 103 | printf("Wrote [%d] bytes to [%s] EEPROM address 0x%08lu\n", (int)len, eepromname, to); 104 | timer_end(); 105 | 106 | return (int)len; 107 | } 108 | 109 | long i2c_init(void) 110 | { 111 | if (ch347i2cConfig(CH347_I2C_STANDARD_SPEED) < 0) 112 | return -1; 113 | 114 | if (eepromsize <= 0) { 115 | printf("I2C EEPROM Not Detected!\n"); 116 | return -1; 117 | } 118 | 119 | bsize = 1; 120 | 121 | printf("I2C EEPROM chip: %s, Size: %d bytes\n", eepromname, eepromsize); 122 | 123 | return (long)eepromsize; 124 | } 125 | 126 | void support_i2c_eeprom_list(void) 127 | { 128 | int i; 129 | 130 | printf("I2C EEPROM Support List:\n"); 131 | for ( i = 0; i < (sizeof(eepromlist)/sizeof(struct EEPROM)); i++) 132 | { 133 | if (!eepromlist[i].size) 134 | break; 135 | printf("%03d. %s\n", i + 1, eepromlist[i].name); 136 | } 137 | } 138 | /* End of [i2c_eeprom.c] package */ 139 | -------------------------------------------------------------------------------- /src/mw_eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 McMCC 3 | * mw_eeprom.c 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "bitbang_microwire.h" 26 | #include "ch341a_gpio.h" 27 | #include "timer.h" 28 | 29 | extern struct gpio_cmd bb_func; 30 | extern char eepromname[12]; 31 | extern unsigned int bsize; 32 | 33 | int mw_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len) 34 | { 35 | unsigned char *pbuf, ebuf[MAX_MW_EEPROM_SIZE]; 36 | 37 | if (len == 0) 38 | return -1; 39 | 40 | timer_start(); 41 | memset(ebuf, 0, sizeof(ebuf)); 42 | pbuf = ebuf; 43 | 44 | Read_EEPROM_3wire(pbuf, mw_eepromsize); 45 | memcpy(buf, pbuf + from, len); 46 | 47 | printf("Read [%lu] bytes from [%s] EEPROM address 0x%08lu\n", len, eepromname, from); 48 | timer_end(); 49 | 50 | return (int)len; 51 | } 52 | 53 | int mw_eeprom_erase(unsigned long offs, unsigned long len) 54 | { 55 | unsigned char *pbuf, ebuf[MAX_MW_EEPROM_SIZE]; 56 | 57 | if (len == 0) 58 | return -1; 59 | 60 | timer_start(); 61 | memset(ebuf, 0xff, sizeof(ebuf)); 62 | pbuf = ebuf; 63 | 64 | if (offs || len < mw_eepromsize) { 65 | Read_EEPROM_3wire(pbuf, mw_eepromsize); 66 | memset(pbuf + offs, 0xff, len); 67 | } 68 | 69 | Erase_EEPROM_3wire(mw_eepromsize); 70 | 71 | if (offs || len < mw_eepromsize) { 72 | if (Write_EEPROM_3wire(pbuf, mw_eepromsize) < 0) { 73 | printf("Failed to erase [%lu] bytes of [%s] EEPROM address 0x%08lu\n", len, eepromname, offs); 74 | return -1; 75 | } 76 | } 77 | 78 | printf("Erased [%lu] bytes of [%s] EEPROM address 0x%08lu\n", len, eepromname, offs); 79 | timer_end(); 80 | 81 | return 0; 82 | } 83 | 84 | int mw_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len) 85 | { 86 | unsigned char *pbuf, ebuf[MAX_MW_EEPROM_SIZE]; 87 | 88 | if (len == 0) 89 | return -1; 90 | 91 | timer_start(); 92 | memset(ebuf, 0xff, sizeof(ebuf)); 93 | pbuf = ebuf; 94 | 95 | if (to || len < mw_eepromsize) { 96 | Read_EEPROM_3wire(pbuf, mw_eepromsize); 97 | } 98 | memcpy(pbuf + to, buf, len); 99 | 100 | Erase_EEPROM_3wire(mw_eepromsize); 101 | 102 | if (Write_EEPROM_3wire(pbuf, mw_eepromsize) < 0) { 103 | printf("Failed to write [%lu] bytes of [%s] EEPROM address 0x%08lu\n", len, eepromname, to); 104 | return -1; 105 | } 106 | 107 | printf("Wrote [%lu] bytes to [%s] EEPROM address 0x%08lu\n", len, eepromname, to); 108 | timer_end(); 109 | 110 | return (int)len; 111 | } 112 | 113 | /* 114 | 25xx 93xx 115 | PIN 22 - D7 - MISO DO 116 | PIN 21 - D6 - 117 | PIN 20 - D5 - MOSI DI 118 | PIN 19 - D4 - 119 | PIN 18 - D3 - CLK CLK 120 | PIN 17 - D2 - 121 | PIN 16 - D1 - 122 | PIN 15 - D0 - CS CS 123 | */ 124 | 125 | static int mw_gpio_init(void) 126 | { 127 | int ret = 0; 128 | 129 | CLK = 1 << 3; 130 | DO = 1 << 7; 131 | DI = 1 << 5; 132 | CSEL = 1 << 0; 133 | 134 | bb_func.gpio_setdir = ch341a_gpio_setdir; 135 | bb_func.gpio_setbits = ch341a_gpio_setbits; 136 | bb_func.gpio_getbits = ch341a_gpio_getbits; 137 | 138 | if(bb_func.gpio_setdir) 139 | ret = bb_func.gpio_setdir(); 140 | else 141 | return -1; 142 | 143 | if(ret < 0) 144 | return -1; 145 | 146 | return 0; 147 | } 148 | 149 | static char *__itoa(int a) 150 | { 151 | char *p, tmp[32]; 152 | p = tmp; 153 | snprintf(p, sizeof(tmp), "%d", a); 154 | return p; 155 | } 156 | 157 | 158 | long mw_init(void) 159 | { 160 | if (mw_eepromsize <= 0) { 161 | printf("Microwire EEPROM Not Detected!\n"); 162 | return -1; 163 | } 164 | 165 | if (mw_gpio_init() < 0) 166 | return -1; 167 | 168 | bsize = 1; 169 | 170 | printf("Microwire EEPROM chip: %s, Size: %d bytes, Org: %d bits, fix addr len: %s\n", eepromname, mw_eepromsize / (org ? 2 : 1), 171 | org ? 16 : 8, fix_addr_len ? __itoa(fix_addr_len) : "Auto"); 172 | 173 | return (long)mw_eepromsize; 174 | } 175 | 176 | void support_mw_eeprom_list(void) 177 | { 178 | int i; 179 | 180 | printf("Microwire EEPROM Support List:\n"); 181 | for ( i = 0; i < (sizeof(mw_eepromlist)/sizeof(struct MW_EEPROM)); i++) 182 | { 183 | if (!mw_eepromlist[i].size) 184 | break; 185 | printf("%03d. %s\n", i + 1, mw_eepromlist[i].name); 186 | } 187 | } 188 | /* End of [mw_eeprom.c] package */ 189 | -------------------------------------------------------------------------------- /src/spi_controller.h: -------------------------------------------------------------------------------- 1 | /*====================================================================================== 2 | * MODULE NAME: spi 3 | * FILE NAME: spi_controller.h 4 | * 5 | * FUNCTIONS 6 | * 7 | * SPI_CONTROLLER_Enable_Manual_Mode To provide interface for Enable SPI Controller Manual Mode. 8 | * SPI_CONTROLLER_Write_One_Byte To provide interface for write one byte to SPI bus. 9 | * SPI_CONTROLLER_Write_NByte To provide interface for write N bytes to SPI bus. 10 | * SPI_CONTROLLER_Read_NByte To provide interface for read N bytes from SPI bus. 11 | * SPI_CONTROLLER_Chip_Select_Low To provide interface for set chip select low in SPI bus. 12 | * SPI_CONTROLLER_Chip_Select_High To provide interface for set chip select high in SPI bus. 13 | * 14 | * DEPENDENCIES 15 | * 16 | * * $History: $ 17 | * MODIFICATION HISTORY: 18 | * 19 | *====================================================================================== 20 | */ 21 | 22 | #ifndef __SPI_CONTROLLER_H__ 23 | #define __SPI_CONTROLLER_H__ 24 | 25 | /* INCLUDE FILE DECLARATIONS --------------------------------------------------------- */ 26 | #include "types.h" 27 | 28 | /* NAMING CONSTANT DECLARATIONS ------------------------------------------------------ */ 29 | 30 | /* MACRO DECLARATIONS ---------------------------------------------------------------- */ 31 | 32 | /* TYPE DECLARATIONS ----------------------------------------------------------------- */ 33 | typedef enum{ 34 | SPI_CONTROLLER_SPEED_SINGLE = 0, 35 | SPI_CONTROLLER_SPEED_DUAL, 36 | SPI_CONTROLLER_SPEED_QUAD 37 | 38 | } SPI_CONTROLLER_SPEED_T; 39 | 40 | typedef enum{ 41 | SPI_CONTROLLER_RTN_NO_ERROR = 0, 42 | SPI_CONTROLLER_RTN_SET_OPFIFO_ERROR, 43 | SPI_CONTROLLER_RTN_READ_DATAPFIFO_ERROR, 44 | SPI_CONTROLLER_RTN_WRITE_DATAPFIFO_ERROR, 45 | SPI_CONTROLLER_RTN_DEF_NO 46 | } SPI_CONTROLLER_RTN_T; 47 | 48 | 49 | typedef enum{ 50 | SPI_CONTROLLER_MODE_AUTO = 0, 51 | SPI_CONTROLLER_MODE_MANUAL, 52 | SPI_CONTROLLER_MODE_NO 53 | } SPI_CONTROLLER_MODE_T; 54 | 55 | /*------------------------------------------------------------------------------------ 56 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Enable_Manual_Mode( void ) 57 | * PURPOSE : To provide interface for enable SPI Controller Manual Mode Enable. 58 | * AUTHOR : 59 | * CALLED BY 60 | * - 61 | * CALLS 62 | * - 63 | * PARAMs : 64 | * INPUT : None 65 | * OUTPUT: None 66 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 67 | * NOTES : 68 | * MODIFICATION HISTORY: 69 | *------------------------------------------------------------------------------------ 70 | */ 71 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Enable_Manual_Mode( void ); 72 | 73 | /*------------------------------------------------------------------------------------ 74 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_One_Byte( u8 data ) 75 | * PURPOSE : To provide interface for write one byte to SPI bus. 76 | * AUTHOR : 77 | * CALLED BY 78 | * - 79 | * CALLS 80 | * - 81 | * PARAMs : 82 | * INPUT : data - The data variable of this function. 83 | * OUTPUT: None 84 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 85 | * NOTES : 86 | * MODIFICATION HISTORY: 87 | *------------------------------------------------------------------------------------ 88 | */ 89 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_One_Byte( u8 data ); 90 | 91 | /*------------------------------------------------------------------------------------ 92 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_WRITE_NBYTES( u8 *ptr_data, 93 | * u32 len, 94 | * SPI_CONTROLLER_SPEED_T speed ) 95 | * PURPOSE : To provide interface for write N bytes to SPI bus. 96 | * AUTHOR : 97 | * CALLED BY 98 | * - 99 | * CALLS 100 | * - 101 | * PARAMs : 102 | * INPUT : ptr_data - The data variable of this function. 103 | * len - The len variable of this function. 104 | * speed - The speed variable of this function. 105 | * OUTPUT: None 106 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 107 | * NOTES : 108 | * MODIFICATION HISTORY: 109 | *------------------------------------------------------------------------------------ 110 | */ 111 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_NByte( u8 *ptr_data, u32 len, SPI_CONTROLLER_SPEED_T speed ); 112 | 113 | /*------------------------------------------------------------------------------------ 114 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_READ_NBYTES( u8 *ptr_rtn_data, 115 | * u8 len, 116 | * SPI_CONTROLLER_SPEED_T speed ) 117 | * PURPOSE : To provide interface for read N bytes from SPI bus. 118 | * AUTHOR : 119 | * CALLED BY 120 | * - 121 | * CALLS 122 | * - 123 | * PARAMs : 124 | * INPUT : len - The len variable of this function. 125 | * speed - The speed variable of this function. 126 | * OUTPUT: ptr_rtn_data - The ptr_rtn_data variable of this function. 127 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 128 | * NOTES : 129 | * MODIFICATION HISTORY: 130 | *------------------------------------------------------------------------------------ 131 | */ 132 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Read_NByte( u8 *ptr_rtn_data, u32 len, SPI_CONTROLLER_SPEED_T speed ); 133 | 134 | /*------------------------------------------------------------------------------------ 135 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_Low( void ) 136 | * PURPOSE : To provide interface for set chip select low in SPI bus. 137 | * AUTHOR : 138 | * CALLED BY 139 | * - 140 | * CALLS 141 | * - 142 | * PARAMs : 143 | * INPUT : None 144 | * OUTPUT: None 145 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 146 | * NOTES : 147 | * MODIFICATION HISTORY: 148 | *------------------------------------------------------------------------------------ 149 | */ 150 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_Low( void ); 151 | 152 | /*------------------------------------------------------------------------------------ 153 | * FUNCTION: SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_High( void ) 154 | * PURPOSE : To provide interface for set chip select high in SPI bus. 155 | * AUTHOR : 156 | * CALLED BY 157 | * - 158 | * CALLS 159 | * - 160 | * PARAMs : 161 | * INPUT : None 162 | * OUTPUT: None 163 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 164 | * NOTES : 165 | * MODIFICATION HISTORY: 166 | *------------------------------------------------------------------------------------ 167 | */ 168 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_High( void ); 169 | 170 | #if 0 171 | SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Xfer_NByte( u8 *ptr_data_in, u32 len_in, u8 *ptr_data_out, u32 len_out, SPI_CONTROLLER_SPEED_T speed ); 172 | #endif 173 | 174 | #endif /* ifndef __SPI_CONTROLLER_H__ */ 175 | /* End of [spi_controller.h] package */ 176 | -------------------------------------------------------------------------------- /src/spi_eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 McMCC 3 | * spi_eeprom.c 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "timer.h" 22 | #include "spi_eeprom.h" 23 | #include "spi_controller.h" 24 | 25 | extern unsigned int bsize; 26 | extern char eepromname[12]; 27 | struct spi_eeprom seeprom_info; 28 | int seepromsize = 0; 29 | int spage_size = 0; 30 | 31 | static void wait_ready(void) 32 | { 33 | uint8_t data[1]; 34 | 35 | while (1) { 36 | SPI_CONTROLLER_Chip_Select_Low(); 37 | SPI_CONTROLLER_Write_One_Byte(SEEP_RDSR_CMD); 38 | SPI_CONTROLLER_Read_NByte(data, 1, SPI_CONTROLLER_SPEED_SINGLE); 39 | SPI_CONTROLLER_Chip_Select_High(); 40 | 41 | if ((data[0] & 0x01) == 0) break; 42 | usleep(1); 43 | } 44 | } 45 | 46 | static void write_enable(void) 47 | { 48 | uint8_t data[1]; 49 | 50 | while (1) { 51 | SPI_CONTROLLER_Chip_Select_Low(); 52 | SPI_CONTROLLER_Write_One_Byte(SEEP_WREN_CMD); 53 | SPI_CONTROLLER_Chip_Select_High(); 54 | usleep(1); 55 | 56 | SPI_CONTROLLER_Chip_Select_Low(); 57 | SPI_CONTROLLER_Write_One_Byte(SEEP_RDSR_CMD); 58 | SPI_CONTROLLER_Read_NByte(data, 1, SPI_CONTROLLER_SPEED_SINGLE); 59 | SPI_CONTROLLER_Chip_Select_High(); 60 | 61 | if (data[0] == 0x02) break; 62 | usleep(1); 63 | } 64 | } 65 | 66 | static void eeprom_write_byte(struct spi_eeprom *dev, uint32_t address, uint8_t data) 67 | { 68 | uint8_t buf[5]; 69 | 70 | write_enable(); 71 | 72 | buf[0] = SEEP_WRITE_CMD; 73 | if (dev->addr_bits == 9 && address > 0xFF) 74 | buf[0] = buf[0] | 0x08; 75 | 76 | SPI_CONTROLLER_Chip_Select_Low(); 77 | if (dev->addr_bits > 16) { 78 | buf[1] = (address & 0xFF0000) >> 16; 79 | buf[2] = (address & 0xFF00) >> 8; 80 | buf[3] = (address & 0xFF); 81 | buf[4] = data; 82 | SPI_CONTROLLER_Write_NByte(buf, 5, SPI_CONTROLLER_SPEED_SINGLE); 83 | } else if (dev->addr_bits < 10) { 84 | buf[1] = (address & 0xFF); 85 | buf[2] = data; 86 | SPI_CONTROLLER_Write_NByte(buf, 3, SPI_CONTROLLER_SPEED_SINGLE); 87 | } else { 88 | buf[1] = (address & 0xFF00) >> 8; 89 | buf[2] = (address & 0xFF); 90 | buf[3] = data; 91 | SPI_CONTROLLER_Write_NByte(buf, 4, SPI_CONTROLLER_SPEED_SINGLE); 92 | } 93 | SPI_CONTROLLER_Chip_Select_High(); 94 | 95 | wait_ready(); 96 | } 97 | 98 | static void eeprom_write_page(struct spi_eeprom *dev, uint32_t address, int page_size, uint8_t *data) 99 | { 100 | uint8_t buf[MAX_SEEP_PSIZE]; 101 | uint8_t offs = 0; 102 | 103 | memset(buf, 0, sizeof(buf)); 104 | 105 | buf[0] = SEEP_WRITE_CMD; 106 | if (dev->addr_bits == 9 && address > 0xFF) 107 | buf[0] = buf[0] | 0x08; 108 | 109 | if (dev->addr_bits > 16) { 110 | buf[1] = (address & 0xFF0000) >> 16; 111 | buf[2] = (address & 0xFF00) >> 8; 112 | buf[3] = (address & 0xFF); 113 | offs = 4; 114 | } else if (dev->addr_bits < 10) { 115 | buf[1] = (address & 0xFF); 116 | offs = 2; 117 | } else { 118 | buf[1] = (address & 0xFF00) >> 8; 119 | buf[2] = (address & 0xFF); 120 | offs = 3; 121 | } 122 | 123 | memcpy(&buf[offs], data, page_size); 124 | 125 | write_enable(); 126 | 127 | SPI_CONTROLLER_Chip_Select_Low(); 128 | SPI_CONTROLLER_Write_NByte(buf, offs + page_size, SPI_CONTROLLER_SPEED_SINGLE); 129 | SPI_CONTROLLER_Chip_Select_High(); 130 | 131 | wait_ready(); 132 | } 133 | 134 | static uint8_t eeprom_read_byte(struct spi_eeprom *dev, uint32_t address) 135 | { 136 | uint8_t buf[4]; 137 | uint8_t data; 138 | buf[0] = SEEP_READ_CMD; 139 | 140 | if (dev->addr_bits == 9 && address > 0xFF) 141 | buf[0] = buf[0] | 0x08; 142 | 143 | SPI_CONTROLLER_Chip_Select_Low(); 144 | if (dev->addr_bits > 16) { 145 | buf[1] = (address & 0xFF0000) >> 16; 146 | buf[2] = (address & 0xFF00) >> 8; 147 | buf[3] = (address & 0xFF); 148 | SPI_CONTROLLER_Write_NByte(buf, 4, SPI_CONTROLLER_SPEED_SINGLE); 149 | SPI_CONTROLLER_Read_NByte(buf, 1, SPI_CONTROLLER_SPEED_SINGLE); 150 | data = buf[0]; 151 | } else if (dev->addr_bits < 10) { 152 | buf[1] = (address & 0xFF); 153 | SPI_CONTROLLER_Write_NByte(buf, 2, SPI_CONTROLLER_SPEED_SINGLE); 154 | SPI_CONTROLLER_Read_NByte(buf, 1, SPI_CONTROLLER_SPEED_SINGLE); 155 | data = buf[0]; 156 | } else { 157 | buf[1] = (address & 0xFF00) >> 8; 158 | buf[2] = (address & 0xFF); 159 | SPI_CONTROLLER_Write_NByte(buf, 3, SPI_CONTROLLER_SPEED_SINGLE); 160 | SPI_CONTROLLER_Read_NByte(buf, 1, SPI_CONTROLLER_SPEED_SINGLE); 161 | data = buf[0]; 162 | } 163 | SPI_CONTROLLER_Chip_Select_High(); 164 | 165 | return data; 166 | } 167 | 168 | int32_t parseSEEPsize(char *seepromname, struct spi_eeprom *seeprom) 169 | { 170 | int i; 171 | 172 | for (i = 0; seepromlist[i].total_bytes; i++) { 173 | if (strstr(seepromlist[i].name, seepromname)) { 174 | memcpy(seeprom, &(seepromlist[i]), sizeof(struct spi_eeprom)); 175 | return (seepromlist[i].total_bytes); 176 | } 177 | } 178 | 179 | return -1; 180 | } 181 | 182 | int spi_eeprom_read(unsigned char *buf, unsigned long from, unsigned long len) 183 | { 184 | unsigned char *pbuf, ebuf[MAX_SEEP_SIZE]; 185 | uint32_t i; 186 | 187 | if (len == 0) 188 | return -1; 189 | 190 | timer_start(); 191 | memset(ebuf, 0, sizeof(ebuf)); 192 | pbuf = ebuf; 193 | 194 | for (i = 0; i < seepromsize; i++) { 195 | pbuf[i] = eeprom_read_byte(&seeprom_info, i); 196 | if( timer_progress() ) 197 | { 198 | printf("\bRead %d%% [%d] of [%d] bytes ", 100 * i / seepromsize, i, seepromsize); 199 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 200 | fflush(stdout); 201 | } 202 | } 203 | memcpy(buf, pbuf + from, len); 204 | 205 | printf("Read 100%% [%lu] bytes from [%s] EEPROM address 0x%08lu\n", len, eepromname, from); 206 | timer_end(); 207 | 208 | return (int)len; 209 | } 210 | 211 | int spi_eeprom_erase(unsigned long offs, unsigned long len) 212 | { 213 | unsigned char *pbuf, ebuf[MAX_SEEP_SIZE]; 214 | uint32_t i; 215 | 216 | if (len == 0) 217 | return -1; 218 | 219 | timer_start(); 220 | memset(ebuf, 0xff, sizeof(ebuf)); 221 | pbuf = ebuf; 222 | 223 | if (offs || len < seepromsize) { 224 | for (i = 0; i < seepromsize; i++) 225 | pbuf[i] = eeprom_read_byte(&seeprom_info, i); 226 | memset(pbuf + offs, 0xff, len); 227 | } 228 | 229 | for (i = 0; i < seepromsize; i++) { 230 | if (spage_size) { 231 | eeprom_write_page(&seeprom_info, i, spage_size, pbuf + i); 232 | i = (spage_size + i) - 1; 233 | } else 234 | eeprom_write_byte(&seeprom_info, i, pbuf[i]); 235 | if( timer_progress() ) 236 | { 237 | printf("\bErase %d%% [%d] of [%d] bytes ", 100 * i / seepromsize, i, seepromsize); 238 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 239 | fflush(stdout); 240 | } 241 | } 242 | 243 | printf("Erased 100%% [%lu] bytes of [%s] EEPROM address 0x%08lu\n", len, eepromname, offs); 244 | timer_end(); 245 | 246 | return 0; 247 | } 248 | 249 | int spi_eeprom_write(unsigned char *buf, unsigned long to, unsigned long len) 250 | { 251 | unsigned char *pbuf, ebuf[MAX_SEEP_SIZE]; 252 | uint32_t i; 253 | 254 | if (len == 0) 255 | return -1; 256 | 257 | timer_start(); 258 | memset(ebuf, 0xff, sizeof(ebuf)); 259 | pbuf = ebuf; 260 | 261 | if (to || len < seepromsize) { 262 | for (i = 0; i < seepromsize; i++) 263 | pbuf[i] = eeprom_read_byte(&seeprom_info, i); 264 | } 265 | memcpy(pbuf + to, buf, len); 266 | 267 | for (i = 0; i < seepromsize; i++) { 268 | if (spage_size) { 269 | eeprom_write_page(&seeprom_info, i, spage_size, pbuf + i); 270 | i = (spage_size + i) - 1; 271 | } else 272 | eeprom_write_byte(&seeprom_info, i, pbuf[i]); 273 | if( timer_progress() ) 274 | { 275 | printf("\bWritten %d%% [%d] of [%d] bytes ", 100 * i / seepromsize, i, seepromsize); 276 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 277 | fflush(stdout); 278 | } 279 | } 280 | 281 | printf("Written 100%% [%lu] bytes to [%s] EEPROM address 0x%08lu\n", len, eepromname, to); 282 | timer_end(); 283 | 284 | return (int)len; 285 | } 286 | 287 | long spi_eeprom_init(void) 288 | { 289 | if (seepromsize <= 0) { 290 | printf("SPI EEPROM Not Detected!\n"); 291 | return -1; 292 | } 293 | 294 | bsize = 1; 295 | 296 | printf("SPI EEPROM chip: %s, Size: %d bytes\n", eepromname, seepromsize); 297 | 298 | return (long)seepromsize; 299 | } 300 | 301 | void support_spi_eeprom_list(void) 302 | { 303 | int i; 304 | 305 | printf("SPI EEPROM Support List:\n"); 306 | for ( i = 0; i < (sizeof(seepromlist)/sizeof(struct spi_eeprom)); i++) 307 | { 308 | if (!seepromlist[i].total_bytes) 309 | break; 310 | printf("%03d. %s\n", i + 1, seepromlist[i].name); 311 | } 312 | } 313 | /* End of [spi_eeprom.c] package */ 314 | -------------------------------------------------------------------------------- /src/bitbang_microwire.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2005-2021 Mokrushin I.V. aka McMCC mcmcc@mail.ru 2 | A simple bitbang protocol for Microwire 8-pin serial EEPROMs 3 | (93XX devices). Support organization 8bit and 16bit(8bit emulation). 4 | 5 | bitbang_microwire.c 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 20 | /* ------------------------------------------------------------------------- */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "bitbang_microwire.h" 27 | 28 | struct gpio_cmd bb_func; 29 | 30 | #if 0 31 | unsigned char ORG = 0; /* organization 0 = 8 bit and 1 = 16 bit */ 32 | #endif 33 | unsigned char CLK = 0; 34 | unsigned char DO = 0; 35 | unsigned char DI = 0; 36 | unsigned char CSEL = 0; 37 | 38 | int org = 0; 39 | int mw_eepromsize = 0; 40 | int fix_addr_len = 0; 41 | 42 | static unsigned char data = 0; 43 | 44 | static void delay_ms(int n) 45 | { 46 | #if 0 /* ifndef _WINDOWS */ 47 | int i; 48 | for(i = 0; i < (n * 100000); i++); 49 | #else 50 | usleep(n); 51 | #endif 52 | } 53 | 54 | static void data_1() 55 | { 56 | data = data | DI; 57 | if (bb_func.gpio_setbits) 58 | bb_func.gpio_setbits(data); 59 | } 60 | 61 | static void data_0() 62 | { 63 | data = data & (~DI); 64 | if (bb_func.gpio_setbits) 65 | bb_func.gpio_setbits(data); 66 | } 67 | 68 | static void org_1() 69 | { 70 | #if 0 71 | data = data | ORG; /* 16bit */ 72 | if (bb_func.gpio_setbits) 73 | bb_func.gpio_setbits(data); 74 | #endif 75 | } 76 | 77 | static void org_0() 78 | { 79 | #if 0 80 | data = data & (~ORG); /* 8bit */ 81 | if (bb_func.gpio_setbits) 82 | bb_func.gpio_setbits(data); 83 | #endif 84 | } 85 | 86 | static void csel_1() 87 | { 88 | data = data | CSEL; 89 | if (bb_func.gpio_setbits) 90 | bb_func.gpio_setbits(data); 91 | } 92 | 93 | static void csel_0() 94 | { 95 | data = data & (~CSEL); 96 | if (bb_func.gpio_setbits) 97 | bb_func.gpio_setbits(data); 98 | } 99 | 100 | static void clock_1() 101 | { 102 | data = data | CLK; 103 | if (bb_func.gpio_setbits) 104 | bb_func.gpio_setbits(data); 105 | } 106 | 107 | static void clock_0() 108 | { 109 | data = data & (~CLK); 110 | if (bb_func.gpio_setbits) 111 | bb_func.gpio_setbits(data); 112 | } 113 | 114 | static unsigned int get_data() 115 | { 116 | unsigned char b = 0; 117 | if (bb_func.gpio_getbits) 118 | bb_func.gpio_getbits(&b); 119 | return ((b & DO) == DO); 120 | } 121 | 122 | static int addr_nbits(const char *func, int size) 123 | { 124 | int i = 0; 125 | 126 | if (fix_addr_len) { 127 | printf("%s: Set address len %d bits\n", func, fix_addr_len); 128 | return fix_addr_len; 129 | } 130 | 131 | switch (size) { 132 | case 128: /* 93c46 */ 133 | i = org ? 6 : 7; 134 | break; 135 | case 256: /* 93c56 */ 136 | case 512: /* 93c66 */ 137 | i = org ? 8 : 9; 138 | break; 139 | case 1024: /* 93c76 */ 140 | case 2048: /* 93c86 */ 141 | i = org ? 10 : 11; 142 | break; 143 | case 4096: /* 93c96(not original name) */ 144 | i = org ? 12 : 13; 145 | break; 146 | default: 147 | i = 6; /* 93c06 and 93c16(not original name) */ 148 | break; 149 | } 150 | 151 | printf("%s: Set address len %d bits\n", func, i); 152 | 153 | return i; 154 | } 155 | 156 | static int convert_size(int eeprom_size) 157 | { 158 | int k = 1; 159 | 160 | org_0(); 161 | delay_ms(1); 162 | if (org) 163 | { 164 | org_1(); 165 | delay_ms(1); 166 | k = 2; 167 | } 168 | eeprom_size = eeprom_size / k; 169 | 170 | return eeprom_size; 171 | } 172 | 173 | static void send_to_di(unsigned int val, int nbit) 174 | { 175 | int b = 0, i = 0; 176 | 177 | while (i < nbit) 178 | { 179 | b = val & (1 << ((nbit - i++) - 1)); 180 | clock_0(); 181 | if (b) 182 | data_1(); 183 | else 184 | data_0(); 185 | delay_ms(1); 186 | clock_1(); 187 | delay_ms(1); 188 | } 189 | } 190 | 191 | static unsigned char get_from_do() 192 | { 193 | unsigned char val = 0; 194 | int b = 0, i = 0; 195 | while (i < 8) 196 | { 197 | clock_0(); 198 | delay_ms(1); 199 | b = get_data(); 200 | clock_1(); 201 | delay_ms(1); 202 | val |= (b << (7 - i++)); 203 | } 204 | return val; 205 | } 206 | 207 | static void enable_write_3wire(int num_bit) 208 | { 209 | csel_0(); 210 | clock_0(); 211 | delay_ms(1); 212 | data_1(); 213 | csel_1(); 214 | delay_ms(1); 215 | clock_1(); 216 | delay_ms(1); 217 | 218 | send_to_di(3, 4); 219 | send_to_di(0, num_bit - 2); 220 | 221 | data_0(); 222 | delay_ms(1); 223 | csel_0(); 224 | delay_ms(1); 225 | } 226 | 227 | static void disable_write_3wire(int num_bit) 228 | { 229 | csel_1(); 230 | delay_ms(1); 231 | clock_0(); 232 | delay_ms(1); 233 | data_1(); 234 | delay_ms(1); 235 | clock_1(); 236 | delay_ms(1); 237 | send_to_di(0, 4); 238 | send_to_di(0, num_bit - 2); 239 | csel_0(); 240 | delay_ms(1); 241 | } 242 | 243 | static void chip_busy(void) 244 | { 245 | printf("Error: Always BUSY! Communication problem...The broken microwire chip?\n"); 246 | } 247 | 248 | void Erase_EEPROM_3wire(int size_eeprom) 249 | { 250 | int i, num_bit; 251 | 252 | num_bit = addr_nbits(__func__, size_eeprom); 253 | 254 | enable_write_3wire(num_bit); 255 | csel_0(); 256 | clock_0(); 257 | delay_ms(1); 258 | data_1(); 259 | csel_1(); 260 | delay_ms(1); 261 | clock_1(); 262 | delay_ms(1); 263 | 264 | send_to_di(2, 4); 265 | send_to_di(0, num_bit - 2); 266 | clock_0(); 267 | data_0(); 268 | delay_ms(1); 269 | csel_0(); 270 | delay_ms(1); 271 | csel_1(); 272 | delay_ms(1); 273 | clock_1(); 274 | delay_ms(1); 275 | i = 0; 276 | while (!get_data() && i < 10000) 277 | { 278 | clock_0(); 279 | delay_ms(1); 280 | clock_1(); 281 | delay_ms(1); 282 | i++; 283 | } 284 | 285 | if (i == 10000) 286 | { 287 | chip_busy(); 288 | return; 289 | } 290 | 291 | csel_0(); 292 | delay_ms(1); 293 | clock_0(); 294 | delay_ms(1); 295 | clock_1(); 296 | delay_ms(1); 297 | 298 | disable_write_3wire(num_bit); 299 | } 300 | 301 | int Read_EEPROM_3wire(unsigned char *buffer, int size_eeprom) 302 | { 303 | int address, num_bit, l; 304 | 305 | num_bit = addr_nbits(__func__, size_eeprom); 306 | size_eeprom = convert_size(size_eeprom); 307 | 308 | address = 0; 309 | 310 | for (l = 0; l < size_eeprom; l++) 311 | { 312 | csel_0(); 313 | clock_0(); 314 | delay_ms(1); 315 | data_1(); 316 | csel_1(); 317 | delay_ms(1); 318 | clock_1(); 319 | delay_ms(1); 320 | 321 | send_to_di(2, 2); 322 | send_to_di(l, num_bit); 323 | 324 | data_0(); 325 | clock_0(); 326 | delay_ms(1); 327 | clock_1(); 328 | delay_ms(1); 329 | buffer[address] = get_from_do(); 330 | if (org) 331 | { 332 | address++; 333 | buffer[address] = get_from_do(); 334 | } 335 | csel_0(); 336 | delay_ms(1); 337 | clock_0(); 338 | delay_ms(1); 339 | clock_1(); 340 | delay_ms(1); 341 | printf("\bRead %d%% [%d] of [%d] bytes ", 100 * l / size_eeprom, l, size_eeprom); 342 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 343 | fflush(stdout); 344 | address++; 345 | } 346 | printf("Read 100%% [%d] of [%d] bytes \n", l, size_eeprom); 347 | return 0; 348 | } 349 | 350 | int Write_EEPROM_3wire(unsigned char *buffer, int size_eeprom) 351 | { 352 | int i, l, address, num_bit; 353 | 354 | num_bit = addr_nbits(__func__, size_eeprom); 355 | size_eeprom = convert_size(size_eeprom); 356 | 357 | enable_write_3wire(num_bit); 358 | address = 0; 359 | 360 | for (l = 0; l < size_eeprom; l++) 361 | { 362 | csel_0(); 363 | clock_0(); 364 | delay_ms(1); 365 | data_1(); 366 | csel_1(); 367 | delay_ms(1); 368 | clock_1(); 369 | delay_ms(1); 370 | send_to_di(1, 2); 371 | send_to_di(l, num_bit); 372 | send_to_di(buffer[address], 8); 373 | if (org) 374 | { 375 | address++; 376 | send_to_di(buffer[address], 8); 377 | } 378 | clock_0(); 379 | data_0(); 380 | delay_ms(1); 381 | csel_0(); 382 | delay_ms(1); 383 | csel_1(); 384 | delay_ms(1); 385 | clock_1(); 386 | delay_ms(1); 387 | i = 0; 388 | while (!get_data() && i < 10000) 389 | { 390 | clock_0(); 391 | delay_ms(1); 392 | clock_1(); 393 | delay_ms(1); 394 | i++; 395 | } 396 | if (i == 10000) 397 | { 398 | printf("\n"); 399 | chip_busy(); 400 | return -1; 401 | } 402 | 403 | csel_0(); 404 | delay_ms(1); 405 | clock_0(); 406 | delay_ms(1); 407 | clock_1(); 408 | delay_ms(1); 409 | printf("\bWritten %d%% [%d] of [%d] bytes ", 100 * l / size_eeprom, l, size_eeprom); 410 | printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 411 | fflush(stdout); 412 | address++; 413 | } 414 | printf("Written 100%% [%d] of [%d] bytes \n", l, size_eeprom); 415 | disable_write_3wire(num_bit); 416 | 417 | return 0; 418 | } 419 | 420 | int deviceSize_3wire(char *eepromname) 421 | { 422 | int i; 423 | 424 | for (i = 0; mw_eepromlist[i].size; i++) { 425 | if (strstr(mw_eepromlist[i].name, eepromname)) { 426 | return (mw_eepromlist[i].size); 427 | } 428 | } 429 | 430 | return -1; 431 | } 432 | /* End of [bitbang_microwire.c] package */ 433 | -------------------------------------------------------------------------------- /src/spi_nand_flash.h: -------------------------------------------------------------------------------- 1 | /*====================================================================================== 2 | * MODULE NAME: spi 3 | * FILE NAME: spi_nand_flash.h 4 | * DATE: 5 | * VERSION: 1.00 6 | * PURPOSE: To Provide SPI NAND Access interface. 7 | * NOTES: 8 | * 9 | * AUTHOR : 10 | * 11 | * FUNCTIONS 12 | * SPI_NAND_Flash_Init To provide interface for SPI NAND init. 13 | * SPI_NAND_Flash_Get_Flash_Info To get the system current flash info. 14 | * SPI_NAND_Flash_Write_Nbyte To provide interface for Write N Bytes into SPI NAND Flash. 15 | * SPI_NAND_Flash_Read_NByte To provide interface for Read N Bytes from SPI NAND Flash. 16 | * SPI_NAND_Flash_Erase To provide interface for Erase SPI NAND Flash. 17 | * SPI_NAND_Flash_Read_Byte To provide interface for read 1 Bytes from SPI NAND Flash. 18 | * SPI_NAND_Flash_Read_DWord To provide interface for read Double Word from SPI NAND Flash. 19 | * 20 | * DEPENDENCIES 21 | * 22 | * * $History: $ 23 | * MODIFICATION HISTORY: 24 | *====================================================================================== 25 | */ 26 | 27 | #ifndef __SPI_NAND_FLASH_H__ 28 | #define __SPI_NAND_FLASH_H__ 29 | 30 | /* INCLUDE FILE DECLARATIONS --------------------------------------------------------- */ 31 | #include "types.h" 32 | #include "ch347_spi.h" 33 | 34 | /* MACRO DECLARATIONS ---------------------------------------------------------------- */ 35 | #define SPI_NAND_FLASH_OOB_FREE_ENTRY_MAX 32 36 | 37 | /* TYPE DECLARATIONS ----------------------------------------------------------------- */ 38 | typedef enum{ 39 | SPI_NAND_FLASH_READ_DUMMY_BYTE_PREPEND, 40 | SPI_NAND_FLASH_READ_DUMMY_BYTE_APPEND, 41 | SPI_NAND_FLASH_READ_DUMMY_BYTE_DEF_NO 42 | } SPI_NAND_FLASH_READ_DUMMY_BYTE_T; 43 | 44 | typedef enum{ 45 | SPI_NAND_FLASH_RTN_NO_ERROR = 0, 46 | SPI_NAND_FLASH_RTN_PROBE_ERROR, 47 | SPI_NAND_FLASH_RTN_ALIGNED_CHECK_FAIL, 48 | SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK, 49 | SPI_NAND_FLASH_RTN_ERASE_FAIL, 50 | SPI_NAND_FLASH_RTN_PROGRAM_FAIL, 51 | SPI_NAND_FLASH_RTN_DEF_NO 52 | } SPI_NAND_FLASH_RTN_T; 53 | 54 | typedef enum{ 55 | SPI_NAND_FLASH_READ_SPEED_MODE_SINGLE = 0, 56 | SPI_NAND_FLASH_READ_SPEED_MODE_DUAL, 57 | SPI_NAND_FLASH_READ_SPEED_MODE_QUAD, 58 | SPI_NAND_FLASH_READ_SPEED_MODE_DEF_NO 59 | } SPI_NAND_FLASH_READ_SPEED_MODE_T; 60 | 61 | 62 | typedef enum{ 63 | SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE = 0, 64 | SPI_NAND_FLASH_WRITE_SPEED_MODE_QUAD, 65 | SPI_NAND_FLASH_WRITE_SPEED_MODE_DEF_NO 66 | } SPI_NAND_FLASH_WRITE_SPEED_MODE_T; 67 | 68 | 69 | typedef enum{ 70 | SPI_NAND_FLASH_DEBUG_LEVEL_0 = 0, 71 | SPI_NAND_FLASH_DEBUG_LEVEL_1, 72 | SPI_NAND_FLASH_DEBUG_LEVEL_2, 73 | SPI_NAND_FLASH_DEBUG_LEVEL_DEF_NO 74 | } SPI_NAND_FLASH_DEBUG_LEVEL_T; 75 | 76 | /* Bitwise */ 77 | #define SPI_NAND_FLASH_FEATURE_NONE ( 0x00 ) 78 | #define SPI_NAND_FLASH_PLANE_SELECT_HAVE ( 0x01 << 0 ) 79 | #define SPI_NAND_FLASH_DIE_SELECT_1_HAVE ( 0x01 << 1 ) 80 | #define SPI_NAND_FLASH_DIE_SELECT_2_HAVE ( 0x01 << 2 ) 81 | 82 | struct SPI_NAND_FLASH_INFO_T { 83 | u8 mfr_id; 84 | u8 dev_id; 85 | u8 dev_id_2; 86 | const char *ptr_name; 87 | u32 device_size; /* Flash total Size */ 88 | u32 page_size; /* Page Size */ 89 | u32 erase_size; /* Block Size */ 90 | u32 oob_size; /* Spare Area (OOB) Size */ 91 | SPI_NAND_FLASH_READ_DUMMY_BYTE_T dummy_mode; 92 | SPI_NAND_FLASH_READ_SPEED_MODE_T read_mode; 93 | SPI_NAND_FLASH_WRITE_SPEED_MODE_T write_mode; 94 | u32 feature; 95 | }; 96 | 97 | struct nand_info { 98 | int mfr_id; 99 | int dev_id; 100 | char *name; 101 | int numchips; 102 | int chip_shift; 103 | int page_shift; 104 | int erase_shift; 105 | int oob_shift; 106 | int badblockpos; 107 | int opcode_type; 108 | }; 109 | 110 | struct ra_nand_chip { 111 | struct nand_info *flash; 112 | }; 113 | 114 | /* EXPORTED SUBPROGRAM SPECIFICATION ------------------------------------------------- */ 115 | 116 | /*------------------------------------------------------------------------------------ 117 | * FUNCTION: SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Init( long rom_base ) 118 | * PURPOSE : To provide interface for SPI NAND init. 119 | * AUTHOR : 120 | * CALLED BY 121 | * - 122 | * CALLS 123 | * - 124 | * PARAMs : 125 | * INPUT : rom_base - The rom_base variable of this function. 126 | * OUTPUT: None 127 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 128 | * NOTES : 129 | * MODIFICATION HISTORY: 130 | * 131 | *------------------------------------------------------------------------------------ 132 | */ 133 | SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Init( u32 rom_base ); 134 | 135 | /*------------------------------------------------------------------------------------ 136 | * FUNCTION: SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Get_Flash_Info( struct SPI_NAND_FLASH_INFO_T *ptr_rtn_into_t ) 137 | * PURPOSE : To get system current flash info. 138 | * AUTHOR : 139 | * CALLED BY 140 | * - 141 | * CALLS 142 | * - 143 | * PARAMs : 144 | * INPUT : None 145 | * OUTPUT: ptr_rtn_into_t - A pointer to the structure of the ptr_rtn_into_t variable. 146 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 147 | * NOTES : 148 | * MODIFICATION HISTORY: 149 | * 150 | *------------------------------------------------------------------------------------ 151 | */ 152 | SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Get_Flash_Info( struct SPI_NAND_FLASH_INFO_T *ptr_rtn_into_t); 153 | 154 | /*------------------------------------------------------------------------------------ 155 | * FUNCTION: SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Write_Nbyte( u32 dst_addr, 156 | * u32 len, 157 | * u32 *ptr_rtn_len, 158 | * u8* ptr_buf ) 159 | * PURPOSE : To provide interface for Write N Bytes into SPI NAND Flash. 160 | * AUTHOR : 161 | * CALLED BY 162 | * - 163 | * CALLS 164 | * - 165 | * PARAMs : 166 | * INPUT : dst_addr - The dst_addr variable of this function. 167 | * len - The len variable of this function. 168 | * buf - The buf variable of this function. 169 | * OUTPUT: rtn_len - The rtn_len variable of this function. 170 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 171 | * NOTES : 172 | * MODIFICATION HISTORY: 173 | * 174 | *------------------------------------------------------------------------------------ 175 | */ 176 | SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Write_Nbyte( u32 dst_addr, 177 | u32 len, 178 | u32 *ptr_rtn_len, 179 | u8 *ptr_buf, 180 | SPI_NAND_FLASH_WRITE_SPEED_MODE_T speed_mode ); 181 | 182 | /*------------------------------------------------------------------------------------ 183 | * FUNCTION: int SPI_NAND_Flash_Read_NByte( long addr, 184 | * long len, 185 | * long *retlen, 186 | * char *buf ) 187 | * PURPOSE : To provide interface for Read N Bytes from SPI NAND Flash. 188 | * AUTHOR : 189 | * CALLED BY 190 | * - 191 | * CALLS 192 | * - 193 | * PARAMs : 194 | * INPUT : addr - The addr variable of this function. 195 | * len - The len variable of this function. 196 | * retlen - The retlen variable of this function. 197 | * buf - The buf variable of this function. 198 | * OUTPUT: None 199 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 200 | * NOTES : 201 | * MODIFICATION HISTORY: 202 | * 203 | *------------------------------------------------------------------------------------ 204 | */ 205 | u32 SPI_NAND_Flash_Read_NByte( u32 addr, 206 | u32 len, 207 | u32 *retlen, 208 | u8 *buf, 209 | SPI_NAND_FLASH_READ_SPEED_MODE_T speed_mode, 210 | SPI_NAND_FLASH_RTN_T *status ); 211 | 212 | /*------------------------------------------------------------------------------------ 213 | * FUNCTION: SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Erase( u32 dst_addr, 214 | * u32 len ) 215 | * PURPOSE : To provide interface for Erase SPI NAND Flash. 216 | * AUTHOR : 217 | * CALLED BY 218 | * - 219 | * CALLS 220 | * - 221 | * PARAMs : 222 | * INPUT : dst_addr - The dst_addr variable of this function. 223 | * len - The len variable of this function. 224 | * OUTPUT: None 225 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 226 | * NOTES : 227 | * MODIFICATION HISTORY: 228 | * 229 | *------------------------------------------------------------------------------------ 230 | */ 231 | SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Erase( u32 dst_addr, 232 | u32 len ); 233 | 234 | /*------------------------------------------------------------------------------------ 235 | * FUNCTION: char SPI_NAND_Flash_Read_Byte( long addr ) 236 | * PURPOSE : To provide interface for read 1 Bytes from SPI NAND Flash. 237 | * AUTHOR : 238 | * CALLED BY 239 | * - 240 | * CALLS 241 | * - 242 | * PARAMs : 243 | * INPUT : addr - The addr variable of this function. 244 | * OUTPUT: None 245 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 246 | * NOTES : 247 | * MODIFICATION HISTORY: 248 | * 249 | *------------------------------------------------------------------------------------ 250 | */ 251 | unsigned char SPI_NAND_Flash_Read_Byte( unsigned long addr, SPI_NAND_FLASH_RTN_T *status); 252 | 253 | /*------------------------------------------------------------------------------------ 254 | * FUNCTION: long SPI_NAND_Flash_Read_DWord( long addr ) 255 | * PURPOSE : To provide interface for read Double Word from SPI NAND Flash. 256 | * AUTHOR : 257 | * CALLED BY 258 | * - 259 | * CALLS 260 | * - 261 | * PARAMs : 262 | * INPUT : addr - The addr variable of this function. 263 | * OUTPUT: None 264 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 265 | * NOTES : 266 | * MODIFICATION HISTORY: 267 | * 268 | *------------------------------------------------------------------------------------ 269 | */ 270 | unsigned long SPI_NAND_Flash_Read_DWord( unsigned long addr, SPI_NAND_FLASH_RTN_T *status); 271 | 272 | /*------------------------------------------------------------------------------------ 273 | * FUNCTION: void SPI_NAND_Flash_Clear_Read_Cache_Data( void ) 274 | * PURPOSE : To clear the cache data for read. 275 | * (The next time to read data will get data from flash chip certainly.) 276 | * AUTHOR : 277 | * CALLED BY 278 | * - 279 | * CALLS 280 | * - 281 | * PARAMs : 282 | * INPUT : None 283 | * OUTPUT: None 284 | * RETURN : SPI_RTN_NO_ERROR - Successful. Otherwise - Failed. 285 | * NOTES : 286 | * MODIFICATION HISTORY: 287 | * 288 | *------------------------------------------------------------------------------------ 289 | */ 290 | void SPI_NAND_Flash_Clear_Read_Cache_Data( void ); 291 | 292 | SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Enable_OnDie_ECC( void ); 293 | 294 | SPI_NAND_FLASH_RTN_T spi_nand_erase_block ( u32 block_index); 295 | 296 | #endif /* ifndef __SPI_NAND_FLASH_H__ */ 297 | /* End of [spi_nand_flash.h] package */ 298 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2022 McMCC 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "flashcmd_api.h" 28 | #include "ch347_spi.h" 29 | #include "spi_nand_flash.h" 30 | 31 | struct flash_cmd prog; 32 | extern unsigned int bsize; 33 | 34 | #ifdef EEPROM_SUPPORT 35 | #include "ch347_i2c.h" 36 | #include "bitbang_microwire.h" 37 | #include "spi_eeprom.h" 38 | extern struct EEPROM eeprom_info; 39 | extern struct spi_eeprom seeprom_info; 40 | extern char eepromname[12]; 41 | extern int eepromsize; 42 | extern int seepromsize; 43 | extern int mw_eepromsize; 44 | extern int spage_size; 45 | extern int org; 46 | #define EHELP " -E select I2C EEPROM {24c01|24c02|24c04|24c08|24c16|24c32|24c64|24c128|24c256|24c512|24c1024}\n" \ 47 | " select Microwire EEPROM {93c06|93c16|93c46|93c56|93c66|93c76|93c86|93c96} (need SPI-to-MW adapter)\n" \ 48 | " select SPI EEPROM 25xxx {25010|25020|25040|25080|25160|25320|25640|25128|25256|25512|251024}\n" \ 49 | " -8 set organization 8-bit for Microwire EEPROM(default 16-bit) and set jumper on SPI-to-MW adapter\n" \ 50 | " -f set manual address size in bits for Microwire EEPROM(default auto)\n" \ 51 | " -s set page size from datasheet for fast write SPI EEPROM(default not use)\n" 52 | #else 53 | #define EHELP "" 54 | #endif 55 | 56 | #define _VER "1.7.8" 57 | 58 | void title(void) 59 | { 60 | #ifdef EEPROM_SUPPORT 61 | printf("\nSNANDer - Serial Nor/nAND/Eeprom programmeR v." _VER " by McMCC \n\n"); 62 | #else 63 | printf("\nSNANDer - Spi Nor/nAND programmER v." _VER " by McMCC \n\n"); 64 | #endif 65 | } 66 | 67 | void usage(void) 68 | { 69 | const char use[] = 70 | " Usage:\n"\ 71 | " -h display this message\n"\ 72 | " -d disable internal ECC(use read and write page size + OOB size)\n"\ 73 | " -o manual set OOB size with disable internal ECC(default 0)\n"\ 74 | " -I ECC ignore errors(for read test only)\n"\ 75 | " -k Skip BAD pages, try to read or write in next page\n"\ 76 | " -L print list support chips\n"\ 77 | " -i read the chip ID info\n"\ 78 | "" EHELP ""\ 79 | " -e erase chip(full or use with -a [-l])\n"\ 80 | " -l manually set length\n"\ 81 | " -a
manually set address\n"\ 82 | " -w write chip with data from filename\n"\ 83 | " -r read chip and save data to filename\n"\ 84 | " -v verify after write on chip\n"; 85 | printf(use); 86 | exit(0); 87 | } 88 | 89 | int main(int argc, char* argv[]) 90 | { 91 | int c, vr = 0, svr = 0, ret = 0; 92 | char *str, *fname = NULL, op = 0; 93 | unsigned char *buf; 94 | int long long len = 0, addr = 0, flen = 0, wlen = 0; 95 | FILE *fp; 96 | 97 | title(); 98 | 99 | #ifdef EEPROM_SUPPORT 100 | while ((c = getopt(argc, argv, "diIhveLkl:a:w:r:o:s:E:f:8")) != -1) 101 | #else 102 | while ((c = getopt(argc, argv, "diIhveLkl:a:w:r:o:s:")) != -1) 103 | #endif 104 | { 105 | switch(c) 106 | { 107 | #ifdef EEPROM_SUPPORT 108 | case 'E': 109 | if ((eepromsize = parseEEPsize(optarg, &eeprom_info)) > 0) { 110 | memset(eepromname, 0, sizeof(eepromname)); 111 | strncpy(eepromname, optarg, 10); 112 | if (len > eepromsize) { 113 | printf("Error set size %lld, max size %d for EEPROM %s!!!\n", len, eepromsize, eepromname); 114 | exit(0); 115 | } 116 | } else if ((mw_eepromsize = deviceSize_3wire(optarg)) > 0) { 117 | memset(eepromname, 0, sizeof(eepromname)); 118 | strncpy(eepromname, optarg, 10); 119 | org = 1; 120 | if (len > mw_eepromsize) { 121 | printf("Error set size %lld, max size %d for EEPROM %s!!!\n", len, mw_eepromsize, eepromname); 122 | exit(0); 123 | } 124 | } else if ((seepromsize = parseSEEPsize(optarg, &seeprom_info)) > 0) { 125 | memset(eepromname, 0, sizeof(eepromname)); 126 | strncpy(eepromname, optarg, 10); 127 | if (len > seepromsize) { 128 | printf("Error set size %lld, max size %d for EEPROM %s!!!\n", len, seepromsize, eepromname); 129 | exit(0); 130 | } 131 | } else { 132 | printf("Unknown EEPROM chip %s!!!\n", optarg); 133 | exit(0); 134 | } 135 | break; 136 | case '8': 137 | if (mw_eepromsize <= 0) 138 | { 139 | printf("-8 option only for Microwire EEPROM chips!!!\n"); 140 | exit(0); 141 | } 142 | org = 0; 143 | break; 144 | case 'f': 145 | if (mw_eepromsize <= 0) 146 | { 147 | printf("-f option only for Microwire EEPROM chips!!!\n"); 148 | exit(0); 149 | } 150 | str = strdup(optarg); 151 | fix_addr_len = strtoll(str, NULL, *str && *(str + 1) == 'x' ? 16 : 10); 152 | if (fix_addr_len > 32) { 153 | printf("Address len is very big!!!\n"); 154 | exit(0); 155 | } 156 | break; 157 | #endif 158 | case 'I': 159 | ECC_ignore = 1; 160 | break; 161 | case 'k': 162 | Skip_BAD_page = 1; 163 | break; 164 | case 'd': 165 | ECC_fcheck = 0; 166 | _ondie_ecc_flag = 0; 167 | break; 168 | case 'l': 169 | str = strdup(optarg); 170 | len = strtoll(str, NULL, *str && *(str + 1) == 'x' ? 16 : 10); 171 | break; 172 | case 'o': 173 | str = strdup(optarg); 174 | OOB_size = strtoll(str, NULL, *str && *(str + 1) == 'x' ? 16 : 10); 175 | break; 176 | case 's': 177 | str = strdup(optarg); 178 | spage_size = strtoll(str, NULL, *str && *(str + 1) == 'x' ? 16 : 10); 179 | break; 180 | case 'a': 181 | str = strdup(optarg); 182 | addr = strtoll(str, NULL, *str && *(str + 1) == 'x' ? 16 : 10); 183 | break; 184 | case 'v': 185 | vr = 1; 186 | break; 187 | case 'i': 188 | case 'e': 189 | if(!op) 190 | op = c; 191 | else 192 | op = 'x'; 193 | break; 194 | case 'r': 195 | case 'w': 196 | if(!op) { 197 | op = c; 198 | fname = strdup(optarg); 199 | } else 200 | op = 'x'; 201 | break; 202 | case 'L': 203 | support_flash_list(); 204 | exit(0); 205 | case 'h': 206 | default: 207 | usage(); 208 | } 209 | } 210 | 211 | if (op == 0) usage(); 212 | 213 | if (op == 'x' || (ECC_ignore && !ECC_fcheck) || (ECC_ignore && Skip_BAD_page) || (op == 'w' && ECC_ignore)) { 214 | printf("Conflicting options, only one option at a time.\n\n"); 215 | return -1; 216 | } 217 | 218 | if (ch347_spi_init() < 0) { 219 | printf("Programmer device not found!\n\n"); 220 | return -1; 221 | } 222 | 223 | if((flen = flash_cmd_init(&prog)) <= 0) 224 | goto out; 225 | 226 | #ifdef EEPROM_SUPPORT 227 | if ((eepromsize || mw_eepromsize || seepromsize) && op == 'i') { 228 | printf("Programmer not supported auto detect EEPROM!\n\n"); 229 | goto out; 230 | } 231 | if (spage_size) { 232 | if (!seepromsize) { 233 | printf("Only use for SPI EEPROM!\n\n"); 234 | goto out; 235 | } 236 | if (((spage_size % 8) != 0) || (spage_size > (MAX_SEEP_PSIZE / 2))){ 237 | printf("Invalid parameter %dB for page size SPI EEPROM!\n\n", spage_size); 238 | goto out; 239 | } 240 | if (op == 'r') 241 | printf("Ignored set page size SPI EEPROM on READ.\n"); 242 | else 243 | printf("Setting page size %dB for write.\n", spage_size); 244 | } 245 | #else 246 | if (op == 'i') goto out; 247 | #endif 248 | if (OOB_size) { 249 | if (ECC_fcheck == 1) { 250 | printf("Ignore option -o, use with -d only!\n"); 251 | OOB_size = 0; 252 | } else { 253 | if (OOB_size > 256) { 254 | printf("Error: Maximum set OOB size <= 256!!!\n"); 255 | goto out; 256 | } 257 | if (OOB_size < 64) { 258 | printf("Error: Minimum set OOB size >= 64!!!\n"); 259 | goto out; 260 | } 261 | printf("Set manual OOB size = %d.\n", OOB_size); 262 | } 263 | } 264 | if (op == 'e') { 265 | printf("ERASE:\n"); 266 | if(addr && !len) 267 | len = flen - addr; 268 | else if(!addr && !len) { 269 | len = flen; 270 | printf("Set full erase chip!\n"); 271 | } 272 | if(len % bsize) { 273 | printf("Please set len = 0x%016llX multiple of the block size 0x%08X\n", len, bsize); 274 | goto out; 275 | } 276 | printf("Erase addr = 0x%016llX, len = 0x%016llX\n", addr, len); 277 | ret = prog.flash_erase(addr, len); 278 | if(!ret){ 279 | printf("Status: OK\n"); 280 | goto okout; 281 | } 282 | else 283 | printf("Status: BAD(%d)\n", ret); 284 | goto out; 285 | } 286 | 287 | if ((op == 'r') || (op == 'w')) { 288 | if(addr && !len) 289 | len = flen - addr; 290 | else if(!addr && !len) { 291 | len = flen; 292 | } 293 | buf = (unsigned char *)malloc(len + 1); 294 | if (!buf) { 295 | printf("Malloc failed for read buffer.\n"); 296 | goto out; 297 | } 298 | } 299 | 300 | if (op == 'w') { 301 | printf("WRITE:\n"); 302 | fp = fopen(fname, "rb"); 303 | if (!fp) { 304 | printf("Couldn't open file %s for reading.\n", fname); 305 | free(buf); 306 | goto out; 307 | } 308 | wlen = fread(buf, 1, len, fp); 309 | if (ferror(fp)) { 310 | printf("Error reading file [%s]\n", fname); 311 | if (fp) 312 | fclose(fp); 313 | free(buf); 314 | goto out; 315 | } 316 | if(len == flen) 317 | len = wlen; 318 | printf("Write addr = 0x%016llX, len = 0x%016llX\n", addr, len); 319 | ret = prog.flash_write(buf, addr, len); 320 | if(ret > 0) { 321 | printf("Status: OK\n"); 322 | if (vr) { 323 | op = 'r'; 324 | svr = 1; 325 | printf("VERIFY:\n"); 326 | goto very; 327 | } 328 | } 329 | else 330 | printf("Status: BAD(%d)\n", ret); 331 | fclose(fp); 332 | free(buf); 333 | } 334 | 335 | very: 336 | if (op == 'r') { 337 | if (!svr) printf("READ:\n"); 338 | else memset(buf, 0, len); 339 | printf("Read addr = 0x%016llX, len = 0x%016llX\n", addr, len); 340 | ret = prog.flash_read(buf, addr, len); 341 | if (ret < 0) { 342 | printf("Status: BAD(%d)\n", ret); 343 | free(buf); 344 | goto out; 345 | } 346 | if (svr) { 347 | unsigned char ch1; 348 | int i = 0; 349 | 350 | fseek(fp, 0, SEEK_SET); 351 | ch1 = (unsigned char)getc(fp); 352 | 353 | while ((ch1 != EOF) && (i < len - 1) && (ch1 == buf[i++])) 354 | ch1 = (unsigned char)getc(fp); 355 | 356 | if (ch1 == buf[i]){ 357 | printf("Status: OK\n"); 358 | fclose(fp); 359 | free(buf); 360 | goto okout; 361 | } 362 | else 363 | printf("Status: BAD\n"); 364 | fclose(fp); 365 | free(buf); 366 | goto out; 367 | } 368 | fp = fopen(fname, "wb"); 369 | if (!fp) { 370 | printf("Couldn't open file %s for writing.\n", fname); 371 | free(buf); 372 | goto out; 373 | } 374 | fwrite(buf, 1, len, fp); 375 | if (ferror(fp)){ 376 | printf("Error writing file [%s]\n", fname); 377 | fclose(fp); 378 | free(buf); 379 | goto out; 380 | } 381 | fclose(fp); 382 | free(buf); 383 | printf("Status: OK\n"); 384 | goto okout; 385 | } 386 | 387 | out: //exit with errors 388 | ch347_spi_shutdown(); 389 | return -1; 390 | okout: //exit without errors 391 | ch347_spi_shutdown(); 392 | return 0; 393 | } 394 | -------------------------------------------------------------------------------- /src/ch347_i2c.c: -------------------------------------------------------------------------------- 1 | // 2 | // ch347eeprom programmer version 0.1 (Beta) 3 | // 4 | // Programming tool for the 24Cxx serial EEPROMs using the Winchiphead ch347 IC 5 | // 6 | // (c) December 2011 asbokid 7 | // 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program. If not, see . 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "ch347_i2c.h" 29 | #define dprintf(args...) 30 | // #define dprintf(args...) do { if (1) printf(args); } while(0) 31 | #define true 1 32 | #define false 0 33 | typedef int bool; 34 | extern struct libusb_device_handle *handle; 35 | unsigned char *readbuf; 36 | uint32_t getnextpkt; // set by the callback function 37 | uint32_t syncackpkt; // synch / ack flag used by BULK OUT cb function 38 | uint32_t byteoffset; 39 | 40 | // callback functions for async USB transfers 41 | static void cbBulkIn(struct libusb_transfer *transfer); 42 | static void cbBulkOut(struct libusb_transfer *transfer); 43 | #ifdef _WIN32 44 | extern pCH347ReadData CH347ReadData; 45 | extern pCH347WriteData CH347WriteData; 46 | extern ULONG ugIndex; 47 | #elif defined(__linux__) 48 | extern struct libusb_device_handle *devHandle; 49 | #endif 50 | extern bool isCH347F; 51 | 52 | struct xxx { 53 | uint8_t ibuf[512]; 54 | uint8_t obuf[512]; 55 | } i2c_dev; 56 | 57 | int32_t ch347i2cConfig(int speed) 58 | { 59 | int32_t actuallen = 0; 60 | int ret; 61 | if (isCH347F) { 62 | uint8_t i2c_switch_cmd[11] = {0xe2, 0x08, 0x00, 0x00, 0x00, 0x81, 0x81, 0x00, 0x00, 0x00, 0x00}; 63 | #ifdef _WIN32 64 | actuallen =11; 65 | if (!CH347WriteData(ugIndex, i2c_switch_cmd, &actuallen)){ 66 | fprintf(stderr, "USB write error\r\n"); 67 | return -1; 68 | } 69 | actuallen = 4; 70 | if (!CH347ReadData(ugIndex, i2c_switch_cmd, &actuallen) || actuallen != 4){ 71 | fprintf(stderr, "USB read error\r\n"); 72 | return -1; 73 | } 74 | #elif defined(__linux__) 75 | ret = libusb_bulk_transfer(devHandle, BULK_WRITE_ENDPOINT, i2c_switch_cmd, 11, &actuallen, DEFAULT_TIMEOUT); 76 | if (ret < 0) { 77 | fprintf(stderr, "ch347setstream(): Failed write %d bytes '%s'\n", 2, strerror(-ret)); 78 | return -1; 79 | } 80 | ret = libusb_bulk_transfer(devHandle, BULK_READ_ENDPOINT, i2c_dev.ibuf, 4, &actuallen, DEFAULT_TIMEOUT); 81 | if (ret < 0 || actuallen != 4) { 82 | fprintf(stderr, "ch347setstream(): Failed read %d bytes '%s'\n", 2, strerror(-ret)); 83 | return -1; 84 | } 85 | #endif 86 | } 87 | 88 | actuallen = 0; 89 | i2c_dev.obuf[0] = mch347_CMD_I2C_STREAM; 90 | i2c_dev.obuf[1] = mch347_CMD_I2C_STM_SET; 91 | i2c_dev.obuf[2] = speed; 92 | #ifdef _WIN32 93 | actuallen = 3; 94 | if (!CH347WriteData(ugIndex, i2c_dev.obuf, &actuallen)){ 95 | fprintf(stderr, "USB write error\r\n"); 96 | return -1; 97 | } 98 | #elif defined(__linux__) 99 | ret = libusb_bulk_transfer(devHandle, BULK_WRITE_ENDPOINT, i2c_dev.obuf, 3, &actuallen, DEFAULT_TIMEOUT); 100 | if (ret < 0) { 101 | fprintf(stderr, "ch347setstream(): Failed write %d bytes '%s'\n", 2, strerror(-ret)); 102 | return -1; 103 | } 104 | #endif 105 | return 0; 106 | } 107 | 108 | void ch347ReadCmdMarshall(uint8_t *buffer, uint32_t addr, struct EEPROM *eeprom_info) 109 | { 110 | uint8_t *ptr = buffer; 111 | uint8_t msb_addr; 112 | uint32_t size_kb; 113 | 114 | *ptr++ = mch347_CMD_I2C_STREAM; // 0 115 | *ptr++ = mch347_CMD_I2C_STM_STA; // 1 116 | // Write address 117 | *ptr++ = mch347_CMD_I2C_STM_OUT | ((*eeprom_info).addr_size + 1); // 2: I2C bus adddress + EEPROM address 118 | if ((*eeprom_info).addr_size >= 2) { 119 | // 24C32 and more 120 | msb_addr = addr >> 16 & (*eeprom_info).i2c_addr_mask; 121 | *ptr++ = (EEPROM_I2C_BUS_ADDRESS | msb_addr) << 1; // 3 122 | *ptr++ = (addr >> 8 & 0xFF); // 4 123 | *ptr++ = (addr >> 0 & 0xFF); // 5 124 | } else { 125 | // 24C16 and less 126 | msb_addr = addr >> 8 & (*eeprom_info).i2c_addr_mask; 127 | *ptr++ = (EEPROM_I2C_BUS_ADDRESS | msb_addr) << 1; // 3 128 | *ptr++ = (addr >> 0 & 0xFF); // 4 129 | } 130 | // Read 131 | *ptr++ = mch347_CMD_I2C_STM_STA; // 6/5 132 | *ptr++ = mch347_CMD_I2C_STM_OUT | 1; // 7/6 133 | *ptr++ = ((EEPROM_I2C_BUS_ADDRESS | msb_addr) << 1) | 1; // 8/7: Read command 134 | 135 | // Configuration? 136 | *ptr++ = 0xE0; // 9/8 137 | *ptr++ = 0x00; // 10/9 138 | if ((*eeprom_info).addr_size < 2) 139 | *ptr++ = 0x10; // x/10 140 | memcpy(ptr, "\x00\x06\x04\x00\x00\x00\x00\x00\x00", 9); 141 | ptr += 9; // 10 142 | size_kb = (*eeprom_info).size/1024; 143 | *ptr++ = size_kb & 0xFF; // 19 144 | *ptr++ = (size_kb >> 8) & 0xFF; // 20 145 | memcpy(ptr, "\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc", 10); 146 | ptr += 10; 147 | 148 | // Frame 2 149 | *ptr++ = mch347_CMD_I2C_STREAM; 150 | memcpy(ptr, "\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 151 | "\xd9\x8b\x41\x7e\x00\xe0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e", 31); 152 | ptr += 31; 153 | 154 | // Frame 3 155 | *ptr++ = mch347_CMD_I2C_STREAM; 156 | memcpy(ptr, "\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 157 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00", 31); 158 | ptr += 31; 159 | 160 | // Finalize 161 | *ptr++ = mch347_CMD_I2C_STREAM; // 0xAA 162 | *ptr++ = 0xDF; // ??? 163 | *ptr++ = mch347_CMD_I2C_STM_IN; // 0xC0 164 | *ptr++ = mch347_CMD_I2C_STM_STO; // 0x75 165 | *ptr++ = mch347_CMD_I2C_STM_END; // 0x00 166 | 167 | assert(ptr - buffer == CH347_EEPROM_READ_CMD_SZ); 168 | } 169 | 170 | int ch347_i2c_write(struct i2c_msg *msg) { 171 | unsigned left = msg->len; 172 | uint8_t *ptr = msg->buf; 173 | bool first = true; 174 | do { 175 | uint8_t *outptr = i2c_dev.obuf; 176 | *outptr++ = mch347_CMD_I2C_STREAM; 177 | unsigned wlen = left; 178 | if (wlen > 62) { // wlen has only 6-bit field in protocol 179 | wlen = 62; 180 | } 181 | if (first) { // Start packet 182 | *outptr++ = mch347_CMD_I2C_STM_STA; 183 | *outptr++ = mch347_CMD_I2C_STM_OUT | (wlen + 1); 184 | *outptr++ = msg->addr << 1; 185 | } 186 | memcpy(outptr, ptr, wlen); 187 | outptr += wlen; 188 | ptr += wlen; 189 | left -= wlen; 190 | 191 | if (left == 0) { // Stop packet 192 | *outptr++ = mch347_CMD_I2C_STM_STO; 193 | } 194 | *outptr++ = mch347_CMD_I2C_STM_END; 195 | first = false; 196 | int ret = 0; 197 | unsigned long actuallen = 0; 198 | #ifdef _WIN32 199 | actuallen = outptr - i2c_dev.obuf; 200 | if (!CH347WriteData(ugIndex, i2c_dev.obuf, &actuallen)){ 201 | fprintf(stderr, "USB write error\r\n"); 202 | return -1; 203 | } 204 | actuallen = 512; 205 | if (!CH347ReadData(ugIndex, i2c_dev.ibuf, &actuallen)){ 206 | fprintf(stderr, "USB read error\r\n"); 207 | return -1; 208 | } 209 | #elif defined(__linux__) 210 | ret = libusb_bulk_transfer(devHandle, BULK_WRITE_ENDPOINT, i2c_dev.obuf, outptr - i2c_dev.obuf, &actuallen, DEFAULT_TIMEOUT); 211 | 212 | if (ret < 0) { 213 | fprintf(stderr, "Failed to write to I2C: '%s'\r\n", strerror(-ret)); 214 | return -1; 215 | } 216 | ret = libusb_bulk_transfer(devHandle, BULK_READ_ENDPOINT, i2c_dev.ibuf, 512, &actuallen, DEFAULT_TIMEOUT); 217 | 218 | if (ret < 0) { 219 | fprintf(stderr, "Failed to write to I2C: '%s'\r\n", strerror(-ret)); 220 | return -1; 221 | } 222 | #endif 223 | if (wlen + 1 != actuallen) { 224 | fprintf(stderr, "failed to get ACKs %d of %d\r\n", actuallen, wlen + 1); 225 | return -1; 226 | } 227 | for (unsigned i = 0; i < actuallen; ++i) { 228 | if (i2c_dev.ibuf[i] != 0x01) { 229 | fprintf(stderr, "received NACK at %d\r\n", i); 230 | return -1; 231 | } 232 | } 233 | } while (left); 234 | return 0; 235 | } 236 | 237 | int ch347_i2c_read(struct i2c_msg *msg) 238 | { 239 | unsigned byteoffset = 0; 240 | while (msg->len - byteoffset > 0) { 241 | unsigned bytestoread = msg->len - byteoffset; 242 | if (bytestoread > 63) // reserve first byte for status 243 | bytestoread = 63; 244 | uint8_t *ptr = i2c_dev.obuf; 245 | *ptr++ = mch347_CMD_I2C_STREAM; 246 | *ptr++ = mch347_CMD_I2C_STM_STA; 247 | *ptr++ = mch347_CMD_I2C_STM_OUT|1; 248 | *ptr++ = (msg->addr << 1) | 1; 249 | if (bytestoread > 1) 250 | *ptr++ = mch347_CMD_I2C_STM_IN | (bytestoread - 1); 251 | *ptr++ = mch347_CMD_I2C_STM_IN; 252 | *ptr++ = mch347_CMD_I2C_STM_STO; 253 | *ptr++ = mch347_CMD_I2C_STM_END; 254 | unsigned long actuallen = 0; 255 | #ifdef _WIN32 256 | actuallen = ptr - i2c_dev.obuf; 257 | if (!CH347WriteData(ugIndex, i2c_dev.obuf, &actuallen)){ 258 | fprintf(stderr, "USB write error\r\n"); 259 | return -1; 260 | } 261 | actuallen = 512; 262 | if (!CH347ReadData(ugIndex, i2c_dev.ibuf, &actuallen)){ 263 | fprintf(stderr, "USB read error\r\n"); 264 | return -1; 265 | } 266 | #elif defined(__linux__) 267 | int ret = libusb_bulk_transfer(devHandle, BULK_WRITE_ENDPOINT, i2c_dev.obuf, ptr - i2c_dev.obuf, &actuallen, DEFAULT_TIMEOUT); 268 | if (ret < 0) { 269 | fprintf(stderr, "USB write error : %s\r\n", strerror(-ret)); 270 | return ret; 271 | } 272 | ret = libusb_bulk_transfer(devHandle, BULK_READ_ENDPOINT, i2c_dev.ibuf, 512, &actuallen, DEFAULT_TIMEOUT); 273 | if (ret < 0) { 274 | fprintf(stderr, "USB read error : %s\r\n", strerror(-ret)); 275 | return ret; 276 | } 277 | #endif 278 | if (actuallen != bytestoread + 1) { 279 | fprintf(stderr, "actuallen(%d) != bytestoread(%d)\b", actuallen, bytestoread); 280 | return -1; 281 | } 282 | if (i2c_dev.ibuf[0] != 0x01) { 283 | fprintf(stderr, "received NACK"); 284 | return -1; 285 | } 286 | memcpy(&msg->buf[byteoffset], &i2c_dev.ibuf[1], bytestoread); 287 | byteoffset += bytestoread; 288 | } 289 | return 0; 290 | } 291 | 292 | int ch347_i2c_xfer(struct i2c_msg *msg, unsigned num) { 293 | for (unsigned i = 0; i < num; ++i) { 294 | if (msg[i].flags & I2C_M_RD) { 295 | int ret = ch347_i2c_read(&msg[i]); 296 | if (ret) return ret; 297 | } else { 298 | int ret = ch347_i2c_write(&msg[i]); 299 | if (ret) return ret; 300 | } 301 | } 302 | return 0; 303 | } 304 | 305 | // Callback function for async bulk in comms 306 | void cbBulkIn(struct libusb_transfer *transfer) 307 | { 308 | int i; 309 | 310 | switch (transfer->status) { 311 | case LIBUSB_TRANSFER_COMPLETED: 312 | // display the contents of the BULK IN data buffer 313 | dprintf("\ncbBulkIn(): status %d - Read %d bytes\n",transfer->status,transfer->actual_length); 314 | 315 | for (i = 0; i < transfer->actual_length; i++) { 316 | if(!(i % 16)) 317 | dprintf("\n "); 318 | dprintf("%02x ", transfer->buffer[i]); 319 | } 320 | dprintf("\n"); 321 | // copy read data to our EEPROM buffer 322 | memcpy(readbuf + byteoffset, transfer->buffer, transfer->actual_length); 323 | getnextpkt = 1; 324 | break; 325 | default: 326 | printf("\ncbBulkIn: error : %d\n", transfer->status); 327 | getnextpkt = -1; 328 | } 329 | return; 330 | } 331 | 332 | // Callback function for async bulk out comms 333 | void cbBulkOut(struct libusb_transfer *transfer) 334 | { 335 | syncackpkt = 1; 336 | dprintf("\ncbBulkOut(): Sync/Ack received: status %d\n", transfer->status); 337 | return; 338 | } 339 | 340 | // -------------------------------------------------------------------------- 341 | // ch347readEEPROM() 342 | // read n bytes from device (in packets of 32 bytes) 343 | int ch347readEEPROM(uint8_t *buffer, uint32_t bytes, struct EEPROM *eeprom_info) 344 | { 345 | struct i2c_msg msg[2]; 346 | 347 | uint8_t out[2] = {0}; 348 | msg[0].len = eeprom_info->addr_size; 349 | msg[0].flags = 0; 350 | msg[0].addr = EEPROM_I2C_BUS_ADDRESS; 351 | msg[0].buf = out; 352 | 353 | msg[1].flags = I2C_M_RD; 354 | msg[1].buf = buffer; 355 | msg[1].addr = EEPROM_I2C_BUS_ADDRESS; 356 | msg[1].len = bytes; 357 | 358 | return ch347_i2c_xfer(msg, 2); 359 | } 360 | 361 | int ch347delay_ms(unsigned ms) { 362 | i2c_dev.obuf[0] = mch347_CMD_I2C_STREAM; 363 | i2c_dev.obuf[1] = mch347_CMD_I2C_STM_MS | (ms & 0xf); // Wait up to 15ms 364 | i2c_dev.obuf[2] = mch347_CMD_I2C_STM_END; 365 | unsigned long actuallen = 0; 366 | #ifdef _WIN32 367 | actuallen = 3; 368 | if (!CH347WriteData(ugIndex, i2c_dev.obuf, &actuallen) || actuallen != 3){ 369 | fprintf(stderr, "USB write error.\r\n"); 370 | return -1; 371 | } 372 | #elif defined(__linux__) 373 | libusb_bulk_transfer(devHandle, BULK_WRITE_ENDPOINT, i2c_dev.obuf, 3, &actuallen, DEFAULT_TIMEOUT); 374 | #endif 375 | return 0; 376 | } 377 | 378 | // -------------------------------------------------------------------------- 379 | // ch347writeEEPROM() 380 | // write n bytes to 24c32/24c64 device (in packets of 32 bytes) 381 | int32_t ch347writeEEPROM(uint8_t *buffer, uint32_t bytesum, struct EEPROM *eeprom_info) 382 | { 383 | uint8_t msgbuffer[256 + 2]; // max EEPROM page size is 256 in 2M part, and 2 bytes for address 384 | int index = 0; 385 | struct i2c_msg msg; 386 | msg.addr = EEPROM_I2C_BUS_ADDRESS; 387 | msg.buf = msgbuffer; 388 | msg.flags = 0; 389 | unsigned offset = 0; 390 | while (offset < bytesum) { 391 | uint8_t *outptr = msgbuffer; 392 | unsigned wlen = eeprom_info->page_size; 393 | if (eeprom_info->addr_size > 1) { 394 | *outptr++ = offset >> 8; 395 | } 396 | *outptr++ = offset; 397 | if (bytesum - offset < wlen) { 398 | wlen = bytesum - offset; 399 | } 400 | memcpy(outptr, buffer + offset, wlen); 401 | outptr += wlen; 402 | msg.len = outptr - msgbuffer; 403 | int ret = 0; 404 | ret = ch347_i2c_xfer(&msg, 1); 405 | if (ret < 0) { 406 | fprintf(stderr, "Failed to write to EEPROM: '%s'\r\n", strerror(-ret)); 407 | return -1; 408 | } 409 | offset += wlen; 410 | 411 | ret = ch347delay_ms(10); 412 | if (ret < 0) { 413 | fprintf(stderr, "Failed to set timeout: '%s'\r\n", strerror(-ret)); 414 | return -1; 415 | } 416 | fprintf(stdout, "Written %d%% [%d] of [%d] bytes%s", 100 * offset / bytesum, offset, bytesum, ((index++)%2)?"\t":"\r\n"); 417 | } 418 | return 0; 419 | } 420 | 421 | // -------------------------------------------------------------------------- 422 | // parseEEPsize() 423 | // passed an EEPROM name (case-sensitive), returns its byte size 424 | int32_t parseEEPsize(char *eepromname, struct EEPROM *eeprom) 425 | { 426 | int i; 427 | 428 | for (i = 0; eepromlist[i].size; i++) { 429 | if (strstr(eepromlist[i].name, eepromname)) { 430 | memcpy(eeprom, &(eepromlist[i]), sizeof(struct EEPROM)); 431 | return (eepromlist[i].size); 432 | } 433 | } 434 | 435 | return -1; 436 | } 437 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SNANDer 2 | === 3 | 4 | SNANDer - Serial Nor/nAND/Eeprom programmeR (based on CH347) 5 | 6 | **copyright** 7 | 8 | This software is modified from the original project: [Droid-MAX/SNANDer](https://github.com/Droid-MAX/SNANDer) 9 | 10 | ![ch341a-nextProgrammer](photos/ch347-nextProgrammer.jpg) 11 | 12 | **Requirements** 13 | 14 | * gcc/mingw-w64, wget, make, and libusb-1.0-dev (via apt Command Line Tools) 15 | 16 | **Compiling for Linux** 17 | 18 | After installing the gcc and necessary tools, building `snander` is as simple as running the command: 19 | 20 | ``` 21 | make -C src/ 22 | ``` 23 | 24 | After successful compilation, the target executable file will be generated in `src` folder. 25 | 26 | Or you can choose static compile, building `snander` statically is as simple as running the command: 27 | 28 | ``` 29 | ./build-for-linux.sh 30 | ``` 31 | 32 | After successful compilation, the target executable file will be generated in the `build` folder. 33 | 34 | **Compiling for Windows** 35 | 36 | After installing the mingw-w64 and necessary tools, building `snander` is as simple as running the included script: 37 | 38 | ``` 39 | ./build-for-windows.sh 40 | ``` 41 | 42 | After successful compilation, the target executable file will be generated in the `build` folder, include x86 and x64 binaries. 43 | 44 | **Compiling for MacOS** 45 | 46 | After installing the necessary tools, building `snander` is as simple as running the included script: 47 | 48 | ``` 49 | ./build-for-darwin.sh 50 | ``` 51 | 52 | After successful compilation, the target executable file will be generated in the `build` folder. 53 | 54 | **Compiling for OpenWrt IPK** 55 | 56 | First download `OpenWrt SDK` and extract it 57 | 58 | ``` 59 | cd /path/to/your/sdk 60 | git clone https://github.com/Droid-MAX/SNANDer package/snander 61 | make menuconfig # Choose `snander` in section `Utilities` 62 | make package/snander/compile V=s 63 | ``` 64 | 65 | **Usage** 66 | 67 | Using `snander` is straightforward: 68 | 69 | ``` 70 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 71 | 72 | Usage: 73 | -h display this message 74 | -d disable internal ECC(use read and write page size + OOB size) 75 | -o manual set OOB size with disable internal ECC(default 0) 76 | -I ECC ignore errors(for read test only) 77 | -k Skip BAD pages, try to read or write in next page 78 | -L print list support chips 79 | -i read the chip ID info 80 | -E select I2C EEPROM {24c01|24c02|24c04|24c08|24c16|24c32|24c64|24c128|24c256|24c512|24c1024} 81 | select Microwire EEPROM {93c06|93c16|93c46|93c56|93c66|93c76|93c86|93c96} (need SPI-to-MW adapter) 82 | select SPI EEPROM 25xxx {25010|25020|25040|25080|25160|25320|25640|25128|25256|25512|251024} 83 | -8 set organization 8-bit for Microwire EEPROM(default 16-bit) and set jumper on SPI-to-MW adapter 84 | -f set manual address size in bits for Microwire EEPROM(default auto) 85 | -s set page size from datasheet for fast write SPI EEPROM(default not use) 86 | -e erase chip(full or use with -a [-l]) 87 | -l manually set length 88 | -a
manually set address 89 | -w write chip with data from filename 90 | -r read chip and save data to filename 91 | -v verify after write on chip 92 | ``` 93 | 94 | For example: 95 | 96 | 1. Get Flash info. 97 | 98 | ``` 99 | $ ./SNANDer -i 100 | 101 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 102 | 103 | Found programmer device: WinChipHead (WCH) - CH341A 104 | Device revision is 3.0.4 105 | spi device id: ff c2 22 c2 22 (c222c222) 106 | SPI NOR Flash Not Detected! 107 | spi_nand_probe: mfr_id = 0xc2, dev_id = 0x22 108 | Get Status Register 1: 0x38 109 | Get Status Register 2: 0x10 110 | Using Flash ECC. 111 | Detected SPI NAND Flash: MXIC MX35LF2GE4AB, Flash Size: 256 MB 112 | $ 113 | ``` 114 | 115 | 2. Full erase flash with disable internal ECC check. Without OOB, page size 2112 bytes. 116 | 117 | ``` 118 | $ ./SNANDer -d -e 119 | 120 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 121 | 122 | Found programmer device: WinChipHead (WCH) - CH341A 123 | Device revision is 3.0.4 124 | spi device id: ff c2 22 c2 22 (c222c222) 125 | SPI NOR Flash Not Detected! 126 | spi_nand_probe: mfr_id = 0xc2, dev_id = 0x22 127 | Get Status Register 1: 0x00 128 | Get Status Register 2: 0x11 129 | Disable Flash ECC. 130 | Detected SPI NAND Flash: MXIC MX35LF2GE4AB, Flash Size: 256 MB 131 | ERASE: 132 | Set full erase chip! 133 | Erase addr = 0x0000000000000000, len = 0x0000000010800000 134 | Erase 100% [276824064] of [276824064] bytes 135 | Elapsed time: 3 seconds 136 | Status: OK 137 | $ 138 | ``` 139 | 140 | 3. Write and verify flash with disable internal ECC check. Without OOB, page size 2112 bytes. 141 | 142 | ``` 143 | $ ./SNANDer -d -v -w ecc_2Gb_2K_64_flashimage_rfb1_ac2600.bin 144 | 145 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 146 | 147 | Found programmer device: WinChipHead (WCH) - CH341A 148 | Device revision is 3.0.4 149 | spi device id: ff c2 22 c2 22 (c222c222) 150 | SPI NOR Flash Not Detected! 151 | spi_nand_probe: mfr_id = 0xc2, dev_id = 0x22 152 | Get Status Register 1: 0x00 153 | Get Status Register 2: 0x11 154 | Disable Flash ECC. 155 | Detected SPI NAND Flash: MXIC MX35LF2GE4AB, Flash Size: 256 MB 156 | WRITE: 157 | Write addr = 0x0000000000000000, len = 0x000000000E5A9D6F 158 | Written 100% [240819567] of [240819567] bytes 159 | Elapsed time: 4184 seconds 160 | Status: OK 161 | VERIFY: 162 | Read addr = 0x0000000000000000, len = 0x000000000E5A9D6F 163 | Read 100% [240819567] of [240819567] bytes 164 | Elapsed time: 2047 seconds 165 | Status: OK 166 | $ 167 | ``` 168 | 169 | 4. Read Microwire EEPROM Atmel 93C46 and save file. 170 | 171 | ``` 172 | $ ./SNANDer -E 93c46 -r test.bin 173 | 174 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 175 | 176 | Found programmer device: WinChipHead (WCH) - CH341A 177 | Device revision is 3.0.4 178 | Microwire EEPROM chip: 93c46, Size: 64 bytes, Org: 16 bits, fix addr len: Auto 179 | READ: 180 | Read addr = 0x0000000000000000, len = 0x0000000000000080 181 | Read_EEPROM_3wire: Set address len 6 bits 182 | Read 100% [64] of [64] bytes 183 | Read [128] bytes from [93c46] EEPROM address 0x00000000 184 | Elapsed time: 0 seconds 185 | Status: OK 186 | ``` 187 | 188 | 5. Write and verify Microwire EEPROM Atmel 93C46 from file. 189 | 190 | ``` 191 | $ ./SNANDer -E 93c46 -w test.bin -v 192 | 193 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 194 | 195 | Found programmer device: WinChipHead (WCH) - CH341A 196 | Device revision is 3.0.4 197 | Microwire EEPROM chip: 93c46, Size: 64 bytes, Org: 16 bits, fix addr len: Auto 198 | WRITE: 199 | Write addr = 0x0000000000000000, len = 0x0000000000000080 200 | Erase_EEPROM_3wire: Set address len 6 bits 201 | Write_EEPROM_3wire: Set address len 6 bits 202 | Written 100% [64] of [64] bytes 203 | Wrote [128] bytes to [93c46] EEPROM address 0x00000000 204 | Elapsed time: 1 seconds 205 | Status: OK 206 | VERIFY: 207 | Read addr = 0x0000000000000000, len = 0x0000000000000080 208 | Read_EEPROM_3wire: Set address len 6 bits 209 | Read 100% [64] of [64] bytes 210 | Read [128] bytes from [93c46] EEPROM address 0x00000000 211 | Elapsed time: 1 seconds 212 | Status: OK 213 | ``` 214 | 215 | 6. Write and verify SPI EEPROM Atmel AT25640B from file. 216 | 217 | ``` 218 | $ ./SNANDer -E 25640 -v -w test.bin 219 | 220 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 221 | 222 | Found programmer device: WinChipHead (WCH) - CH341A 223 | Device revision is 3.0.4 224 | SPI EEPROM chip: 25640, Size: 8192 bytes 225 | WRITE: 226 | Written addr = 0x0000000000000000, len = 0x0000000000002000 227 | Wrote 100% [8192] bytes to [25640] EEPROM address 0x00000000 228 | Elapsed time: 22 seconds 229 | Status: OK 230 | VERIFY: 231 | Read addr = 0x0000000000000000, len = 0x0000000000002000 232 | Read 100% [8192] bytes from [25640] EEPROM address 0x00000000 233 | Elapsed time: 2 seconds 234 | Status: OK 235 | ``` 236 | 237 | 7. Fast write and verify SPI EEPROM Atmel AT25640B from file with use page size. 238 | (Find out page size from datasheet on chip!!!) 239 | 240 | ``` 241 | $ ./SNANDer -E 25640 -v -w test.bin -s 32 242 | 243 | SNANDer - Serial Nor/nAND/Eeprom programmeR v.1.7.8 by McMCC 244 | 245 | Found programmer device: WinChipHead (WCH) - CH341A 246 | Device revision is 3.0.4 247 | SPI EEPROM chip: 25640, Size: 8192 bytes 248 | Setting page size 32B for write. 249 | WRITE: 250 | Write addr = 0x0000000000000000, len = 0x0000000000002000 251 | Written 100% [8192] bytes to [25640] EEPROM address 0x00000000 252 | Elapsed time: 1 seconds 253 | Status: OK 254 | VERIFY: 255 | Read addr = 0x0000000000000000, len = 0x0000000000002000 256 | Read 100% [8192] bytes from [25640] EEPROM address 0x00000000 257 | Elapsed time: 2 seconds 258 | Status: OK 259 | ``` 260 | 261 | **Supported Chips** 262 | 263 | ``` 264 | SPI NAND Flash Support List: 265 | 001. GIGADEVICE GD5F1GQ4UA 266 | 002. GIGADEVICE GD5F1GQ4UB 267 | 003. GIGADEVICE GD5F1GQ4UC 268 | 004. GIGADEVICE GD5F1GQ4UE 269 | 005. GIGADEVICE GD5F1GQ5UE 270 | 006. GIGADEVICE GD5F1GQ5RE 271 | 007. GIGADEVICE GD5F2GQ5UE 272 | 008. GIGADEVICE GD5F2GQ5RE 273 | 009. GIGADEVICE GD5F2GQ4UB 274 | 010. GIGADEVICE GD5F2GQ4UE 275 | 011. GIGADEVICE GD5F2GQ4UC 276 | 012. GIGADEVICE GD5F4GQ4UB 277 | 013. GIGADEVICE GD5F4GQ4UC 278 | 014. ESMT F50D1G41LB(2M) 279 | 015. ESMT F50L512 280 | 016. ESMT F50L1G 281 | 017. ESMT F50L1G41LB 282 | 018. ESMT F50L2G41LB 283 | 019. WINBOND W25N01GV 284 | 020. WINBOND W25N01GW 285 | 021. WINBOND W25N02KV 286 | 022. WINBOND W25N04KV 287 | 023. WINBOND W25M02GV 288 | 024. MXIC MX35LF1GE4AB 289 | 025. MXIC MX35LF2GE4AB 290 | 026. MXIC MX35LF2G14AC 291 | 027. MXIC MX35LF2GE4AD 292 | 028. MXIC MX35LF1G24AD 293 | 029. MXIC MX35LF2G24AD 294 | 030. MXIC MX35LF4G24AD 295 | 031. MXIC MX35UF1GE4AD 296 | 032. MXIC MX35UF2GE4AD 297 | 033. MXIC MX35UF4GE4AD 298 | 034. ZENTEL A5U12A21ASC 299 | 035. ZENTEL A5U1GA21BWS 300 | 036. ETRON EM73C044SNB 301 | 037. ETRON EM73C044SND 302 | 038. ETRON EM73C044SNF 303 | 039. ETRON EM73C044VCA 304 | 040. ETRON EM73C044VCD 305 | 041. ETRON EM73D044VCA 306 | 042. ETRON EM73D044VCB 307 | 043. ETRON EM73D044VCD 308 | 044. ETRON EM73D044VCG 309 | 045. ETRON EM73D044VCH 310 | 046. ETRON EM73D044SNA 311 | 047. ETRON EM73D044SNC 312 | 048. ETRON EM73D044SND 313 | 049. ETRON EM73D044SNF 314 | 050. ETRON EM73E044SNA 315 | 051. TOSHIBA TC58CVG0S3H 316 | 052. TOSHIBA TC58CVG1S3H 317 | 053. TOSHIBA TC58CVG2S0H 318 | 054. KIOXIA TC58CVG2S0HRAIJ 319 | 055. MICRON MT29F1G01 320 | 056. MICRON MT29F2G01 321 | 057. MICRON MT29F4G01 322 | 058. HEYANG HYF1GQ4UAACAE 323 | 059. HEYANG HYF2GQ4UAACAE 324 | 060. HEYANG HYF2GQ4UHCCAE 325 | 061. HEYANG HYF1GQ4UDACAE 326 | 062. HEYANG HYF2GQ4UDACAE 327 | 063. PN PN26G01A-X 328 | 064. PN PN26G02A-X 329 | 065. PN PN26Q01A-X 330 | 066. ATO ATO25D1GA 331 | 067. ATO ATO25D2GA 332 | 068. ATO ATO25D2GB 333 | 069. FM FM25S01 334 | 070. FM FM25S01A 335 | 071. FM FM25S02A 336 | 072. FM FM25G01B 337 | 073. FM FM25G02B 338 | 074. FM FM25G02C 339 | 075. FM FM25G02 340 | 076. XTX XT26G02B 341 | 077. XTX XT26G01C 342 | 078. XTX XT26G02C 343 | 079. XTX XT26G01A 344 | 080. XTX XT26G02A 345 | 081. MIRA PSU1GS20BN 346 | 082. BIWIN BWJX08U 347 | 083. BIWIN BWET08U 348 | 084. FORESEE FS35ND01GD1F1 349 | 085. FORESEE FS35ND01GS1F1 350 | 086. FORESEE FS35ND02GS2F1 351 | 087. FORESEE FS35ND02GD1F1 352 | 088. FORESEE FS35ND01GS1Y2 353 | 089. FORESEE FS35ND02G-S3Y2 354 | 090. FORESEE FS35ND04G-S2Y2 355 | 091. DS DS35Q2GA 356 | 092. DS DS35M2GA 357 | 093. DS DS35Q1GA 358 | 094. DS DS35M1GA 359 | 095. FISON CS11G0T0A0AA 360 | 096. FISON CS11G1T0A0AA 361 | 097. FISON CS11G0G0A0AA 362 | 098. TYM TYM25D2GA01 363 | 099. TYM TYM25D2GA02 364 | 100. TYM TYM25D1GA03 365 | 101. XINCUN XCSP1AAWH-NT 366 | 367 | SPI NOR Flash Support List: 368 | 001. AT26DF161 369 | 002. AT25DF321 370 | 003. A25L10PU 371 | 004. A25L20PU 372 | 005. A25L040 373 | 006. A25LQ080 374 | 007. A25L080 375 | 008. A25LQ16 376 | 009. A25LQ32 377 | 010. A25L032 378 | 011. A25LQ64 379 | 012. ES25P10 380 | 013. ES25P20 381 | 014. ES25P40 382 | 015. ES25P80 383 | 016. ES25P16 384 | 017. ES25P32 385 | 018. ES25M40A 386 | 019. ES25M80A 387 | 020. ES25M16A 388 | 021. DQ25Q64AS 389 | 022. F25L016 390 | 023. F25L16QA 391 | 024. F25L032 392 | 025. F25L32QA 393 | 026. F25L064 394 | 027. F25L64QA 395 | 028. GD25Q20C 396 | 029. GD25Q40C 397 | 030. GD25Q80C 398 | 031. GD25LQ80C 399 | 032. GD25WD80C 400 | 033. GD25WQ80E 401 | 034. GD25Q16 402 | 035. GD25LQ16C 403 | 036. GD25WQ16E 404 | 037. GD25Q32 405 | 038. GD25LQ32E 406 | 039. GD25WQ32E 407 | 040. GD25Q64CSIG 408 | 041. GD25Q128CSIG 409 | 042. GD25F256F 410 | 043. GD25Q256CSIG 411 | 044. MX25L4005A 412 | 045. MX25L8005M 413 | 046. MX25L1605D 414 | 047. MX25U1635F 415 | 048. MX25L3205D 416 | 049. MX25U3235F 417 | 050. MX25L6405D 418 | 051. MX25U6435F 419 | 052. MX25L12805D 420 | 053. MX25U12835F 421 | 054. MX25L25635E 422 | 055. MX25U25643G 423 | 056. MX25L51245G 424 | 057. MX25U51245G 425 | 058. YC25Q128 426 | 059. FL016AIF 427 | 060. FL064AIF 428 | 061. S25FL016P 429 | 062. S25FL032P 430 | 063. S25FL064P 431 | 064. S25FL128P 432 | 065. S25FL129P 433 | 066. S25FL256S 434 | 067. S25FL512S 435 | 068. S25FL116K 436 | 069. S25FL132K 437 | 070. S25FL164K 438 | 071. EN25F16 439 | 072. EN25Q16 440 | 073. EN25QH16 441 | 074. EN25Q32B 442 | 075. EN25F32 443 | 076. EN25F64 444 | 077. EN25Q64 445 | 078. EN25QA64A 446 | 079. EN25QH64A 447 | 080. EN25Q128 448 | 081. EN25Q256 449 | 082. EN25QA128A 450 | 083. EN25QH128A 451 | 084. GM25Q128A 452 | 085. W25X05 453 | 086. W25X10 454 | 087. W25X20 455 | 088. W25X40 456 | 089. W25X80 457 | 090. W25X16 458 | 091. W25X32VS 459 | 092. W25X64 460 | 093. W25Q20CL 461 | 094. W25Q20BW 462 | 095. W25Q20EW 463 | 096. W25Q80 464 | 097. W25Q80BL 465 | 098. W25Q16JQ 466 | 099. W25Q16JM 467 | 100. W25Q32BV 468 | 101. W25Q32DW 469 | 102. W25Q32JWIM 470 | 103. W25Q64BV 471 | 104. W25Q64DW 472 | 105. W25Q64JVIM 473 | 106. W25Q128BV 474 | 107. W25Q128FW 475 | 108. W25Q256FV 476 | 109. W25Q256JW 477 | 110. W25Q256JWIM 478 | 111. W25Q512JV 479 | 112. W25Q512JVIM 480 | 113. W25Q512NW 481 | 114. W25Q512NWIM 482 | 115. M25P05 483 | 116. M25P10 484 | 117. M25P20 485 | 118. M25P40 486 | 119. M25P80 487 | 120. M25P16 488 | 121. M25P32 489 | 122. M25P64 490 | 123. M25P128 491 | 124. N25Q016A 492 | 125. N25Q032A 493 | 126. N25Q032A 494 | 127. N25Q064A 495 | 128. N25Q064A 496 | 129. N25Q128A 497 | 130. N25Q128A 498 | 131. N25Q256A 499 | 132. N25Q512A 500 | 133. MT25QL64AB 501 | 134. MT25QU64AB 502 | 135. MT25QL128AB 503 | 136. MT25QU128AB 504 | 137. MT25QL256AB 505 | 138. MT25QU256AB 506 | 139. MT25QL512AB 507 | 140. MT25QU512AB 508 | 141. XM25QH10B 509 | 142. XM25QH20B 510 | 143. XM25QU41B 511 | 144. XM25QH40B 512 | 145. XM25QU80B 513 | 146. XM25QH80B 514 | 147. XM25QU16B 515 | 148. XM25QH16C 516 | 149. XM25QW16C 517 | 150. XM25QH32B 518 | 151. XM25QW32C 519 | 152. XM25LU32C 520 | 153. XM25QH32A 521 | 154. XM25QH64C 522 | 155. XM25LU64C 523 | 156. XM25QW64C 524 | 157. XM25QH64A 525 | 158. XM25QH128A 526 | 159. XM25QH128C 527 | 160. XM25LU128C 528 | 161. XM25QW128C 529 | 162. XM25QH256C 530 | 163. XM25QU256C 531 | 164. XM25QW256C 532 | 165. XM25QH512C 533 | 166. XM25QU512C 534 | 167. XM25QW512C 535 | 168. MD25D20 536 | 169. MD25D40 537 | 170. ZB25VQ16 538 | 171. ZB25LQ16 539 | 172. ZB25VQ32 540 | 173. ZB25LQ32 541 | 174. ZB25VQ64 542 | 175. ZB25LQ64 543 | 176. ZB25VQ128 544 | 177. ZB25LQ128 545 | 178. LE25U20AMB 546 | 179. LE25U40CMC 547 | 180. BY25D05AS 548 | 181. BY25D10AS 549 | 182. BY25D20AS 550 | 183. BY25D40AS 551 | 184. BY25Q40BL 552 | 185. BY25Q40BL 553 | 186. BY25Q80BS 554 | 187. BY25Q16BS 555 | 188. BY25Q16BL 556 | 189. BY25Q32BS 557 | 190. BY25Q32AL 558 | 191. BY25Q64AS 559 | 192. BY25Q64AL 560 | 193. BY25Q128AS 561 | 194. BY25Q128EL 562 | 195. BY25Q256ES 563 | 196. XT25F04D 564 | 197. XT25F08B 565 | 198. XT25F08D 566 | 199. XT25F16B 567 | 200. XT25Q16D 568 | 201. XT25F32B 569 | 202. XT25F64B 570 | 203. XT25Q64D 571 | 204. XT25F128B 572 | 205. XT25F128D 573 | 206. PM25LQ016 574 | 207. PM25LQ032 575 | 208. PM25LQ064 576 | 209. PM25LQ128 577 | 210. IS25LQ010 578 | 211. IS25LQ020 579 | 212. IS25WP040D 580 | 213. IS25LP080D 581 | 214. IS25WP080D 582 | 215. IS25LP016D 583 | 216. IS25WP016D 584 | 217. IS25LP032D 585 | 218. IS25WP032D 586 | 219. IS25LP064D 587 | 220. IS25WP064D 588 | 221. IS25LP128F 589 | 222. IS25WP128F 590 | 223. IS25LP256D 591 | 224. IS25WP256D 592 | 225. IS25LP256D 593 | 226. IS25WP256D 594 | 227. FM25W04 595 | 228. FM25Q04 596 | 229. FM25Q08 597 | 230. FM25W16 598 | 231. FM25Q16 599 | 232. FM25W32 600 | 233. FS25Q32 601 | 234. FM25W64 602 | 235. FS25Q64 603 | 236. FM25W128 604 | 237. FS25Q128 605 | 238. FM25Q04A 606 | 239. FM25M04A 607 | 240. FM25Q08A 608 | 241. FM25M08A 609 | 242. FM25Q16A 610 | 243. FM25M16A 611 | 244. FM25Q32A 612 | 245. FM25M32B 613 | 246. FM25Q64A 614 | 247. FM25M64A 615 | 248. FM25Q128A 616 | 249. PN25F16 617 | 250. PN25F32 618 | 251. PN25F64 619 | 252. PN25F128 620 | 253. P25D05H 621 | 254. P25D10H 622 | 255. P25D20H 623 | 256. P25D40H 624 | 257. P25D80H 625 | 258. P25Q16H 626 | 259. P25Q32H 627 | 260. P25Q64H 628 | 261. P25Q128H 629 | 262. PY25Q128HA 630 | 263. SK25P32 631 | 264. SK25P64 632 | 265. SK25P128 633 | 266. ZD25Q16A 634 | 267. ZD25Q32A 635 | 268. ZD25Q64A 636 | 269. ZD25Q128A 637 | 270. ZD25Q16B 638 | 271. ZD25Q32B 639 | 272. ZD25Q64B 640 | 273. ZD25Q128B 641 | 274. PCT25VF010A 642 | 275. PCT25VF020B 643 | 276. PCT25VF040B 644 | 277. PCT25VF080B 645 | 278. PCT25VF016B 646 | 279. PCT25VF032B 647 | 280. PCT25VF064C 648 | 281. PCT26VF016 649 | 282. PCT26VF032 650 | 651 | I2C EEPROM Support List: 652 | 001. 24c01 653 | 002. 24c02 654 | 003. 24c04 655 | 004. 24c08 656 | 005. 24c16 657 | 006. 24c32 658 | 007. 24c64 659 | 008. 24c128 660 | 009. 24c256 661 | 010. 24c512 662 | 011. 24c1024 663 | 664 | Microwire EEPROM Support List: 665 | 001. 93c06 666 | 002. 93c16 667 | 003. 93c46 668 | 004. 93c56 669 | 005. 93c66 670 | 006. 93c76 671 | 007. 93c86 672 | 008. 93c96 673 | 674 | SPI EEPROM Support List: 675 | 001. 25010 676 | 002. 25020 677 | 003. 25040 678 | 004. 25080 679 | 005. 25160 680 | 006. 25320 681 | 007. 25640 682 | 008. 25128 683 | 009. 25256 684 | 010. 25512 685 | 011. 251024 686 | ``` 687 | 688 | **Author** 689 | 690 | Originally written by [McMCC](https://github.com/McMCCRU/SNANDer) and released under the terms of the GNU GPL, version 2.0, or later. Modifications by [Droid-MAX](https://github.com/Droid-MAX/) to make it more easier build for Windows. 691 | 692 | **License** 693 | 694 | This is free software: you can redistribute it and/or modify it under the terms of 695 | the latest GNU General Public License as published by the Free Software Foundation. 696 | 697 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 698 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 699 | See the GNU General Public License for more details. 700 | 701 | You should have received a copy of the GNU General Public License along with this program. 702 | If not, see . 703 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /src/ch347_i2c.h: -------------------------------------------------------------------------------- 1 | // libUSB driver for the ch347 in i2c mode 2 | // 3 | // Copyright 2011 asbokid 4 | #ifndef __CH347_I2C_H__ 5 | #define __CH347_I2C_H__ 6 | 7 | #include 8 | #ifdef _WIN32 9 | typedef int(__stdcall * pCH347OpenDevice)(unsigned long iIndex); 10 | 11 | typedef int(__stdcall * pCH347CloseDevice)(unsigned long iIndex); 12 | typedef unsigned long(__stdcall * pCH347SetTimeout)( 13 | unsigned long iIndex, /* Specify equipment serial number */ 14 | unsigned long iWriteTimeout, /* Specifies the timeout period for USB 15 | write out data blocks, in milliseconds 16 | mS, and 0xFFFFFFFF specifies no timeout 17 | (default) */ 18 | unsigned long iReadTimeout); /* Specifies the timeout period for USB 19 | reading data blocks, in milliseconds mS, 20 | and 0xFFFFFFFF specifies no timeout 21 | (default) */ 22 | 23 | typedef unsigned long(__stdcall * pCH347WriteData)( 24 | unsigned long iIndex, /* Specify equipment serial number */ 25 | void *oBuffer, /* Point to a buffer large enough to hold 26 | the descriptor */ 27 | unsigned long *ioLength); /* Pointing to the length unit, the input 28 | is the length to be read, and the 29 | return is the actual read length */ 30 | 31 | typedef unsigned long(__stdcall * pCH347ReadData)( 32 | unsigned long iIndex, /* Specify equipment serial number */ 33 | void *oBuffer, /* Point to a buffer large enough to 34 | hold the descriptor */ 35 | unsigned long *ioLength); /* Pointing to the length unit, the input 36 | is the length to be read, and the 37 | return is the actual read length */ 38 | #endif 39 | 40 | #define MAX_EEPROM_SIZE 131072 /* For 24c1024*/ 41 | 42 | #define EEPROM_I2C_BUS_ADDRESS 0x50 43 | 44 | #define BULK_WRITE_ENDPOINT 0x06 45 | #define BULK_READ_ENDPOINT 0x86 46 | #define DEFAULT_INTERFACE 0x02 47 | 48 | #define DEFAULT_CONFIGURATION 0x01 49 | #define DEFAULT_TIMEOUT 3000 // 300mS for USB timeouts 50 | 51 | #define IN_BUF_SZ 0x100 52 | #define EEPROM_WRITE_BUF_SZ 0x2b // only for 24c64 / 24c32 ?? 53 | #define EEPROM_READ_BULKIN_BUF_SZ 0x20 54 | #define EEPROM_READ_BULKOUT_BUF_SZ 0x65 55 | 56 | /* Based on (closed-source) DLL V1.9 for USB by WinChipHead (c) 2005. 57 | Supports USB chips: ch347, ch347A 58 | This can be a problem for copyright, sure asbokid can't release this part on any GPL licence*/ 59 | 60 | #define mch347_PACKET_LENGTH 32 /* wMaxPacketSize 0x0020 1x 32 bytes, unused on the source */ 61 | #define mch347_PKT_LEN_SHORT 8 /* wMaxPacketSize 0x0008 1x 8 bytes, unused on the source */ 62 | 63 | #define mch347_ENDP_INTER_UP 0x81 /* bEndpointAddress 0x81 EP 1 IN (Interrupt), unused on the source */ 64 | #define mch347_ENDP_INTER_DOWN 0x01 /* This endpoint isn't list on my lsusb -v output, unused on the source */ 65 | #define mch347_ENDP_DATA_UP 0x82 /* ==BULK_READ_ENDPOINT Why repeat it? */ 66 | #define mch347_ENDP_DATA_DOWN 0x02 /* ==BULK_WRITE_ENDPOINT Why repeat it? */ 67 | 68 | #define mch347_VENDOR_READ 0xC0 /* Unused on the source */ 69 | #define mch347_VENDOR_WRITE 0x40 /* Unused on the source */ 70 | 71 | #define mch347_PARA_INIT 0xB1 /* Unused on the source */ 72 | #define mch347_I2C_STATUS 0x52 /* Unused on the source */ 73 | #define mch347_I2C_COMMAND 0x53 /* Unused on the source */ 74 | 75 | #define mch347_PARA_CMD_R0 0xAC /* Unused on the source */ 76 | #define mch347_PARA_CMD_R1 0xAD /* Unused on the source */ 77 | #define mch347_PARA_CMD_W0 0xA6 /* Unused on the source */ 78 | #define mch347_PARA_CMD_W1 0xA7 /* Unused on the source */ 79 | #define mch347_PARA_CMD_STS 0xA0 /* Unused on the source */ 80 | 81 | #define mch347_CMD_SET_OUTPUT 0xA1 /* Unused on the source */ 82 | #define mch347_CMD_IO_ADDR 0xA2 /* Unused on the source */ 83 | #define mch347_CMD_PRINT_OUT 0xA3 /* Unused on the source */ 84 | #define mch347_CMD_SPI_STREAM 0xA8 /* Unused on the source */ 85 | #define mch347_CMD_SIO_STREAM 0xA9 /* Unused on the source */ 86 | #define mch347_CMD_I2C_STREAM 0xAA 87 | #define mch347_CMD_UIO_STREAM 0xAB /* Unused on the source */ 88 | 89 | #define mch347_BUF_CLEAR 0xB2 /* Unused on the source */ 90 | #define mch347_I2C_CMD_X 0x54 /* Unused on the source */ 91 | #define mch347_DELAY_MS 0x5E /* Unused on the source */ 92 | #define mch347_GET_VER 0x5F /* Unused on the source */ 93 | 94 | #define mch347_EPP_IO_MAX ( mch347_PACKET_LENGTH - 1 ) /* Unused on the source */ 95 | #define mch347_EPP_IO_MAX 0xFF /* Unused on the source */ 96 | 97 | #define mch347_CMD_IO_ADDR_W 0x00 /* Unused on the source */ 98 | #define mch347_CMD_IO_ADDR_R 0x80 /* Unused on the source */ 99 | 100 | #define mch347_CMD_I2C_STM_STA 0x74 101 | #define mch347_CMD_I2C_STM_STO 0x75 102 | #define mch347_CMD_I2C_STM_OUT 0x80 103 | #define mch347_CMD_I2C_STM_IN 0xC0 104 | #define mch347_CMD_I2C_STM_MAX ( min( 0x3F, mch347_PACKET_LENGTH ) ) /* Unused on the source */ 105 | #define mch347_CMD_I2C_STM_SET 0x63 106 | #define mch347_CMD_I2C_STM_US 0x40 /* Unused on the source */ 107 | #define mch347_CMD_I2C_STM_MS 0x50 /* Unused on the source */ 108 | #define mch347_CMD_I2C_STM_DLY 0x0F /* Unused on the source */ 109 | #define mch347_CMD_I2C_STM_END 0x00 110 | 111 | #define mch347_CMD_UIO_STM_IN 0x00 /* Unused on the source */ 112 | #define mch347_CMD_UIO_STM_DIR 0x40 /* Unused on the source */ 113 | #define mch347_CMD_UIO_STM_OUT 0x80 /* Unused on the source */ 114 | #define mch347_CMD_UIO_STM_US 0xC0 /* Unused on the source */ 115 | #define mch347_CMD_UIO_STM_END 0x20 /* Unused on the source */ 116 | 117 | #define mch347_PARA_MODE_EPP 0x00 /* Unused on the source */ 118 | #define mch347_PARA_MODE_EPP17 0x00 /* Unused on the source */ 119 | #define mch347_PARA_MODE_EPP19 0x01 /* Unused on the source */ 120 | #define mch347_PARA_MODE_MEM 0x02 /* Unused on the source */ 121 | 122 | /* End of part based on (closed-source) DLL V1.9 for USB by WinChipHead (c) 2005. 123 | Since is largely unused we can replace it */ 124 | 125 | 126 | #define CH347_I2C_LOW_SPEED 0 // low speed - 20kHz 127 | #define CH347_I2C_STANDARD_SPEED 1 // standard speed - 100kHz 128 | #define CH347_I2C_FAST_SPEED 2 // fast speed - 400kHz 129 | #define CH347_I2C_HIGH_SPEED 3 // high speed - 750kHz 130 | 131 | #define CH347_EEPROM_READ_CMD_SZ 0x65 /* Same size for all 24cXX read setup and next packets*/ 132 | 133 | /* CH341a READ EEPROM setup packet for the 24c01 134 | this needs putting into a struct to allow convenient access to individual elements*/ 135 | #define CH347_EEPROM_24c01_READ_SETUP_CMD "\xaa\x74\x82\xa0\x00\x74\x81\xa1\xe0\x00\x0f\x00\x06\x04\x00\x00" \ 136 | "\x00\x00\x00\x00\x01\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 137 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 138 | "\xd9\x8b\x41\x7e\x00\xd0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 139 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 140 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 141 | "\xaa\xdf\xc0\x75\x00" 142 | /* please see file /wiresharkusbsniffing/sniffed.txt 143 | this is the read setup packet for 24c01 144 | 145 | 0040 aa 74 82 a0 00 74 81 a1 e0 00 0f 00 06 04 00 00 .t...t.. ........ 146 | 0050 00 00 00 00 01 00 00 00 11 4d 40 77 cd ab ba dc ........ .M@w.... 147 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 148 | 0070 d9 8b 41 7e 00 d0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 149 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 150 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 151 | 00a0 aa df c0 75 00 ...u. 152 | */ 153 | 154 | /* CH341a READ EEPROM next packet for 24c01 (no packets!!!)*/ 155 | 156 | 157 | /* CH341a READ EEPROM setup packet for the 24c02 158 | this needs putting into a struct to allow convenient access to individual elements*/ 159 | #define CH347_EEPROM_24c02_READ_SETUP_CMD "\xaa\x74\x82\xa0\x00\x74\x81\xa1\xe0\x00\x10\x00\x06\x04\x00\x00" \ 160 | "\x00\x00\x00\x00\x02\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 161 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 162 | "\xd9\x8b\x41\x7e\x00\xf0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 163 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 164 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 165 | "\xaa\xdf\xc0\x75\x00" 166 | /* please see file /wiresharkusbsniffing/sniffed.txt 167 | this is the read setup packet for 24c02 168 | 169 | 0040 aa 74 82 a0 00 74 81 a1 e0 00 10 00 06 04 00 00 .t...t.. ........ 170 | 0050 00 00 00 00 02 00 00 00 11 4d 40 77 cd ab ba dc ........ .M@w.... 171 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 172 | 0070 d9 8b 41 7e 00 f0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 173 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 174 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 175 | 00a0 aa df c0 75 00 ...u. 176 | */ 177 | 178 | /* CH341a READ EEPROM next packet for 24c02 (one packet)*/ 179 | #define CH347_EEPROM_24c02_READ_NEXT_CMD "\xaa\x74\x82\xa0\x80\x74\x81\xa1\xe0\x00\x00\x00\x10\x00\x00\x00" \ 180 | "\x00\x00\x00\x00\x8c\xf1\x12\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 181 | "\xaa\xe0\x00\x00\x4c\xf1\x12\x00\x5d\x22\xd7\x5a\xdc\xf1\x12\x00" \ 182 | "\x8f\x04\x44\x7e\x30\x88\x41\x7e\xff\xff\xff\xff\x2a\x88\x41\x7e" \ 183 | "\xaa\xe0\x00\x7e\x00\x00\x00\x00\x69\x0e\x3c\x00\xe4\x00\x18\x00" \ 184 | "\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xe8\x67\x00" \ 185 | "\xaa\xdf\xc0\x75\x00" 186 | /* please see file /wiresharkusbsniffing/sniffed.txt 187 | this is the read next packet for 24c02 (one packet) 188 | 189 | 0040 aa 74 82 a0 80 74 81 a1 e0 00 00 00 10 00 00 00 .t...t.. ........ 190 | 0050 00 00 00 00 8c f1 12 00 01 00 00 00 00 00 00 00 ........ ........ 191 | 0060 aa e0 00 00 4c f1 12 00 5d 22 d7 5a dc f1 12 00 ....L... ]".Z.... 192 | 0070 8f 04 44 7e 30 88 41 7e ff ff ff ff 2a 88 41 7e ..D~0.A~ ....*.A~ 193 | 0080 aa e0 00 7e 00 00 00 00 69 0e 3c 00 e4 00 18 00 ...~.... i.<..... 194 | 0090 0f 00 00 00 00 00 00 00 00 00 00 00 8c e8 67 00 ........ ......g. 195 | 00a0 aa df c0 75 00 ...u. 196 | */ 197 | 198 | 199 | /* CH341a READ EEPROM setup packet for the 24c04 200 | this needs putting into a struct to allow convenient access to individual elements*/ 201 | #define CH347_EEPROM_24c04_READ_SETUP_CMD "\xaa\x74\x82\xa0\x00\x74\x81\xa1\xe0\x00\x11\x00\x06\x04\x00\x00" \ 202 | "\x00\x00\x00\x00\x04\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 203 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 204 | "\xd9\x8b\x41\x7e\x00\xd0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 205 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 206 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 207 | "\xaa\xdf\xc0\x75\x00" 208 | /* please see file /wiresharkusbsniffing/sniffed.txt 209 | this is the read setup packet for 24c04 210 | 211 | 0040 aa 74 82 a0 00 74 81 a1 e0 00 11 00 06 04 00 00 .t...t.. ........ 212 | 0050 00 00 00 00 04 00 00 00 11 4d 40 77 cd ab ba dc ........ .M@w.... 213 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 214 | 0070 d9 8b 41 7e 00 d0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 215 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 216 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 217 | 00a0 aa df c0 75 00 ...u. 218 | */ 219 | 220 | /* CH341a READ EEPROM next packet for 24c04 (three packets)*/ 221 | #define CH347_EEPROM_24c04_READ_NEXT_CMD "\xaa\x74\x82\xa0\x80\x74\x81\xa1\xe0\x00\x00\x00\x10\x00\x00\x00" \ 222 | "\x00\x00\x00\x00\x8c\xf1\x12\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 223 | "\xaa\xe0\x00\x00\x4c\xf1\x12\x00\x5d\x22\xd7\x5a\xdc\xf1\x12\x00" \ 224 | "\x8f\x04\x44\x7e\x30\x88\x41\x7e\xff\xff\xff\xff\x2a\x88\x41\x7e" \ 225 | "\xaa\xe0\x00\x7e\x00\x00\x00\x00\x69\x0e\x3c\x00\xde\x00\x16\x00" \ 226 | "\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xe8\x67\x00" \ 227 | "\xaa\xdf\xc0\x75\x00" 228 | /* please see file /wiresharkusbsniffing/sniffed.txt 229 | this is the first read next packet for 24c04 (three different packets) 230 | 231 | 0040 aa 74 82 a0 80 74 81 a1 e0 00 00 00 10 00 00 00 .t...t.. ........ 232 | 0050 00 00 00 00 8c f1 12 00 01 00 00 00 00 00 00 00 ........ ........ 233 | 0060 aa e0 00 00 4c f1 12 00 5d 22 d7 5a dc f1 12 00 ....L... ]".Z.... 234 | 0070 8f 04 44 7e 30 88 41 7e ff ff ff ff 2a 88 41 7e ..D~0.A~ ....*.A~ 235 | 0080 aa e0 00 7e 00 00 00 00 69 0e 3c 00 de 00 16 00 ...~.... i.<..... 236 | 0090 0f 00 00 00 00 00 00 00 00 00 00 00 8c e8 67 00 ........ ......g. 237 | 00a0 aa df c0 75 00 ...u. 238 | */ 239 | 240 | 241 | /* CH341a READ EEPROM setup packet for the 24c08 242 | this needs putting into a struct to allow convenient access to individual elements*/ 243 | #define CH347_EEPROM_24c08_READ_SETUP_CMD "\xaa\x74\x82\xa0\x00\x74\x81\xa1\xe0\x00\x16\x00\x06\x04\x00\x00" \ 244 | "\x00\x00\x00\x00\x08\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 245 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 246 | "\xd9\x8b\x41\x7e\x00\xd0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 247 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 248 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 249 | "\xaa\xdf\xc0\x75\x00" 250 | /* please see file /wiresharkusbsniffing/sniffed.txt 251 | this is the read setup packet for 24c08 252 | 253 | 0040 aa 74 82 a0 00 74 81 a1 e0 00 16 00 06 04 00 00 .t...t.. ........ 254 | 0050 00 00 00 00 08 00 00 00 11 4d 40 77 cd ab ba dc ........ .M@w.... 255 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 256 | 0070 d9 8b 41 7e 00 d0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 257 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 258 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 259 | 00a0 aa df c0 75 00 ...u. 260 | */ 261 | 262 | /* CH341a READ EEPROM next packet for 24c08 (seven packets)*/ 263 | #define CH347_EEPROM_24c08_READ_NEXT_CMD "\xaa\x74\x82\xa0\x80\x74\x81\xa1\xe0\x00\x00\x00\x10\x00\x00\x00" \ 264 | "\x00\x00\x00\x00\x8c\xf1\x12\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 265 | "\xaa\xe0\x00\x00\x4c\xf1\x12\x00\x5d\x22\xd7\x5a\xdc\xf1\x12\x00" \ 266 | "\x8f\x04\x44\x7e\x30\x88\x41\x7e\xff\xff\xff\xff\x2a\x88\x41\x7e" \ 267 | "\xaa\xe0\x00\x7e\x00\x00\x00\x00\x69\x0e\x3c\x00\x00\x01\x1a\x00" \ 268 | "\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xe8\x67\x00" \ 269 | "\xaa\xdf\xc0\x75\x00" 270 | /* please see file /wiresharkusbsniffing/sniffed.txt 271 | this is the first read next packet for 24c08 (seven different packets) 272 | 273 | 0040 aa 74 82 a0 80 74 81 a1 e0 00 00 00 10 00 00 00 .t...t.. ........ 274 | 0050 00 00 00 00 8c f1 12 00 01 00 00 00 00 00 00 00 ........ ........ 275 | 0060 aa e0 00 00 4c f1 12 00 5d 22 d7 5a dc f1 12 00 ....L... ]".Z.... 276 | 0070 8f 04 44 7e 30 88 41 7e ff ff ff ff 2a 88 41 7e ..D~0.A~ ....*.A~ 277 | 0080 aa e0 00 7e 00 00 00 00 69 0e 3c 00 00 01 1a 00 ...~.... i.<..... 278 | 0090 0f 00 00 00 00 00 00 00 00 00 00 00 8c e8 67 00 ........ ......g. 279 | 00a0 aa df c0 75 00 ...u. 280 | */ 281 | 282 | 283 | /* CH341a READ EEPROM setup packet for the 24c16 284 | this needs putting into a struct to allow convenient access to individual elements*/ 285 | #define CH347_EEPROM_24c16_READ_SETUP_CMD "\xaa\x74\x82\xa0\x00\x74\x81\xa1\xe0\x00\x0e\x00\x06\x04\x00\x00" \ 286 | "\x00\x00\x00\x00\x10\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 287 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 288 | "\xd9\x8b\x41\x7e\x00\xe0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 289 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 290 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 291 | "\xaa\xdf\xc0\x75\x00" 292 | /* please see file /wiresharkusbsniffing/sniffed.txt 293 | this is the read setup packet for 24c16 294 | 295 | 0040 aa 74 82 a0 00 74 81 a1 e0 00 0e 00 06 04 00 00 .t...t.. ........ 296 | 0050 00 00 00 00 10 00 00 00 11 4d 40 77 cd ab ba dc ........ .M@w.... 297 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 298 | 0070 d9 8b 41 7e 00 e0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 299 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 300 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 301 | 00a0 aa df c0 75 00 ...u. 302 | */ 303 | 304 | /* CH341a READ EEPROM next packet for 24c16*/ 305 | #define CH347_EEPROM_24c16_READ_NEXT_CMD "\xaa\x74\x82\xa0\x80\x74\x81\xa1\xe0\x00\x00\x00\x10\x00\x00\x00" \ 306 | "\x00\x00\x00\x00\x8c\xf1\x12\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 307 | "\xaa\xe0\x00\x00\x4c\xf1\x12\x00\x5d\x22\xd7\x5a\xdc\xf1\x12\x00" \ 308 | "\x8f\x04\x44\x7e\x30\x88\x41\x7e\xff\xff\xff\xff\x2a\x88\x41\x7e" \ 309 | "\xaa\xe0\x00\x7e\x00\x00\x00\x00\x69\x0e\x3c\x00\xfa\x00\x31\x00" \ 310 | "\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xe8\x67\x00" \ 311 | "\xaa\xdf\xc0\x75\x00" 312 | /* please see file /wiresharkusbsniffing/sniffed.txt 313 | this is the first read next packet for 24c16 (fifteen different packets) 314 | 315 | 0040 aa 74 82 a0 80 74 81 a1 e0 00 00 00 10 00 00 00 .t...t.. ........ 316 | 0050 00 00 00 00 8c f1 12 00 01 00 00 00 00 00 00 00 ........ ........ 317 | 0060 aa e0 00 00 4c f1 12 00 5d 22 d7 5a dc f1 12 00 ....L... ]".Z.... 318 | 0070 8f 04 44 7e 30 88 41 7e ff ff ff ff 2a 88 41 7e ..D~0.A~ ....*.A~ 319 | 0080 aa e0 00 7e 00 00 00 00 69 0e 3c 00 fa 00 31 00 ...~.... i.<...1. 320 | 0090 0f 00 00 00 00 00 00 00 00 00 00 00 8c e8 67 00 ........ ......g. 321 | 00a0 aa df c0 75 00 ...u. 322 | */ 323 | 324 | 325 | /* CH341a READ EEPROM setup packet for the 24c64 326 | this needs putting into a struct to allow convenient access to individual elements*/ 327 | #define CH347_EEPROM_24c64_READ_SETUP_CMD "\xaa\x74\x83\xa0\x00\x00\x74\x81\xa1\xe0\x00\x00\x06\x04\x00\x00" \ 328 | "\x00\x00\x00\x00\x40\x00\x00\x00\x11\x4d\x40\x77\xcd\xab\xba\xdc" \ 329 | "\xaa\xe0\x00\x00\xc4\xf1\x12\x00\x11\x4d\x40\x77\xf0\xf1\x12\x00" \ 330 | "\xd9\x8b\x41\x7e\x00\xf0\xfd\x7f\xf0\xf1\x12\x00\x5a\x88\x41\x7e" \ 331 | "\xaa\xe0\x00\x00\x2a\x88\x41\x7e\x06\x04\x00\x00\x11\x4d\x40\x77" \ 332 | "\xe8\xf3\x12\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 333 | "\xaa\xdf\xc0\x75\x00" 334 | /* please see file /wiresharkusbsniffing/sniffed.txt 335 | this is the read setup packet for 24c64 336 | 337 | 0040 aa 74 83 a0 00 00 74 81 a1 e0 00 00 06 04 00 00 .t....t. ........ 338 | 0050 00 00 00 00 40 00 00 00 11 4d 40 77 cd ab ba dc ....@... .M@w.... 339 | 0060 aa e0 00 00 c4 f1 12 00 11 4d 40 77 f0 f1 12 00 ........ .M@w.... 340 | 0070 d9 8b 41 7e 00 e0 fd 7f f0 f1 12 00 5a 88 41 7e ..A~.... ....Z.A~ 341 | 0080 aa e0 00 00 2a 88 41 7e 06 04 00 00 11 4d 40 77 ....*.A~ .....M@w 342 | 0090 e8 f3 12 00 14 00 00 00 01 00 00 00 00 00 00 00 ........ ........ 343 | 00a0 aa df c0 75 00 ...u. 344 | */ 345 | 346 | /* CH341a READ EEPROM next packet for 24c64 (63 packets)*/ 347 | #define CH347_EEPROM_24c64_READ_NEXT_CMD "\xaa\x74\x83\xa0\x00\x00\x74\x81\xa1\xe0\x00\x00\x10\x00\x00\x00" \ 348 | "\x00\x00\x00\x00\x8c\xf1\x12\x00\x01\x00\x00\x00\x00\x00\x00\x00" \ 349 | "\xaa\xe0\x00\x00\x4c\xf1\x12\x00\x5d\x22\xd7\x5a\xdc\xf1\x12\x00" \ 350 | "\x8f\x04\x44\x7e\x30\x88\x41\x7e\xff\xff\xff\xff\x2a\x88\x41\x7e" \ 351 | "\xaa\xe0\x00\x7e\x00\x00\x00\x00\x69\x0e\x3c\x00\x12\x01\x19\x00" \ 352 | "\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\x2e\x68\x00" \ 353 | "\xaa\xdf\xc0\x75\x00" 354 | /* please see file /wiresharkusbsniffing/sniffed.txt 355 | this is the first read next packet for 24c64 (63 different packets) 356 | 357 | 0040 aa 74 83 a0 00 80 74 81 a1 e0 00 00 10 00 00 00 .t....t. ........ 358 | 0050 00 00 00 00 8c f1 12 00 01 00 00 00 00 00 00 00 ........ ........ 359 | 0060 aa e0 00 00 4c f1 12 00 5d 22 d7 5a dc f1 12 00 ....L... ]".Z.... 360 | 0070 8f 04 44 7e 30 88 41 7e ff ff ff ff 2a 88 41 7e ..D~0.A~ ....*.A~ 361 | 0080 aa e0 00 7e 00 00 00 00 69 0e 3c 00 3a 01 1b 00 ...~.... i.<.:... 362 | 0090 0f 00 00 00 00 00 00 00 00 00 00 00 8c e8 67 00 ........ ......g. 363 | 00a0 aa df c0 75 00 ...u. 364 | */ 365 | 366 | #define MIN(a,b) (((a)<(b))?(a):(b)) 367 | #define MAX(a,b) (((a)>(b))?(a):(b)) 368 | 369 | #define TRUE 1 370 | #define FALSE 0 371 | 372 | struct EEPROM { 373 | char *name; 374 | uint32_t size; 375 | uint16_t page_size; 376 | uint8_t addr_size; // Length of addres in bytes 377 | uint8_t i2c_addr_mask; 378 | }; 379 | 380 | const static struct EEPROM eepromlist[] = { 381 | { "24c01", 128, 8, 1, 0x00 }, // 16 pages of 8 bytes each = 128 bytes 382 | { "24c02", 256, 8, 1, 0x00 }, // 32 pages of 8 bytes each = 256 bytes 383 | { "24c04", 512, 16, 1, 0x01 }, // 32 pages of 16 bytes each = 512 bytes 384 | { "24c08", 1024, 16, 1, 0x03 }, // 64 pages of 16 bytes each = 1024 bytes 385 | { "24c16", 2048, 16, 1, 0x07 }, // 128 pages of 16 bytes each = 2048 bytes 386 | { "24c32", 4096, 32, 2, 0x00 }, // 32kbit = 4kbyte 387 | { "24c64", 8192, 32, 2, 0x00 }, 388 | { "24c128", 16384, 32/*64*/, 2, 0x00 }, 389 | { "24c256", 32768, 32/*64*/, 2, 0x00 }, 390 | { "24c512", 65536, 32/*128*/, 2, 0x00 }, 391 | { "24c1024", 131072, 32/*128*/, 2, 0x01 }, 392 | { 0, 0, 0, 0 } 393 | }; 394 | 395 | struct i2c_msg { 396 | uint16_t addr; /* slave address */ 397 | uint16_t flags; 398 | #define I2C_M_RD 0x0001 /* read data, from slave to master */ 399 | /* I2C_M_RD is guaranteed to be 0x0001! */ 400 | #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ 401 | #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */ 402 | /* makes only sense in kernelspace */ 403 | /* userspace buffers are copied anyway */ 404 | #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ 405 | #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ 406 | #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ 407 | #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ 408 | #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ 409 | #define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ 410 | uint16_t len; /* msg length */ 411 | uint8_t *buf; /* pointer to msg data */ 412 | }; 413 | 414 | 415 | int32_t ch347readEEPROM(uint8_t *buf, uint32_t bytes, struct EEPROM *eeprom_info); 416 | int32_t ch347writeEEPROM(uint8_t *buf, uint32_t bytes, struct EEPROM *eeprom_info); 417 | int32_t parseEEPsize(char *eepromname, struct EEPROM *eeprom); 418 | int32_t ch347i2cConfig(int speed); 419 | #endif /* __CH347_I2C_H__ */ 420 | -------------------------------------------------------------------------------- /src/ch347_spi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the flashrom project. 3 | * 4 | * Copyright (C) 2011 asbokid 5 | * Copyright (C) 2014 Pluto Yang 6 | * Copyright (C) 2015-2016 Stefan Tauner 7 | * Copyright (C) 2015 Urja Rannikko 8 | * Copyright (C) 2018-2021 McMCC 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | */ 24 | #include 25 | #include 26 | #include "ch347_spi.h" 27 | #include 28 | #include 29 | /* LIBUSB_CALL ensures the right calling conventions on libusb callbacks. 30 | * However, the macro is not defined everywhere. m( 31 | */ 32 | #ifndef LIBUSB_CALL 33 | #define LIBUSB_CALL 34 | #endif 35 | 36 | #define CH347_VID 0x1A86 37 | #define CH347T_PID 0x55DB 38 | #define CH347F_PID 0x55DE 39 | 40 | #define CH347_CMD_SPI_SET_CFG 0xC0 41 | #define CH347_CMD_SPI_CS_CTRL 0xC1 42 | #define CH347_CMD_SPI_OUT_IN 0xC2 43 | #define CH347_CMD_SPI_IN 0xC3 44 | #define CH347_CMD_SPI_OUT 0xC4 45 | #define CH347_CMD_SPI_GET_CFG 0xCA 46 | 47 | #define CH347_CS_ASSERT 0x00 48 | #define CH347_CS_DEASSERT 0x40 49 | #define CH347_CS_CHANGE 0x80 50 | #define CH347_CS_IGNORE 0x00 51 | 52 | #define WRITE_EP 0x06 53 | #define READ_EP 0x86 54 | 55 | #define MODE_1_IFACE 2 56 | #define MODE_2_IFACE 1 57 | 58 | 59 | #define CH341_PACKET_LENGTH 0x20 60 | 61 | 62 | struct device_speeds { 63 | const char *name; 64 | const int speed; 65 | }; 66 | /* The USB descriptor says the max transfer size is 512 bytes, but the 67 | * vendor driver only seems to transfer a maximum of 510 bytes at once, 68 | * leaving 507 bytes for data as the command + length take up 3 bytes 69 | */ 70 | #define CH347_PACKET_SIZE 510 71 | #define CH347_MAX_DATA_LEN (CH347_PACKET_SIZE - 3) 72 | static const struct device_speeds spispeeds[] = { 73 | {"60M", 0x0}, 74 | {"30M", 0x1}, 75 | {"15M", 0x2}, 76 | {"7.5M", 0x3}, 77 | {"3.75M", 0x4}, 78 | {"1.875M", 0x5}, 79 | {"937.5K", 0x6}, 80 | {"468.75", 0x7}, 81 | {NULL, 0x0} 82 | }; 83 | bool isCH347F = false; 84 | #ifdef _WIN32 85 | #include 86 | // 设备信息 87 | typedef struct _DEV_INFOR { 88 | UCHAR iIndex; // 当前打开序号 89 | UCHAR DevicePath[MAX_PATH]; // 设备链接名,用于CreateFile 90 | UCHAR UsbClass; // 驱动类别 0:CH347_USB_CH341, 2:CH347_USB_HID,3:CH347_USB_VCP 91 | UCHAR FuncType; // 功能类别 0:CH347_FUNC_UART,1:CH347_FUNC_SPI_I2C,2:CH347_FUNC_JTAG_I2C 92 | CHAR DeviceID[64]; // USB\VID_xxxx&PID_xxxx 93 | UCHAR ChipMode; // 芯片工作模式,0:Mode0(UART0/1); 1:Mode1(Uart1+SPI+I2C); 2:Mode2(HID Uart1+SPI+I2C) 3:Mode3(Uart1+Jtag+IIC) 4:CH347F(Uart*2+Jtag/SPI/IIC) 94 | HANDLE DevHandle; // 设备句柄 95 | USHORT BulkOutEndpMaxSize; // 批量上传端点大小 96 | USHORT BulkInEndpMaxSize; // 批量下传端点大小 97 | UCHAR UsbSpeedType; // USB速度类型,0:FS,1:HS,2:SS 98 | UCHAR CH347IfNum; // USB接口号: CH347T: IF0:UART; IF1:SPI/IIC/JTAG/GPIO 99 | // CH347F: IF0:UART0; IF1:UART1; IF 2:SPI/IIC/JTAG/GPIO 100 | UCHAR DataUpEndp; // 批量上传端点地址 101 | UCHAR DataDnEndp; // 批量下传端点地址 102 | CHAR ProductString[64]; // USB产品字符串 103 | CHAR ManufacturerString[64]; // USB厂商字符串 104 | ULONG WriteTimeout; // USB写超时 105 | ULONG ReadTimeout; // USB读超时 106 | CHAR FuncDescStr[64]; // 接口功能描述符 107 | UCHAR FirewareVer; // 固件版本,十六进制值 108 | } mDeviceInforS, *mPDeviceInforS; 109 | typedef int(__stdcall * pCH347OpenDevice)(unsigned long iIndex); 110 | 111 | typedef int(__stdcall * pCH347CloseDevice)(unsigned long iIndex); 112 | typedef unsigned long(__stdcall * pCH347SetTimeout)( 113 | unsigned long iIndex, /* Specify equipment serial number */ 114 | unsigned long iWriteTimeout, /* Specifies the timeout period for USB 115 | write out data blocks, in milliseconds 116 | mS, and 0xFFFFFFFF specifies no timeout 117 | (default) */ 118 | unsigned long iReadTimeout); /* Specifies the timeout period for USB 119 | reading data blocks, in milliseconds mS, 120 | and 0xFFFFFFFF specifies no timeout 121 | (default) */ 122 | 123 | typedef unsigned long(__stdcall * pCH347WriteData)( 124 | unsigned long iIndex, /* Specify equipment serial number */ 125 | void *oBuffer, /* Point to a buffer large enough to hold 126 | the descriptor */ 127 | unsigned long *ioLength); /* Pointing to the length unit, the input 128 | is the length to be read, and the 129 | return is the actual read length */ 130 | 131 | typedef unsigned long(__stdcall * pCH347ReadData)( 132 | unsigned long iIndex, /* Specify equipment serial number */ 133 | void *oBuffer, /* Point to a buffer large enough to 134 | hold the descriptor */ 135 | unsigned long *ioLength); /* Pointing to the length unit, the input 136 | is the length to be read, and the 137 | return is the actual read length */ 138 | typedef unsigned long(__stdcall * pCH347GetDeviceInfor)(unsigned long iIndex, mDeviceInforS *DevInformation); 139 | HMODULE uhModule = 0; 140 | ULONG ugIndex = -1; 141 | pCH347OpenDevice CH347OpenDevice; 142 | pCH347CloseDevice CH347CloseDevice; 143 | pCH347SetTimeout CH347SetTimeout; 144 | pCH347ReadData CH347ReadData; 145 | pCH347WriteData CH347WriteData; 146 | pCH347GetDeviceInfor CH347GetDeviceInfor; 147 | BOOL DevIsOpened = FALSE; /* Whether the device is turned on */ 148 | #endif 149 | struct libusb_device_handle *devHandle = NULL; 150 | 151 | 152 | /* Number of parallel IN transfers. 32 seems to produce the most stable throughput on Windows. */ 153 | #define USB_IN_TRANSFERS 32 154 | 155 | struct dev_entry { 156 | uint16_t vendor_id; 157 | uint16_t device_id; 158 | const char *vendor_name; 159 | const char *device_name; 160 | }; 161 | 162 | /* TODO: Add support for HID mode */ 163 | static const struct dev_entry devs_ch347_spi[] = { 164 | {CH347_VID, CH347T_PID, "WCH", "CH347T"}, 165 | {CH347_VID, CH347F_PID, "WCH", "CH347F"}, 166 | {0}, 167 | }; 168 | 169 | /* We need to use many queued IN transfers for any resemblance of performance (especially on Windows) 170 | * because USB spec says that transfers end on non-full packets and the device sends the 31 reply 171 | * data bytes to each 32-byte packet with command + 31 bytes of data... */ 172 | static struct libusb_transfer *transfer_out = NULL; 173 | static struct libusb_transfer *transfer_ins[USB_IN_TRANSFERS] = {0}; 174 | 175 | enum trans_state {TRANS_ACTIVE = -2, TRANS_ERR = -1, TRANS_IDLE = 0}; 176 | 177 | #if 0 178 | static void print_hex(const void *buf, size_t len) 179 | { 180 | size_t i; 181 | for (i = 0; i < len; i++) { 182 | printf(" %02x", ((uint8_t *)buf)[i]); 183 | if (i % CH341_PACKET_LENGTH == CH341_PACKET_LENGTH - 1) 184 | printf("\n"); 185 | } 186 | } 187 | 188 | 189 | static void cb_common(const char *func, struct libusb_transfer *transfer) 190 | { 191 | int *transfer_cnt = (int*)transfer->user_data; 192 | 193 | if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { 194 | /* Silently ACK and exit. */ 195 | *transfer_cnt = TRANS_IDLE; 196 | return; 197 | } 198 | 199 | if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 200 | printf("\n%s: error: %s\n", func, libusb_error_name(transfer->status)); 201 | *transfer_cnt = TRANS_ERR; 202 | } else { 203 | *transfer_cnt = transfer->actual_length; 204 | } 205 | } 206 | 207 | /* callback for bulk out async transfer */ 208 | static void LIBUSB_CALL cb_out(struct libusb_transfer *transfer) 209 | { 210 | cb_common(__func__, transfer); 211 | } 212 | 213 | /* callback for bulk in async transfer */ 214 | static void LIBUSB_CALL cb_in(struct libusb_transfer *transfer) 215 | { 216 | cb_common(__func__, transfer); 217 | } 218 | 219 | static int32_t usb_transfer(const char *func, unsigned int writecnt, unsigned int readcnt, const uint8_t *writearr, uint8_t *readarr) 220 | { 221 | if (devHandle == NULL) 222 | return -1; 223 | 224 | int state_out = TRANS_IDLE; 225 | transfer_out->buffer = (uint8_t*)writearr; 226 | transfer_out->length = writecnt; 227 | transfer_out->user_data = &state_out; 228 | 229 | /* Schedule write first */ 230 | if (writecnt > 0) { 231 | state_out = TRANS_ACTIVE; 232 | int ret = libusb_submit_transfer(transfer_out); 233 | if (ret) { 234 | printf("%s: failed to submit OUT transfer: %s\n", func, libusb_error_name(ret)); 235 | state_out = TRANS_ERR; 236 | goto err; 237 | } 238 | } 239 | 240 | /* Handle all asynchronous packets as long as we have stuff to write or read. The write(s) simply need 241 | * to complete but we need to scheduling reads as long as we are not done. */ 242 | unsigned int free_idx = 0; /* The IN transfer we expect to be free next. */ 243 | unsigned int in_idx = 0; /* The IN transfer we expect to be completed next. */ 244 | unsigned int in_done = 0; 245 | unsigned int in_active = 0; 246 | unsigned int out_done = 0; 247 | uint8_t *in_buf = readarr; 248 | int state_in[USB_IN_TRANSFERS] = {0}; 249 | do { 250 | /* Schedule new reads as long as there are free transfers and unscheduled bytes to read. */ 251 | while ((in_done + in_active) < readcnt && state_in[free_idx] == TRANS_IDLE) { 252 | unsigned int cur_todo = min(CH341_PACKET_LENGTH - 1, readcnt - in_done - in_active); 253 | transfer_ins[free_idx]->length = cur_todo; 254 | transfer_ins[free_idx]->buffer = in_buf; 255 | transfer_ins[free_idx]->user_data = &state_in[free_idx]; 256 | int ret = libusb_submit_transfer(transfer_ins[free_idx]); 257 | if (ret) { 258 | state_in[free_idx] = TRANS_ERR; 259 | printf("%s: failed to submit IN transfer: %s\n", 260 | func, libusb_error_name(ret)); 261 | goto err; 262 | } 263 | in_buf += cur_todo; 264 | in_active += cur_todo; 265 | state_in[free_idx] = TRANS_ACTIVE; 266 | free_idx = (free_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */ 267 | } 268 | 269 | /* Actually get some work done. */ 270 | libusb_handle_events_timeout(NULL, &(struct timeval){1, 0}); 271 | 272 | /* Check for the write */ 273 | if (out_done < writecnt) { 274 | if (state_out == TRANS_ERR) { 275 | goto err; 276 | } else if (state_out > 0) { 277 | out_done += state_out; 278 | state_out = TRANS_IDLE; 279 | } 280 | } 281 | /* Check for completed transfers. */ 282 | while (state_in[in_idx] != TRANS_IDLE && state_in[in_idx] != TRANS_ACTIVE) { 283 | if (state_in[in_idx] == TRANS_ERR) { 284 | goto err; 285 | } 286 | /* If a transfer is done, record the number of bytes read and reuse it later. */ 287 | in_done += state_in[in_idx]; 288 | in_active -= state_in[in_idx]; 289 | state_in[in_idx] = TRANS_IDLE; 290 | in_idx = (in_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */ 291 | } 292 | } while ((out_done < writecnt) || (in_done < readcnt)); 293 | #if 0 294 | if (out_done > 0) { 295 | printf("Wrote %d bytes:\n", out_done); 296 | print_hex(writearr, out_done); 297 | printf("\n\n"); 298 | } 299 | if (in_done > 0) { 300 | printf("Read %d bytes:\n", in_done); 301 | print_hex(readarr, in_done); 302 | printf("\n\n"); 303 | } 304 | #endif 305 | return 0; 306 | err: 307 | /* Clean up on errors. */ 308 | printf("%s: Failed to %s %d bytes\n", func, (state_out == TRANS_ERR) ? "write" : "read", 309 | (state_out == TRANS_ERR) ? writecnt : readcnt); 310 | /* First, we must cancel any ongoing requests and wait for them to be canceled. */ 311 | if ((writecnt > 0) && (state_out == TRANS_ACTIVE)) { 312 | if (libusb_cancel_transfer(transfer_out) != 0) 313 | state_out = TRANS_ERR; 314 | } 315 | if (readcnt > 0) { 316 | unsigned int i; 317 | for (i = 0; i < USB_IN_TRANSFERS; i++) { 318 | if (state_in[i] == TRANS_ACTIVE) 319 | if (libusb_cancel_transfer(transfer_ins[i]) != 0) 320 | state_in[i] = TRANS_ERR; 321 | } 322 | } 323 | 324 | /* Wait for cancellations to complete. */ 325 | while (1) { 326 | bool finished = true; 327 | if ((writecnt > 0) && (state_out == TRANS_ACTIVE)) 328 | finished = false; 329 | if (readcnt > 0) { 330 | unsigned int i; 331 | for (i = 0; i < USB_IN_TRANSFERS; i++) { 332 | if (state_in[i] == TRANS_ACTIVE) 333 | finished = false; 334 | } 335 | } 336 | if (finished) 337 | break; 338 | libusb_handle_events_timeout(NULL, &(struct timeval){1, 0}); 339 | } 340 | return -1; 341 | } 342 | #endif 343 | 344 | static uint16_t read_le16(const uint8_t *base, size_t offset) { 345 | // 读取 16 位值(两个字节)并以小端序合并 346 | uint16_t value = base[offset] | (base[offset + 1] << 8); 347 | // printf("value = %d\n",value); 348 | return value; 349 | } 350 | 351 | /* Set the I2C bus speed (speed(b1b0): 0 = 20kHz; 1 = 100kHz, 2 = 400kHz, 3 = 750kHz). 352 | * Set the SPI bus data width (speed(b2): 0 = Single, 1 = Double). */ 353 | int config_stream(unsigned int speed) 354 | { 355 | int32_t ret; 356 | uint8_t buff[29] = { 357 | [0] = CH347_CMD_SPI_SET_CFG, 358 | [1] = (sizeof(buff) - 3) & 0xFF, 359 | [2] = ((sizeof(buff) - 3) & 0xFF00) >> 8, 360 | /* Not sure what these two bytes do, but the vendor 361 | * drivers seem to unconditionally set these values 362 | */ 363 | [3] = 0, 364 | [4] = 0, 365 | [5] = 4, 366 | [6] = 1, 367 | /* Clock polarity: bit 1 */ 368 | [9] = 0, 369 | /* Clock phase: bit 0 */ 370 | [11] = 0, 371 | /* Another mystery byte */ 372 | [14] = 2, 373 | /* Clock divisor: bits 5:3 */ 374 | [15] = (speed & 0x7) << 3, 375 | /* Bit order: bit 7, 0=MSB */ 376 | [17] = 0, 377 | /* Yet another mystery byte */ 378 | [19] = 7, 379 | /* CS polarity: bit 7 CS2, bit 6 CS1. 0 = active low */ 380 | [24] = 0 381 | }; 382 | #ifdef _WIN32 383 | ULONG transferred = sizeof(buff); 384 | if (!CH347WriteData(ugIndex, buff, &transferred)){ 385 | printf("Could not configure SPI interface\n"); 386 | return -1; 387 | } 388 | transferred = 4; 389 | if (!CH347ReadData(ugIndex, buff, &transferred) || buff[3] != 0x0){ 390 | printf("configure SPI fail\n"); 391 | return -1; 392 | } 393 | ret = 0; 394 | #elif defined(__linux__) 395 | ret = libusb_bulk_transfer(devHandle, WRITE_EP, buff, sizeof(buff), NULL, 1000); 396 | if (ret < 0) { 397 | printf("Could not configure SPI interface\n"); 398 | } 399 | 400 | /* FIXME: Not sure if the CH347 sends error responses for 401 | * invalid config data, if so the code should check 402 | */ 403 | ret = libusb_bulk_transfer(devHandle, READ_EP, buff, 4, NULL, 1000); 404 | if (ret < 0 || buff[3] != 0x0) { 405 | printf("Could not receive configure SPI command response\n"); 406 | } 407 | #endif 408 | return ret; 409 | } 410 | 411 | /* ch341 requires LSB first, swap the bit order before send and after receive */ 412 | static uint8_t swap_byte(uint8_t x) 413 | { 414 | x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa); 415 | x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc); 416 | x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0); 417 | return x; 418 | } 419 | 420 | static int ch347_cs_control(uint8_t cs1, uint8_t cs2) 421 | { 422 | uint8_t cmd[13] = { 423 | [0] = CH347_CMD_SPI_CS_CTRL, 424 | /* payload length, uint16 LSB: 10 */ 425 | [1] = 10, 426 | [3] = cs1, 427 | [8] = cs2 428 | }; 429 | #ifdef _WIN32 430 | ULONG transferred = sizeof(cmd); 431 | if (!CH347WriteData(ugIndex, cmd, &transferred) || transferred != sizeof(cmd)){ 432 | printf("Could not change CS!\n"); 433 | return -1; 434 | } 435 | #elif defined(__linux__) 436 | int32_t ret = libusb_bulk_transfer(devHandle, WRITE_EP, cmd, sizeof(cmd), NULL, 1000); 437 | if (ret < 0) { 438 | printf("Could not change CS!\n"); 439 | return -1; 440 | } 441 | #endif 442 | return 0; 443 | } 444 | 445 | int enable_pins(bool enable) 446 | { 447 | if (enable){ 448 | ch347_cs_control(CH347_CS_ASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE); 449 | } 450 | else{ 451 | ch347_cs_control(CH347_CS_DEASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE); 452 | } 453 | } 454 | 455 | static int ch347_write(unsigned int writecnt, const uint8_t *writearr) 456 | { 457 | unsigned int data_len; 458 | int packet_len; 459 | int ret; 460 | uint8_t resp_buf[4] = {0}; 461 | uint8_t buffer[CH347_PACKET_SIZE] = {0}; 462 | unsigned int bytes_written = 0; 463 | 464 | while (bytes_written < writecnt) { 465 | data_len = min(CH347_MAX_DATA_LEN, writecnt - bytes_written ); 466 | packet_len = data_len + 3; 467 | 468 | buffer[0] = CH347_CMD_SPI_OUT; 469 | buffer[1] = (data_len) & 0xFF; 470 | buffer[2] = ((data_len) & 0xFF00) >> 8; 471 | memcpy(buffer + 3, writearr + bytes_written, data_len); 472 | #ifdef _WIN32 473 | ULONG transferred; 474 | 475 | transferred = packet_len; 476 | if (!CH347WriteData(ugIndex, buffer, &transferred) || transferred != packet_len){ 477 | printf("Could not send write command\n"); 478 | return -1; 479 | } 480 | transferred = sizeof(resp_buf); 481 | if(!CH347ReadData(ugIndex, resp_buf, &transferred) || transferred != sizeof(resp_buf)){ 482 | printf("Could not receive write command response\n"); 483 | return -1; 484 | } 485 | #elif defined(__linux__) 486 | unsigned long transferred = packet_len; 487 | ret = libusb_bulk_transfer(devHandle, WRITE_EP, buffer, packet_len, &transferred, 1000); 488 | if (ret < 0 || transferred != packet_len) { 489 | printf("Could not send write command\n"); 490 | return -1; 491 | } 492 | ret = libusb_bulk_transfer(devHandle, READ_EP, resp_buf, sizeof(resp_buf), NULL, 1000); 493 | if (ret < 0) { 494 | printf("Could not receive write command response\n"); 495 | return -1; 496 | } 497 | #endif 498 | bytes_written += data_len; 499 | } 500 | return 0; 501 | } 502 | 503 | static int ch347_read(unsigned int readcnt, uint8_t *readarr) 504 | { 505 | uint8_t *read_ptr = readarr; 506 | int ret; 507 | unsigned int bytes_read = 0; 508 | uint8_t buffer[CH347_PACKET_SIZE] = {0}; 509 | uint8_t command_buf[7] = { 510 | [0] = CH347_CMD_SPI_IN, 511 | [1] = 4, 512 | [2] = 0, 513 | [3] = readcnt & 0xFF, 514 | [4] = (readcnt & 0xFF00) >> 8, 515 | [5] = (readcnt & 0xFF0000) >> 16, 516 | [6] = (readcnt & 0xFF000000) >> 24 517 | }; 518 | #ifdef _WIN32 519 | ULONG transferred; 520 | transferred = sizeof(command_buf); 521 | if (!CH347WriteData(ugIndex, command_buf, &transferred) || transferred != sizeof(command_buf)){ 522 | printf("Could not send read command\n"); 523 | return -1; 524 | } 525 | #elif defined(__linux__) 526 | unsigned long transferred = sizeof(command_buf); 527 | ret = libusb_bulk_transfer(devHandle, WRITE_EP, command_buf, sizeof(command_buf), &transferred, 1000); 528 | if (ret < 0 || transferred != sizeof(command_buf)) { 529 | printf("Could not send read command\n"); 530 | return -1; 531 | } 532 | #endif 533 | while (bytes_read < readcnt) { 534 | #ifdef _WIN32 535 | transferred = CH347_PACKET_SIZE; 536 | if (!CH347ReadData(ugIndex, buffer, &transferred)){ 537 | printf("Could not read data\n"); 538 | return -1; 539 | } 540 | #elif defined(__linux__) 541 | ret = libusb_bulk_transfer(devHandle, READ_EP, buffer, CH347_PACKET_SIZE, &transferred, 1000); 542 | if (ret < 0) { 543 | printf("Could not read data\n"); 544 | return -1; 545 | } 546 | #endif 547 | if (transferred > CH347_PACKET_SIZE) { 548 | printf("libusb bug: bytes received overflowed buffer\n"); 549 | return -1; 550 | } 551 | /* Response: u8 command, u16 data length, then the data that was read */ 552 | if (transferred < 3) { 553 | printf("CH347 returned an invalid response to read command\n"); 554 | return -1; 555 | } 556 | // printf("buffer [1] = %02x [2] = %02x\n",buffer[1], buffer[2]); 557 | int ch347_data_length = read_le16(buffer, 1); 558 | if (transferred - 3 < ch347_data_length) { 559 | printf("CH347 returned less data than data length header indicates\n"); 560 | return -1; 561 | } 562 | bytes_read += ch347_data_length; 563 | if (bytes_read > readcnt) { 564 | printf("CH347 returned more bytes than requested\n"); 565 | return -1; 566 | } 567 | memcpy(read_ptr, buffer + 3, ch347_data_length); 568 | read_ptr += ch347_data_length; 569 | } 570 | return 0; 571 | } 572 | 573 | int ch347_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) 574 | { 575 | int ret; 576 | // ch347_cs_control(CH347_CS_ASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE); 577 | if (writecnt) { 578 | ret = ch347_write(writecnt, writearr); 579 | if (ret < 0) { 580 | printf("CH347 write error\n"); 581 | return -1; 582 | } 583 | } 584 | if (readcnt) { 585 | ret = ch347_read(readcnt, readarr); 586 | if (ret < 0) { 587 | printf("CH347 read error\n"); 588 | return -1; 589 | } 590 | } 591 | // ch347_cs_control(CH347_CS_DEASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE); 592 | return 0; 593 | } 594 | 595 | int ch347_spi_shutdown(void) 596 | { 597 | #ifdef _WIN32 598 | if (CH347CloseDevice(ugIndex) == -1){ 599 | printf("Close the CH347 failed.\n"); 600 | }else{ 601 | DevIsOpened = FALSE; 602 | } 603 | #elif defined(__linux__) 604 | if (devHandle == NULL) 605 | return -1; 606 | /* TODO: Set this depending on the mode */ 607 | int spi_interface = MODE_1_IFACE; 608 | libusb_release_interface(devHandle, spi_interface); 609 | libusb_attach_kernel_driver(devHandle, spi_interface); 610 | libusb_close(devHandle); 611 | libusb_exit(NULL); 612 | #endif 613 | return 0; 614 | } 615 | 616 | int ch347_spi_init(void) 617 | { 618 | int open_res = -1; 619 | uint16_t vid = CH347_VID; 620 | uint16_t pid = devs_ch347_spi[0].device_id; 621 | int spispeed = 0x0; //defaulet 60M SPI 622 | int i = 0; 623 | #ifdef _WIN32 624 | if (uhModule == 0) { 625 | #ifdef _WIN64 626 | uhModule = LoadLibrary("CH347DLLA64.DLL"); 627 | #else 628 | uhModule = LoadLibrary("CH347DLL.DLL"); 629 | #endif 630 | if (uhModule) { 631 | CH347OpenDevice = (pCH347OpenDevice)GetProcAddress( 632 | uhModule, "CH347OpenDevice"); 633 | CH347CloseDevice = (pCH347CloseDevice)GetProcAddress( 634 | uhModule, "CH347CloseDevice"); 635 | CH347ReadData = (pCH347ReadData)GetProcAddress( 636 | uhModule, "CH347ReadData"); 637 | CH347WriteData = (pCH347WriteData)GetProcAddress( 638 | uhModule, "CH347WriteData"); 639 | CH347SetTimeout = (pCH347SetTimeout)GetProcAddress( 640 | uhModule, "CH347SetTimeout"); 641 | CH347GetDeviceInfor = (pCH347GetDeviceInfor)GetProcAddress( 642 | uhModule, "CH347GetDeviceInfor"); 643 | if (CH347OpenDevice == NULL || CH347CloseDevice == NULL 644 | || CH347SetTimeout == NULL || CH347ReadData == NULL 645 | || CH347WriteData == NULL || CH347GetDeviceInfor == NULL) { 646 | printf("ch347_spi_init error\n"); 647 | return -1; 648 | } 649 | } 650 | } 651 | for (int i = 0;i < 16; i++){ 652 | if(CH347OpenDevice(i) != -1){ 653 | open_res = 0; 654 | ugIndex = i; 655 | break; 656 | } 657 | } 658 | if (open_res == -1){ 659 | DevIsOpened = FALSE; 660 | printf("Couldn't open CH347 device.\n"); 661 | return -1; 662 | }else { 663 | DevIsOpened = TRUE; 664 | printf("Open CH347 device success.\n"); 665 | } 666 | mDeviceInforS devInfo; 667 | CH347GetDeviceInfor(ugIndex, &devInfo); 668 | char* pidstr = strstr(devInfo.DeviceID, "PID_"); 669 | if (pidstr){ 670 | pidstr += 4; 671 | } 672 | if (strncmp("55DE", pidstr, 4) == 0){ 673 | isCH347F = true; 674 | }else{ 675 | isCH347F = false; 676 | } 677 | #elif defined(__linux__) 678 | int32_t ret = libusb_init(NULL); 679 | if (ret < 0) { 680 | printf("Could not initialize libusb!\n"); 681 | return -1; 682 | } 683 | 684 | /* Enable information, warning, and error messages (only). */ 685 | #if LIBUSB_API_VERSION < 0x01000106 686 | libusb_set_debug(NULL, 3); 687 | #else 688 | libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); 689 | #endif 690 | i = 0; 691 | while (devs_ch347_spi[i].vendor_id != 0) { 692 | pid = devs_ch347_spi[i].device_id; 693 | devHandle = libusb_open_device_with_vid_pid(NULL, vid, pid); 694 | if (devHandle != NULL) { 695 | break; 696 | } 697 | i++; 698 | } 699 | if (devHandle == NULL) { 700 | printf("Couldn't open device %04x:%04x.\n", vid, pid); 701 | return -1; 702 | } 703 | 704 | /* TODO: set based on mode */ 705 | /* Mode 1 uses interface 2 for the SPI interface */ 706 | int spi_interface = MODE_1_IFACE; 707 | 708 | ret = libusb_detach_kernel_driver(devHandle, spi_interface); 709 | if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) 710 | printf("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n", 711 | libusb_error_name(ret)); 712 | 713 | ret = libusb_claim_interface(devHandle, spi_interface); 714 | if (ret != 0) { 715 | printf("Failed to claim interface %d: '%s'\n", MODE_1_IFACE, libusb_error_name(ret)); 716 | goto error_exit; 717 | } 718 | 719 | struct libusb_device *dev; 720 | if (!(dev = libusb_get_device(devHandle))) { 721 | printf("Failed to get device from device handle.\n"); 722 | goto error_exit; 723 | } 724 | 725 | struct libusb_device_descriptor desc; 726 | ret = libusb_get_device_descriptor(dev, &desc); 727 | if (ret < 0) { 728 | printf("Failed to get device descriptor: '%s'\n", libusb_error_name(ret)); 729 | goto error_exit; 730 | } 731 | if (pid == CH347F_PID){ 732 | isCH347F = true; 733 | }else{ 734 | isCH347F = false; 735 | } 736 | printf("Device revision is %d.%01d.%01d\n", 737 | (desc.bcdDevice >> 8) & 0x00FF, 738 | (desc.bcdDevice >> 4) & 0x000F, 739 | (desc.bcdDevice >> 0) & 0x000F); 740 | #endif 741 | /* TODO: add programmer cfg for things like CS pin and divisor */ 742 | if (config_stream(0) < 0) 743 | goto error_exit; 744 | return 0; 745 | error_exit: 746 | ch347_spi_shutdown(); 747 | return -1; 748 | } 749 | /* End of [ch347_spi.c] package */ 750 | --------------------------------------------------------------------------------