diff --git a/patch.sh b/patch.sh index d60e8edc3d7cd19fc009a26992b04335991e324d..07a7575cc52c9c6542adf7b68904a34cb303e424 100644 --- a/patch.sh +++ b/patch.sh @@ -330,7 +330,7 @@ dtb_makefile_append () { } beagleboard_dtbs () { - bbdtbs="v5.3.x" + bbdtbs="v5.4.x" #regenerate="enable" if [ "x${regenerate}" = "xenable" ] ; then cd ../ @@ -382,7 +382,7 @@ local_patch () { } #external_git -aufs +#aufs can_isotp #rt wireguard @@ -424,10 +424,7 @@ patch_backports (){ } backports () { - dir 'drivers/exfat' - # backport_tag="v4.x-y" - backport_tag="619e17cf75dd58905aa67ccd494a6ba5f19d6cc6" subsystem="exfat" #regenerate="enable" @@ -489,10 +486,11 @@ soc () { } ### -backports +#backports #reverts drivers soc +dir 'fixes' packaging () { echo "dir: packaging" diff --git a/patches/WireGuard/0001-merge-WireGuard.patch b/patches/WireGuard/0001-merge-WireGuard.patch index e2df120ab19151dbdbbea397c101a2638d2e819f..8dd7ee4a750a9dc7547f6020de10eb816c617d41 100644 --- a/patches/WireGuard/0001-merge-WireGuard.patch +++ b/patches/WireGuard/0001-merge-WireGuard.patch @@ -1,6 +1,6 @@ -From 18b9299bc240d57dcc401fed6defadf8360f9e82 Mon Sep 17 00:00:00 2001 +From 800183001259bfdfcbe8d69de90cae904cf95b20 Mon Sep 17 00:00:00 2001 From: Robert Nelson <robertcnelson@gmail.com> -Date: Tue, 1 Oct 2019 10:29:04 -0500 +Date: Tue, 1 Oct 2019 11:24:09 -0500 Subject: [PATCH] merge: WireGuard Signed-off-by: Robert Nelson <robertcnelson@gmail.com> @@ -202,7 +202,7 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> create mode 100644 net/wireguard/version.h diff --git a/net/Kconfig b/net/Kconfig -index 57f51a279ad6..6006564bc33b 100644 +index 3101bfcbdd7a..5ecae010f9ec 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -88,6 +88,7 @@ config INET diff --git a/patches/can_isotp/0001-merge-can-isotp-https-github.com-hartkopp-can-isotp.patch b/patches/can_isotp/0001-merge-can-isotp-https-github.com-hartkopp-can-isotp.patch index 2a37fd9173091089bdf5bf5acb91444ca8faee30..5970dff042481fd5952caf86dcafea546165358b 100644 --- a/patches/can_isotp/0001-merge-can-isotp-https-github.com-hartkopp-can-isotp.patch +++ b/patches/can_isotp/0001-merge-can-isotp-https-github.com-hartkopp-can-isotp.patch @@ -1,6 +1,6 @@ -From a776f7edb2a0d58a10e46cb252e73652f83774c2 Mon Sep 17 00:00:00 2001 +From 25d2c346881a073f8018721bcc77abf88863a311 Mon Sep 17 00:00:00 2001 From: Robert Nelson <robertcnelson@gmail.com> -Date: Tue, 1 Oct 2019 10:28:29 -0500 +Date: Tue, 1 Oct 2019 11:24:51 -0500 Subject: [PATCH] merge: can-isotp: https://github.com/hartkopp/can-isotp Signed-off-by: Robert Nelson <robertcnelson@gmail.com> diff --git a/patches/can_isotp/0002-CAN_ISOTP-wire-up-to-kconfig-makefile.patch b/patches/can_isotp/0002-CAN_ISOTP-wire-up-to-kconfig-makefile.patch index 9582a9cb3a53ed5496f84353be2a82dc2da9d41f..1948be8dd7ee701ff2700d270073090f13df6562 100644 --- a/patches/can_isotp/0002-CAN_ISOTP-wire-up-to-kconfig-makefile.patch +++ b/patches/can_isotp/0002-CAN_ISOTP-wire-up-to-kconfig-makefile.patch @@ -10,12 +10,12 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> 2 files changed, 13 insertions(+) diff --git a/net/can/Kconfig b/net/can/Kconfig -index a15c0e0d1fc7..8774a591398b 100644 +index d77042752457..9e2f196f0423 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig -@@ -51,6 +51,16 @@ config CAN_GW - They can be modified with AND/OR/XOR/SET operations as configured - by the netlink configuration interface known e.g. from iptables. +@@ -55,6 +55,16 @@ config CAN_GW + + source "net/can/j1939/Kconfig" +config CAN_ISOTP + tristate "ISO 15765-2:2016 CAN transport protocol" @@ -31,16 +31,17 @@ index a15c0e0d1fc7..8774a591398b 100644 endif diff --git a/net/can/Makefile b/net/can/Makefile -index 1242bbbfe57f..fde676965946 100644 +index 08bd217fc051..cfa1024369cf 100644 --- a/net/can/Makefile +++ b/net/can/Makefile -@@ -15,3 +15,6 @@ can-bcm-y := bcm.o - +@@ -16,4 +16,7 @@ can-bcm-y := bcm.o obj-$(CONFIG_CAN_GW) += can-gw.o can-gw-y := gw.o -+ + +obj-$(CONFIG_CAN_ISOTP) += can-isotp.o +can-isotp-y := isotp.o ++ + obj-$(CONFIG_CAN_J1939) += j1939/ -- -2.20.1 +2.23.0 diff --git a/patches/defconfig b/patches/defconfig index 0d960d24a07b1a6b0d0c986096d02bc4dfde83e1..fd58152a6f1203ae2413c91d3847ffcac99f4f1b 100644 --- a/patches/defconfig +++ b/patches/defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.3.2 Kernel Configuration +# Linux/arm 5.4.0-rc1 Kernel Configuration # # @@ -11,6 +11,7 @@ CONFIG_GCC_VERSION=80300 CONFIG_CLANG_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_EXTABLE_SORT=y @@ -24,7 +25,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_HEADER_TEST is not set CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set -CONFIG_BUILD_SALT="5.3.2-bone9.2" +CONFIG_BUILD_SALT="5.4-rc1-bone0" CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y CONFIG_HAVE_KERNEL_XZ=y @@ -256,19 +257,13 @@ CONFIG_ARCH_MULTIPLATFORM=y # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set -# CONFIG_ARCH_IOP33X is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_DOVE is not set -# CONFIG_ARCH_KS8695 is not set -# CONFIG_ARCH_W90X900 is not set -# CONFIG_ARCH_LPC32XX is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C24XX is not set -# CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP1 is not set # @@ -287,6 +282,7 @@ CONFIG_ARCH_MULTI_V6_V7=y # CONFIG_ARCH_ACTIONS is not set # CONFIG_ARCH_ALPINE is not set # CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set # CONFIG_ARCH_AT91 is not set # CONFIG_ARCH_BCM is not set # CONFIG_ARCH_BERLIN is not set @@ -538,6 +534,7 @@ CONFIG_DT_IDLE_STATES=y # ARM CPU Idle Drivers # CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y # CONFIG_ARM_HIGHBANK_CPUIDLE is not set # end of ARM CPU Idle Drivers # end of CPU Idle @@ -611,6 +608,7 @@ CONFIG_EFI_BOOTLOADER_CONTROL=m CONFIG_EFI_CAPSULE_LOADER=m # CONFIG_EFI_TEST is not set # CONFIG_RESET_ATTACK_MITIGATION is not set +# CONFIG_EFI_RCI2_TABLE is not set # end of EFI (Extensible Firmware Interface) Support # @@ -685,6 +683,7 @@ CONFIG_ARCH_HAS_ELF_RANDOMIZE=y CONFIG_HAVE_ARCH_MMAP_RND_BITS=y CONFIG_HAVE_EXIT_THREAD=y CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y CONFIG_CLONE_BACKWARDS=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_OLD_SIGACTION=y @@ -732,6 +731,8 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_COMPRESS=y # CONFIG_MODULE_COMPRESS_GZIP is not set CONFIG_MODULE_COMPRESS_XZ=y +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_TRIM_UNUSED_KSYMS is not set CONFIG_MODULES_TREE_LOOKUP=y CONFIG_BLOCK=y @@ -745,6 +746,7 @@ CONFIG_BLK_DEV_THROTTLING=y # CONFIG_BLK_CMDLINE_PARSER is not set CONFIG_BLK_WBT=y # CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CGROUP_IOCOST is not set CONFIG_BLK_WBT_MQ=y CONFIG_BLK_DEBUG_FS=y CONFIG_BLK_DEBUG_FS_ZONED=y @@ -1379,7 +1381,6 @@ CONFIG_NET_DSA=m # CONFIG_NET_DSA_TAG_EDSA is not set # CONFIG_NET_DSA_TAG_MTK is not set # CONFIG_NET_DSA_TAG_KSZ is not set -# CONFIG_NET_DSA_TAG_KSZ9477 is not set # CONFIG_NET_DSA_TAG_QCA is not set # CONFIG_NET_DSA_TAG_LAN9303 is not set # CONFIG_NET_DSA_TAG_SJA1105 is not set @@ -1507,6 +1508,7 @@ CONFIG_NET_ACT_TUNNEL_KEY=m CONFIG_NET_IFE_SKBMARK=m CONFIG_NET_IFE_SKBPRIO=m CONFIG_NET_IFE_SKBTCINDEX=m +# CONFIG_NET_TC_SKB_EXT is not set CONFIG_NET_SCH_FIFO=y CONFIG_DCB=y CONFIG_DNS_RESOLVER=y @@ -1549,7 +1551,7 @@ CONFIG_BPF_STREAM_PARSER=y # Network testing # CONFIG_NET_PKTGEN=m -CONFIG_NET_DROP_MONITOR=m +CONFIG_NET_DROP_MONITOR=y # end of Network testing # end of Networking options @@ -1578,6 +1580,7 @@ CONFIG_CAN=y CONFIG_CAN_RAW=m CONFIG_CAN_BCM=m CONFIG_CAN_GW=m +CONFIG_CAN_J1939=m CONFIG_CAN_ISOTP=m # @@ -1818,6 +1821,7 @@ CONFIG_DMA_SHARED_BUFFER=y # Bus devices # # CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_MOXTET is not set CONFIG_OMAP_INTERCONNECT=y # CONFIG_OMAP_OCP2SCP is not set CONFIG_SIMPLE_PM_BUS=y @@ -1834,13 +1838,13 @@ CONFIG_GNSS_SIRF_SERIAL=m CONFIG_GNSS_UBX_SERIAL=m CONFIG_MTD=y # CONFIG_MTD_TESTS is not set -# CONFIG_MTD_CMDLINE_PARTS is not set -CONFIG_MTD_OF_PARTS=m -CONFIG_MTD_AR7_PARTS=m # # Partition parsers # +CONFIG_MTD_AR7_PARTS=m +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_OF_PARTS=m # CONFIG_MTD_AFS_PARTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set # end of Partition parsers @@ -1892,7 +1896,6 @@ CONFIG_MTD_PLATRAM=m CONFIG_MTD_DATAFLASH=m # CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set # CONFIG_MTD_DATAFLASH_OTP is not set -CONFIG_MTD_M25P80=m # CONFIG_MTD_MCHP23K256 is not set CONFIG_MTD_SST25L=m # CONFIG_MTD_SLRAM is not set @@ -1924,6 +1927,7 @@ CONFIG_MTD_NAND_ECC_SW_BCH=y CONFIG_MTD_NAND_OMAP2=m # CONFIG_MTD_NAND_OMAP_BCH is not set # CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_MXIC is not set # CONFIG_MTD_NAND_GPIO is not set # CONFIG_MTD_NAND_PLATFORM is not set @@ -2180,6 +2184,7 @@ CONFIG_DM_CACHE=m CONFIG_DM_CACHE_SMQ=m CONFIG_DM_WRITECACHE=m CONFIG_DM_ERA=m +# CONFIG_DM_CLONE is not set CONFIG_DM_MIRROR=m CONFIG_DM_LOG_USERSPACE=m # CONFIG_DM_RAID is not set @@ -2192,6 +2197,7 @@ CONFIG_DM_DELAY=m CONFIG_DM_UEVENT=y CONFIG_DM_FLAKEY=m CONFIG_DM_VERITY=m +# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set # CONFIG_DM_VERITY_FEC is not set CONFIG_DM_SWITCH=m CONFIG_DM_LOG_WRITES=m @@ -2255,6 +2261,7 @@ CONFIG_ATM_DUMMY=m # CONFIG_NET_DSA_MT7530 is not set # CONFIG_NET_DSA_MV88E6060 is not set # CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set # CONFIG_NET_DSA_MV88E6XXX is not set # CONFIG_NET_DSA_SJA1105 is not set # CONFIG_NET_DSA_QCA8K is not set @@ -2301,6 +2308,7 @@ CONFIG_NET_VENDOR_MICROSEMI=y # CONFIG_NET_VENDOR_NETRONOME is not set # CONFIG_NET_VENDOR_NI is not set # CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PENSANDO is not set # CONFIG_NET_VENDOR_QUALCOMM is not set # CONFIG_NET_VENDOR_RENESAS is not set # CONFIG_NET_VENDOR_ROCKER is not set @@ -2347,6 +2355,7 @@ CONFIG_LED_TRIGGER_PHY=y # MII PHY device drivers # # CONFIG_SFP is not set +# CONFIG_ADIN_PHY is not set # CONFIG_AMD_PHY is not set # CONFIG_AQUANTIA_PHY is not set # CONFIG_AX88796B_PHY is not set @@ -2706,6 +2715,7 @@ CONFIG_JOYSTICK_XPAD_LEDS=y CONFIG_JOYSTICK_PSXPAD_SPI=y CONFIG_JOYSTICK_PSXPAD_SPI_FF=y CONFIG_JOYSTICK_PXRC=m +CONFIG_JOYSTICK_FSIA6B=m CONFIG_INPUT_TABLET=y CONFIG_TABLET_USB_ACECAD=m CONFIG_TABLET_USB_AIPTEK=m @@ -2830,7 +2840,6 @@ CONFIG_INPUT_UINPUT=m # CONFIG_INPUT_ADXL34X is not set # CONFIG_INPUT_IMS_PCU is not set # CONFIG_INPUT_CMA3000 is not set -# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set # CONFIG_INPUT_DRV260X_HAPTICS is not set # CONFIG_INPUT_DRV2665_HAPTICS is not set # CONFIG_INPUT_DRV2667_HAPTICS is not set @@ -2926,6 +2935,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_XILINX_PS_UART is not set # CONFIG_SERIAL_ARC is not set # CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set # CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set # CONFIG_SERIAL_ST_ASC is not set # end of Serial drivers @@ -2958,6 +2968,8 @@ CONFIG_TCG_TIS_I2C_ATMEL=y # CONFIG_XILLYBUS is not set # end of Character devices +CONFIG_RANDOM_TRUST_BOOTLOADER=y + # # I2C support # @@ -3181,6 +3193,7 @@ CONFIG_W1_MASTER_DS2482=m # CONFIG_W1_MASTER_DS1WM is not set CONFIG_W1_MASTER_GPIO=m CONFIG_HDQ_MASTER_OMAP=m +# CONFIG_W1_MASTER_SGI is not set # end of 1-wire Bus Masters # @@ -3199,6 +3212,7 @@ CONFIG_W1_SLAVE_DS2431=m CONFIG_W1_SLAVE_DS2433=m # CONFIG_W1_SLAVE_DS2433_CRC is not set CONFIG_W1_SLAVE_DS2438=m +CONFIG_W1_SLAVE_DS250X=m CONFIG_W1_SLAVE_DS2780=m CONFIG_W1_SLAVE_DS2781=m CONFIG_W1_SLAVE_DS28E04=m @@ -3278,6 +3292,7 @@ CONFIG_SENSORS_ADT7411=m CONFIG_SENSORS_ADT7462=m CONFIG_SENSORS_ADT7470=m CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_AS370=m CONFIG_SENSORS_ASC7621=m CONFIG_SENSORS_ASPEED=m CONFIG_SENSORS_ATXP1=m @@ -3351,6 +3366,7 @@ CONFIG_PMBUS=m CONFIG_SENSORS_PMBUS=m CONFIG_SENSORS_ADM1275=m CONFIG_SENSORS_IBM_CFFPS=m +CONFIG_SENSORS_INSPUR_IPSPS=m CONFIG_SENSORS_IR35221=m CONFIG_SENSORS_IR38064=m CONFIG_SENSORS_IRPS5401=m @@ -3388,7 +3404,6 @@ CONFIG_SENSORS_SCH5636=m CONFIG_SENSORS_STTS751=m CONFIG_SENSORS_SMM665=m CONFIG_SENSORS_ADC128D818=m -CONFIG_SENSORS_ADS1015=m CONFIG_SENSORS_ADS7828=m CONFIG_SENSORS_ADS7871=m CONFIG_SENSORS_AMC6821=m @@ -3499,7 +3514,6 @@ CONFIG_MFD_CORE=y # CONFIG_MFD_BCM590XX is not set # CONFIG_MFD_BD9571MWV is not set # CONFIG_MFD_AXP20X_I2C is not set -# CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_MADERA is not set # CONFIG_MFD_ASIC3 is not set # CONFIG_PMIC_DA903X is not set @@ -3629,6 +3643,7 @@ CONFIG_REGULATOR_PWM=y # CONFIG_REGULATOR_SLG51000 is not set CONFIG_REGULATOR_TI_ABB=y # CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set # CONFIG_REGULATOR_TPS51632 is not set # CONFIG_REGULATOR_TPS62360 is not set # CONFIG_REGULATOR_TPS65023 is not set @@ -3689,6 +3704,7 @@ CONFIG_MEDIA_CONTROLLER_DVB=y CONFIG_VIDEO_DEV=m CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L2_I2C=y # CONFIG_VIDEO_ADV_DEBUG is not set # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set CONFIG_VIDEO_TUNER=m @@ -4030,6 +4046,7 @@ CONFIG_VIDEO_OV2640=m # CONFIG_VIDEO_OV5647 is not set # CONFIG_VIDEO_OV6650 is not set # CONFIG_VIDEO_OV5670 is not set +# CONFIG_VIDEO_OV5675 is not set # CONFIG_VIDEO_OV5695 is not set # CONFIG_VIDEO_OV7251 is not set # CONFIG_VIDEO_OV772X is not set @@ -4333,6 +4350,7 @@ CONFIG_DVB_DUMMY_FE=m # # CONFIG_IMX_IPUV3_CORE is not set CONFIG_DRM=y +CONFIG_DRM_MIPI_DBI=m CONFIG_DRM_MIPI_DSI=y CONFIG_DRM_DP_AUX_CHARDEV=y # CONFIG_DRM_DEBUG_MM is not set @@ -4346,6 +4364,7 @@ CONFIG_DRM_LOAD_EDID_FIRMWARE=y # CONFIG_DRM_DP_CEC is not set CONFIG_DRM_GEM_CMA_HELPER=y CONFIG_DRM_KMS_CMA_HELPER=y +CONFIG_DRM_GEM_SHMEM_HELPER=y # # I2C encoder or helper chips @@ -4396,12 +4415,16 @@ CONFIG_DRM_PANEL_SIMPLE=y # CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set # CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set # CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set # CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set # CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set # CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set # CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set # CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set # CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set # CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set # CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set # CONFIG_DRM_PANEL_RONBO_RB070D30 is not set @@ -4412,9 +4435,13 @@ CONFIG_DRM_PANEL_SIMPLE=y # CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set # CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set # CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set # CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set # CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set # CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set # CONFIG_DRM_PANEL_TPO_TPG110 is not set # CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set # end of Display Panels @@ -4450,8 +4477,7 @@ CONFIG_DRM_I2C_ADV7511_CEC=y # CONFIG_DRM_ETNAVIV is not set # CONFIG_DRM_ARCPGU is not set # CONFIG_DRM_MXSFB is not set -CONFIG_DRM_TINYDRM=m -CONFIG_TINYDRM_MIPI_DBI=m +CONFIG_DRM_GM12U320=m CONFIG_TINYDRM_HX8357D=m CONFIG_TINYDRM_ILI9225=m CONFIG_TINYDRM_ILI9341=m @@ -4771,6 +4797,7 @@ CONFIG_SND_SOC_TLV320AIC3X=m CONFIG_SND_SOC_TS3A227E=m # CONFIG_SND_SOC_TSCS42XX is not set # CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_UDA1334 is not set # CONFIG_SND_SOC_WM8510 is not set # CONFIG_SND_SOC_WM8523 is not set # CONFIG_SND_SOC_WM8524 is not set @@ -4841,6 +4868,7 @@ CONFIG_HID_COUGAR=m CONFIG_HID_PRODIKEYS=m CONFIG_HID_CMEDIA=m CONFIG_HID_CP2112=m +CONFIG_HID_CREATIVE_SB0540=m CONFIG_HID_CYPRESS=m CONFIG_HID_DRAGONRISE=m CONFIG_DRAGONRISE_FF=y @@ -4947,6 +4975,9 @@ CONFIG_I2C_HID=m CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_SUPPORT=y CONFIG_USB_COMMON=y +CONFIG_USB_LED_TRIG=y +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -4963,8 +4994,6 @@ CONFIG_USB_OTG=y CONFIG_USB_LEDS_TRIGGER_USBPORT=m CONFIG_USB_AUTOSUSPEND_DELAY=2 CONFIG_USB_MON=m -CONFIG_USB_WUSB_CBAF=m -# CONFIG_USB_WUSB_CBAF_DEBUG is not set # # USB Host Controller Drivers @@ -4999,21 +5028,21 @@ CONFIG_USB_TMC=m # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set -CONFIG_USB_STORAGE_REALTEK=m +CONFIG_USB_STORAGE_REALTEK=y CONFIG_REALTEK_AUTOPM=y -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_FREECOM=m -CONFIG_USB_STORAGE_ISD200=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_STORAGE_ALAUDA=m -CONFIG_USB_STORAGE_ONETOUCH=m -CONFIG_USB_STORAGE_KARMA=m -CONFIG_USB_STORAGE_CYPRESS_ATACB=m -CONFIG_USB_STORAGE_ENE_UB6250=m -CONFIG_USB_UAS=m +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y +CONFIG_USB_STORAGE_ENE_UB6250=y +CONFIG_USB_UAS=y # # USB Imaging devices @@ -5027,6 +5056,7 @@ CONFIG_USBIP_VHCI_NR_HCS=8 CONFIG_USBIP_HOST=m CONFIG_USBIP_VUDC=m # CONFIG_USBIP_DEBUG is not set +# CONFIG_USB_CDNS3 is not set CONFIG_USB_MUSB_HDRC=y # CONFIG_USB_MUSB_HOST is not set # CONFIG_USB_MUSB_GADGET is not set @@ -5254,9 +5284,6 @@ CONFIG_USB_G_DBGP_SERIAL=y # CONFIG_USB_G_WEBCAM is not set # CONFIG_TYPEC is not set # CONFIG_USB_ROLE_SWITCH is not set -CONFIG_USB_LED_TRIG=y -# CONFIG_USB_ULPI_BUS is not set -# CONFIG_UWB is not set CONFIG_MMC=y CONFIG_PWRSEQ_EMMC=y # CONFIG_PWRSEQ_SD8787 is not set @@ -5404,7 +5431,6 @@ CONFIG_RTC_DRV_PCF8563=y CONFIG_RTC_DRV_PCF8583=y CONFIG_RTC_DRV_M41T80=y CONFIG_RTC_DRV_M41T80_WDT=y -# CONFIG_RTC_DRV_BD70528 is not set CONFIG_RTC_DRV_BQ32K=y CONFIG_RTC_DRV_S35390A=y CONFIG_RTC_DRV_FM3130=m @@ -5519,6 +5545,7 @@ CONFIG_ASYNC_TX_DMA=y CONFIG_SYNC_FILE=y # CONFIG_SW_SYNC is not set # CONFIG_UDMABUF is not set +# CONFIG_DMABUF_SELFTESTS is not set # end of DMABUF options CONFIG_AUXDISPLAY=y @@ -5545,6 +5572,8 @@ CONFIG_VIRTIO_MMIO=m # # end of Microsoft Hyper-V guest support +CONFIG_GREYBUS=m +CONFIG_GREYBUS_ES2=m CONFIG_STAGING=y # CONFIG_PRISM2_USB is not set # CONFIG_COMEDI is not set @@ -5676,8 +5705,6 @@ CONFIG_FB_FLEX=m # CONFIG_WILC1000_SPI is not set # CONFIG_MOST is not set # CONFIG_KS7010 is not set -CONFIG_GREYBUS=m -CONFIG_GREYBUS_ES2=m CONFIG_GREYBUS_AUDIO=m CONFIG_GREYBUS_BOOTROM=m CONFIG_GREYBUS_FIRMWARE=m @@ -5704,8 +5731,10 @@ CONFIG_GREYBUS_USB=m # end of Gasket devices # CONFIG_XIL_AXIS_FIFO is not set -# CONFIG_EROFS_FS is not set # CONFIG_FIELDBUS_DEV is not set +CONFIG_USB_WUSB_CBAF=m +# CONFIG_USB_WUSB_CBAF_DEBUG is not set +# CONFIG_UWB is not set CONFIG_EXFAT_FS=m CONFIG_EXFAT_DONT_MOUNT_VFAT=y CONFIG_EXFAT_DISCARD=y @@ -5715,6 +5744,7 @@ CONFIG_EXFAT_DISCARD=y CONFIG_EXFAT_DEFAULT_CODEPAGE=437 CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" # CONFIG_GOLDFISH is not set +# CONFIG_MFD_CROS_EC is not set # CONFIG_CHROME_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set CONFIG_CLKDEV_LOOKUP=y @@ -5912,7 +5942,6 @@ CONFIG_DMARD06=m CONFIG_DMARD09=m CONFIG_DMARD10=m CONFIG_HID_SENSOR_ACCEL_3D=m -# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set CONFIG_IIO_ST_ACCEL_3AXIS=m CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m @@ -6159,6 +6188,7 @@ CONFIG_SI7020=m # Inertial measurement units # CONFIG_ADIS16400=m +CONFIG_ADIS16460=m CONFIG_ADIS16480=m CONFIG_BMI160=m CONFIG_BMI160_I2C=m @@ -6201,6 +6231,7 @@ CONFIG_LTR501=m CONFIG_LV0104CS=m CONFIG_MAX44000=m CONFIG_MAX44009=m +CONFIG_NOA1305=m CONFIG_OPT3001=m CONFIG_PA12203001=m CONFIG_SI1133=m @@ -6273,6 +6304,7 @@ CONFIG_IIO_SYSFS_TRIGGER=m # CONFIG_AD5272=m CONFIG_DS1803=m +CONFIG_MAX5432=m CONFIG_MAX5481=m CONFIG_MAX5487=m CONFIG_MCP4018=m @@ -6500,6 +6532,9 @@ CONFIG_EXPORTFS_BLOCK_OPS=y CONFIG_FILE_LOCKING=y CONFIG_MANDATORY_FILE_LOCKING=y CONFIG_FS_ENCRYPTION=y +CONFIG_FS_VERITY=y +# CONFIG_FS_VERITY_DEBUG is not set +# CONFIG_FS_VERITY_BUILTIN_SIGNATURES is not set CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY_USER=y @@ -6517,6 +6552,7 @@ CONFIG_AUTOFS4_FS=y CONFIG_AUTOFS_FS=y CONFIG_FUSE_FS=y CONFIG_CUSE=m +# CONFIG_VIRTIO_FS is not set CONFIG_OVERLAY_FS=y # CONFIG_OVERLAY_FS_REDIRECT_DIR is not set CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y @@ -6647,23 +6683,7 @@ CONFIG_ROMFS_ON_MTD=y # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -CONFIG_AUFS_FS=m -CONFIG_AUFS_BRANCH_MAX_127=y -# CONFIG_AUFS_BRANCH_MAX_511 is not set -# CONFIG_AUFS_BRANCH_MAX_1023 is not set -# CONFIG_AUFS_BRANCH_MAX_32767 is not set -CONFIG_AUFS_SBILIST=y -# CONFIG_AUFS_HNOTIFY is not set -CONFIG_AUFS_EXPORT=y -CONFIG_AUFS_XATTR=y -# CONFIG_AUFS_FHSM is not set -# CONFIG_AUFS_RDU is not set -# CONFIG_AUFS_DIRREN is not set -# CONFIG_AUFS_SHWH is not set -# CONFIG_AUFS_BR_RAMFS is not set -# CONFIG_AUFS_BR_FUSE is not set -CONFIG_AUFS_BDEV_LOOP=y -# CONFIG_AUFS_DEBUG is not set +# CONFIG_EROFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y @@ -6693,7 +6713,6 @@ CONFIG_NFSD_BLOCKLAYOUT=y # CONFIG_NFSD_SCSILAYOUT is not set # CONFIG_NFSD_FLEXFILELAYOUT is not set CONFIG_NFSD_V4_SECURITY_LABEL=y -# CONFIG_NFSD_FAULT_INJECTION is not set CONFIG_GRACE_PERIOD=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y @@ -6831,6 +6850,7 @@ CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y # CONFIG_SECURITY_LOADPIN is not set CONFIG_SECURITY_YAMA=y # CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set CONFIG_INTEGRITY=y CONFIG_INTEGRITY_SIGNATURE=y CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y @@ -6914,10 +6934,7 @@ CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_CRYPTO_AEGIS128=m -CONFIG_CRYPTO_AEGIS128L=m -CONFIG_CRYPTO_AEGIS256=m -CONFIG_CRYPTO_MORUS640=m -CONFIG_CRYPTO_MORUS1280=m +CONFIG_CRYPTO_AEGIS128_SIMD=y CONFIG_CRYPTO_SEQIV=y CONFIG_CRYPTO_ECHAINIV=m @@ -6936,6 +6953,7 @@ CONFIG_CRYPTO_XTS=y # CONFIG_CRYPTO_KEYWRAP is not set CONFIG_CRYPTO_NHPOLY1305=m CONFIG_CRYPTO_ADIANTUM=m +CONFIG_CRYPTO_ESSIV=m # # Hash modes @@ -6962,6 +6980,7 @@ CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_RMD256=m CONFIG_CRYPTO_RMD320=m CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_SHA3=m @@ -6973,6 +6992,7 @@ CONFIG_CRYPTO_WP512=m # # Ciphers # +CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_AES_TI is not set CONFIG_CRYPTO_ANUBIS=m @@ -6984,6 +7004,7 @@ CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST_COMMON=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_LIB_DES=y CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m @@ -7032,6 +7053,7 @@ CONFIG_CRYPTO_DEV_ATMEL_I2C=y CONFIG_CRYPTO_DEV_ATMEL_ECC=y CONFIG_CRYPTO_DEV_ATMEL_SHA204A=y CONFIG_CRYPTO_DEV_VIRTIO=m +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set # CONFIG_CRYPTO_DEV_CCREE is not set CONFIG_ASYMMETRIC_KEY_TYPE=y CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y @@ -7147,7 +7169,6 @@ CONFIG_CLZ_TAB=y CONFIG_IRQ_POLL=y CONFIG_MPILIB=y CONFIG_SIGNATURE=y -CONFIG_DIMLIB=y CONFIG_LIBFDT=y CONFIG_OID_REGISTRY=y CONFIG_UCS2_STRING=y @@ -7185,10 +7206,9 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_FRAME_WARN=1024 CONFIG_STRIP_ASM_SYMS=y # CONFIG_READABLE_ASM is not set -# CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_FS=y # CONFIG_HEADERS_INSTALL is not set -# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_OPTIMIZE_INLINING=y # CONFIG_DEBUG_SECTION_MISMATCH is not set CONFIG_SECTION_MISMATCH_WARN_ONLY=y # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set diff --git a/patches/drivers/exfat/0001-staging-exfat-add-exfat-filesystem-code-to-staging.patch b/patches/drivers/exfat/0001-staging-exfat-add-exfat-filesystem-code-to-staging.patch deleted file mode 100644 index 7d01cc501424b8e2aca21994922ed9e3d89d218a..0000000000000000000000000000000000000000 --- a/patches/drivers/exfat/0001-staging-exfat-add-exfat-filesystem-code-to-staging.patch +++ /dev/null @@ -1,11019 +0,0 @@ -From c48c9f7ff32b8b3965a08e40eb6763682d905b5d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Valdis=20Kl=C4=93tnieks?= <valdis.kletnieks@vt.edu> -Date: Wed, 28 Aug 2019 18:08:17 +0200 -Subject: staging: exfat: add exfat filesystem code to staging - -The exfat code needs a lot of work to get it into "real" shape for -the fs/ part of the kernel, so put it into drivers/staging/ for now so -that it can be worked on by everyone in the community. - -The full specification of the filesystem can be found at: - https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification - -Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu> -Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -Link: https://lore.kernel.org/r/20190828160817.6250-1-gregkh@linuxfoundation.org -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - MAINTAINERS | 5 + - drivers/staging/Kconfig | 2 + - drivers/staging/Makefile | 1 + - drivers/staging/exfat/Kconfig | 39 + - drivers/staging/exfat/Makefile | 10 + - drivers/staging/exfat/TODO | 12 + - drivers/staging/exfat/exfat.h | 973 ++++++++ - drivers/staging/exfat/exfat_blkdev.c | 136 ++ - drivers/staging/exfat/exfat_cache.c | 722 ++++++ - drivers/staging/exfat/exfat_core.c | 3704 ++++++++++++++++++++++++++++++ - drivers/staging/exfat/exfat_nls.c | 404 ++++ - drivers/staging/exfat/exfat_super.c | 4137 ++++++++++++++++++++++++++++++++++ - drivers/staging/exfat/exfat_upcase.c | 740 ++++++ - 13 files changed, 10885 insertions(+) - create mode 100644 drivers/staging/exfat/Kconfig - create mode 100644 drivers/staging/exfat/Makefile - create mode 100644 drivers/staging/exfat/TODO - create mode 100644 drivers/staging/exfat/exfat.h - create mode 100644 drivers/staging/exfat/exfat_blkdev.c - create mode 100644 drivers/staging/exfat/exfat_cache.c - create mode 100644 drivers/staging/exfat/exfat_core.c - create mode 100644 drivers/staging/exfat/exfat_nls.c - create mode 100644 drivers/staging/exfat/exfat_super.c - create mode 100644 drivers/staging/exfat/exfat_upcase.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index e3242687cd19..a484b36e5117 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6097,6 +6097,11 @@ F: include/trace/events/mdio.h - F: include/uapi/linux/mdio.h - F: include/uapi/linux/mii.h - -+EXFAT FILE SYSTEM -+M: Valdis Kletnieks <valdis.kletnieks@vt.edu> -+S: Maintained -+F: fs/exfat/ -+ - EXT2 FILE SYSTEM - M: Jan Kara <jack@suse.com> - L: linux-ext4@vger.kernel.org -diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig -index d972ec8e71fb..fbdc33874780 100644 ---- a/drivers/staging/Kconfig -+++ b/drivers/staging/Kconfig -@@ -118,4 +118,6 @@ source "drivers/staging/kpc2000/Kconfig" - - source "drivers/staging/isdn/Kconfig" - -+source "drivers/staging/exfat/Kconfig" -+ - endif # STAGING -diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile -index 6018b9a4a077..ca13f87b1e1b 100644 ---- a/drivers/staging/Makefile -+++ b/drivers/staging/Makefile -@@ -49,3 +49,4 @@ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ - obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ - obj-$(CONFIG_KPC2000) += kpc2000/ - obj-$(CONFIG_ISDN_CAPI) += isdn/ -+obj-$(CONFIG_EXFAT_FS) += exfat/ -diff --git a/drivers/staging/exfat/Kconfig b/drivers/staging/exfat/Kconfig -new file mode 100644 -index 000000000000..78b32aa2ca19 ---- /dev/null -+++ b/drivers/staging/exfat/Kconfig -@@ -0,0 +1,39 @@ -+config EXFAT_FS -+ tristate "exFAT fs support" -+ select NLS -+ help -+ This adds support for the exFAT file system. -+ -+config EXFAT_DISCARD -+ bool "enable discard support" -+ depends on EXFAT_FS -+ default y -+ -+config EXFAT_DELAYED_SYNC -+ bool "enable delayed sync" -+ depends on EXFAT_FS -+ default n -+ -+config EXFAT_KERNEL_DEBUG -+ bool "enable kernel debug features via ioctl" -+ depends on EXFAT_FS -+ default n -+ -+config EXFAT_DEBUG_MSG -+ bool "print debug messages" -+ depends on EXFAT_FS -+ default n -+ -+config EXFAT_DEFAULT_CODEPAGE -+ int "Default codepage for exFAT" -+ default 437 -+ depends on EXFAT_FS -+ help -+ This option should be set to the codepage of your exFAT filesystems. -+ -+config EXFAT_DEFAULT_IOCHARSET -+ string "Default iocharset for exFAT" -+ default "utf8" -+ depends on EXFAT_FS -+ help -+ Set this to the default input/output character set you'd like exFAT to use. -diff --git a/drivers/staging/exfat/Makefile b/drivers/staging/exfat/Makefile -new file mode 100644 -index 000000000000..84944dfbae28 ---- /dev/null -+++ b/drivers/staging/exfat/Makefile -@@ -0,0 +1,10 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+obj-$(CONFIG_EXFAT_FS) += exfat.o -+ -+exfat-y := exfat_core.o \ -+ exfat_super.o \ -+ exfat_blkdev.o \ -+ exfat_cache.o \ -+ exfat_nls.o \ -+ exfat_upcase.o -diff --git a/drivers/staging/exfat/TODO b/drivers/staging/exfat/TODO -new file mode 100644 -index 000000000000..a3eb282f9efc ---- /dev/null -+++ b/drivers/staging/exfat/TODO -@@ -0,0 +1,12 @@ -+exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse(). -+same for ffsWriteFile. -+ -+exfat_core.c - fs_sync(sb,0) all over the place looks fishy as hell. -+There's only one place that calls it with a non-zero argument. -+ -+ffsTruncateFile - if (old_size <= new_size) { -+That doesn't look right. How did it ever work? Are they relying on lazy -+block allocation when actual writes happen? If nothing else, it never -+does the 'fid->size = new_size' and do the inode update.... -+ -+ffsSetAttr() is just dangling in the breeze, not wired up at all... -diff --git a/drivers/staging/exfat/exfat.h b/drivers/staging/exfat/exfat.h -new file mode 100644 -index 000000000000..bae180e10609 ---- /dev/null -+++ b/drivers/staging/exfat/exfat.h -@@ -0,0 +1,973 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#ifndef _EXFAT_H -+#define _EXFAT_H -+ -+#include <linux/types.h> -+#include <linux/buffer_head.h> -+ -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ /* For Debugging Purpose */ -+ /* IOCTL code 'f' used by -+ * - file systems typically #0~0x1F -+ * - embedded terminal devices #128~ -+ * - exts for debugging purpose #99 -+ * number 100 and 101 is available now but has possible conflicts -+ */ -+#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) -+#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) -+ -+#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 -+#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+#ifdef CONFIG_EXFAT_DEBUG_MSG -+#define DEBUG 1 -+#else -+#undef DEBUG -+#endif -+ -+#define DENTRY_SIZE 32 /* dir entry size */ -+#define DENTRY_SIZE_BITS 5 -+ -+/* PBR entries */ -+#define PBR_SIGNATURE 0xAA55 -+#define EXT_SIGNATURE 0xAA550000 -+#define VOL_LABEL "NO NAME " /* size should be 11 */ -+#define OEM_NAME "MSWIN4.1" /* size should be 8 */ -+#define STR_FAT12 "FAT12 " /* size should be 8 */ -+#define STR_FAT16 "FAT16 " /* size should be 8 */ -+#define STR_FAT32 "FAT32 " /* size should be 8 */ -+#define STR_EXFAT "EXFAT " /* size should be 8 */ -+#define VOL_CLEAN 0x0000 -+#define VOL_DIRTY 0x0002 -+ -+/* max number of clusters */ -+#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ -+#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ -+#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ -+#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ -+ -+/* file types */ -+#define TYPE_UNUSED 0x0000 -+#define TYPE_DELETED 0x0001 -+#define TYPE_INVALID 0x0002 -+#define TYPE_CRITICAL_PRI 0x0100 -+#define TYPE_BITMAP 0x0101 -+#define TYPE_UPCASE 0x0102 -+#define TYPE_VOLUME 0x0103 -+#define TYPE_DIR 0x0104 -+#define TYPE_FILE 0x011F -+#define TYPE_SYMLINK 0x015F -+#define TYPE_CRITICAL_SEC 0x0200 -+#define TYPE_STREAM 0x0201 -+#define TYPE_EXTEND 0x0202 -+#define TYPE_ACL 0x0203 -+#define TYPE_BENIGN_PRI 0x0400 -+#define TYPE_GUID 0x0401 -+#define TYPE_PADDING 0x0402 -+#define TYPE_ACLTAB 0x0403 -+#define TYPE_BENIGN_SEC 0x0800 -+#define TYPE_ALL 0x0FFF -+ -+/* time modes */ -+#define TM_CREATE 0 -+#define TM_MODIFY 1 -+#define TM_ACCESS 2 -+ -+/* checksum types */ -+#define CS_DIR_ENTRY 0 -+#define CS_PBR_SECTOR 1 -+#define CS_DEFAULT 2 -+ -+#define CLUSTER_16(x) ((u16)(x)) -+#define CLUSTER_32(x) ((u32)(x)) -+ -+#define FALSE 0 -+#define TRUE 1 -+ -+#define START_SECTOR(x) \ -+ ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + \ -+ p_fs->data_start_sector) -+ -+#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ -+ ((((sec) - p_fs->data_start_sector + 1) & \ -+ ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) -+ -+#define GET_CLUSTER_FROM_SECTOR(sec) \ -+ ((u32)((((sec) - p_fs->data_start_sector) >> \ -+ p_fs->sectors_per_clu_bits) + 2)) -+ -+#define GET16(p_src) \ -+ (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) -+#define GET32(p_src) \ -+ (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ -+ (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) -+#define GET64(p_src) \ -+ (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ -+ (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ -+ (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ -+ (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) -+ -+#define SET16(p_dst, src) \ -+ do { \ -+ (p_dst)[0] = (u8)(src); \ -+ (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ -+ } while (0) -+#define SET32(p_dst, src) \ -+ do { \ -+ (p_dst)[0] = (u8)(src); \ -+ (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ -+ (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ -+ (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ -+ } while (0) -+#define SET64(p_dst, src) \ -+ do { \ -+ (p_dst)[0] = (u8)(src); \ -+ (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ -+ (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ -+ (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ -+ (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ -+ (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ -+ (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ -+ (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ -+ } while (0) -+ -+#ifdef __LITTLE_ENDIAN -+#define GET16_A(p_src) (*((u16 *)(p_src))) -+#define GET32_A(p_src) (*((u32 *)(p_src))) -+#define GET64_A(p_src) (*((u64 *)(p_src))) -+#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) -+#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) -+#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) -+#else /* BIG_ENDIAN */ -+#define GET16_A(p_src) GET16(p_src) -+#define GET32_A(p_src) GET32(p_src) -+#define GET64_A(p_src) GET64(p_src) -+#define SET16_A(p_dst, src) SET16(p_dst, src) -+#define SET32_A(p_dst, src) SET32(p_dst, src) -+#define SET64_A(p_dst, src) SET64(p_dst, src) -+#endif -+ -+/* cache size (in number of sectors) */ -+/* (should be an exponential value of 2) */ -+#define FAT_CACHE_SIZE 128 -+#define FAT_CACHE_HASH_SIZE 64 -+#define BUF_CACHE_SIZE 256 -+#define BUF_CACHE_HASH_SIZE 64 -+ -+/* Upcase table macro */ -+#define HIGH_INDEX_BIT (8) -+#define HIGH_INDEX_MASK (0xFF00) -+#define LOW_INDEX_BIT (16-HIGH_INDEX_BIT) -+#define UTBL_ROW_COUNT (1<<LOW_INDEX_BIT) -+#define UTBL_COL_COUNT (1<<HIGH_INDEX_BIT) -+ -+static inline u16 get_col_index(u16 i) -+{ -+ return i >> LOW_INDEX_BIT; -+} -+static inline u16 get_row_index(u16 i) -+{ -+ return i & ~HIGH_INDEX_MASK; -+} -+ -+#define EXFAT_SUPER_MAGIC (0x2011BAB0L) -+#define EXFAT_ROOT_INO 1 -+ -+/* FAT types */ -+#define FAT12 0x01 /* FAT12 */ -+#define FAT16 0x0E /* Win95 FAT16 (LBA) */ -+#define FAT32 0x0C /* Win95 FAT32 (LBA) */ -+#define EXFAT 0x07 /* exFAT */ -+ -+/* file name lengths */ -+#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ -+#define MAX_PATH_DEPTH 15 /* max depth of path name */ -+#define MAX_NAME_LENGTH 256 /* max len of filename including NULL */ -+#define MAX_PATH_LENGTH 260 /* max len of pathname including NULL */ -+#define DOS_NAME_LENGTH 11 /* DOS filename length excluding NULL */ -+#define DOS_PATH_LENGTH 80 /* DOS pathname length excluding NULL */ -+ -+/* file attributes */ -+#define ATTR_NORMAL 0x0000 -+#define ATTR_READONLY 0x0001 -+#define ATTR_HIDDEN 0x0002 -+#define ATTR_SYSTEM 0x0004 -+#define ATTR_VOLUME 0x0008 -+#define ATTR_SUBDIR 0x0010 -+#define ATTR_ARCHIVE 0x0020 -+#define ATTR_SYMLINK 0x0040 -+#define ATTR_EXTEND 0x000F -+#define ATTR_RWMASK 0x007E -+ -+/* file creation modes */ -+#define FM_REGULAR 0x00 -+#define FM_SYMLINK 0x40 -+ -+/* return values */ -+#define FFS_SUCCESS 0 -+#define FFS_MEDIAERR 1 -+#define FFS_FORMATERR 2 -+#define FFS_MOUNTED 3 -+#define FFS_NOTMOUNTED 4 -+#define FFS_ALIGNMENTERR 5 -+#define FFS_SEMAPHOREERR 6 -+#define FFS_INVALIDPATH 7 -+#define FFS_INVALIDFID 8 -+#define FFS_NOTFOUND 9 -+#define FFS_FILEEXIST 10 -+#define FFS_PERMISSIONERR 11 -+#define FFS_NOTOPENED 12 -+#define FFS_MAXOPENED 13 -+#define FFS_FULL 14 -+#define FFS_EOF 15 -+#define FFS_DIRBUSY 16 -+#define FFS_MEMORYERR 17 -+#define FFS_NAMETOOLONG 18 -+#define FFS_ERROR 19 -+ -+#define NUM_UPCASE 2918 -+ -+#define DOS_CUR_DIR_NAME ". " -+#define DOS_PAR_DIR_NAME ".. " -+ -+#ifdef __LITTLE_ENDIAN -+#define UNI_CUR_DIR_NAME ".\0" -+#define UNI_PAR_DIR_NAME ".\0.\0" -+#else -+#define UNI_CUR_DIR_NAME "\0." -+#define UNI_PAR_DIR_NAME "\0.\0." -+#endif -+ -+struct date_time_t { -+ u16 Year; -+ u16 Month; -+ u16 Day; -+ u16 Hour; -+ u16 Minute; -+ u16 Second; -+ u16 MilliSecond; -+}; -+ -+struct part_info_t { -+ u32 Offset; /* start sector number of the partition */ -+ u32 Size; /* in sectors */ -+}; -+ -+struct dev_info_t { -+ u32 SecSize; /* sector size in bytes */ -+ u32 DevSize; /* block device size in sectors */ -+}; -+ -+struct vol_info_t { -+ u32 FatType; -+ u32 ClusterSize; -+ u32 NumClusters; -+ u32 FreeClusters; -+ u32 UsedClusters; -+}; -+ -+/* directory structure */ -+struct chain_t { -+ u32 dir; -+ s32 size; -+ u8 flags; -+}; -+ -+struct file_id_t { -+ struct chain_t dir; -+ s32 entry; -+ u32 type; -+ u32 attr; -+ u32 start_clu; -+ u64 size; -+ u8 flags; -+ s64 rwoffset; -+ s32 hint_last_off; -+ u32 hint_last_clu; -+}; -+ -+struct dir_entry_t { -+ char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; -+ -+ /* used only for FAT12/16/32, not used for exFAT */ -+ char ShortName[DOS_NAME_LENGTH + 2]; -+ -+ u32 Attr; -+ u64 Size; -+ u32 NumSubdirs; -+ struct date_time_t CreateTimestamp; -+ struct date_time_t ModifyTimestamp; -+ struct date_time_t AccessTimestamp; -+}; -+ -+struct timestamp_t { -+ u16 sec; /* 0 ~ 59 */ -+ u16 min; /* 0 ~ 59 */ -+ u16 hour; /* 0 ~ 23 */ -+ u16 day; /* 1 ~ 31 */ -+ u16 mon; /* 1 ~ 12 */ -+ u16 year; /* 0 ~ 127 (since 1980) */ -+}; -+ -+/* MS_DOS FAT partition boot record (512 bytes) */ -+struct pbr_sector_t { -+ u8 jmp_boot[3]; -+ u8 oem_name[8]; -+ u8 bpb[109]; -+ u8 boot_code[390]; -+ u8 signature[2]; -+}; -+ -+/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ -+struct bpb16_t { -+ u8 sector_size[2]; -+ u8 sectors_per_clu; -+ u8 num_reserved[2]; -+ u8 num_fats; -+ u8 num_root_entries[2]; -+ u8 num_sectors[2]; -+ u8 media_type; -+ u8 num_fat_sectors[2]; -+ u8 sectors_in_track[2]; -+ u8 num_heads[2]; -+ u8 num_hid_sectors[4]; -+ u8 num_huge_sectors[4]; -+ -+ u8 phy_drv_no; -+ u8 reserved; -+ u8 ext_signature; -+ u8 vol_serial[4]; -+ u8 vol_label[11]; -+ u8 vol_type[8]; -+}; -+ -+/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ -+struct bpb32_t { -+ u8 sector_size[2]; -+ u8 sectors_per_clu; -+ u8 num_reserved[2]; -+ u8 num_fats; -+ u8 num_root_entries[2]; -+ u8 num_sectors[2]; -+ u8 media_type; -+ u8 num_fat_sectors[2]; -+ u8 sectors_in_track[2]; -+ u8 num_heads[2]; -+ u8 num_hid_sectors[4]; -+ u8 num_huge_sectors[4]; -+ u8 num_fat32_sectors[4]; -+ u8 ext_flags[2]; -+ u8 fs_version[2]; -+ u8 root_cluster[4]; -+ u8 fsinfo_sector[2]; -+ u8 backup_sector[2]; -+ u8 reserved[12]; -+ -+ u8 phy_drv_no; -+ u8 ext_reserved; -+ u8 ext_signature; -+ u8 vol_serial[4]; -+ u8 vol_label[11]; -+ u8 vol_type[8]; -+}; -+ -+/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ -+struct bpbex_t { -+ u8 reserved1[53]; -+ u8 vol_offset[8]; -+ u8 vol_length[8]; -+ u8 fat_offset[4]; -+ u8 fat_length[4]; -+ u8 clu_offset[4]; -+ u8 clu_count[4]; -+ u8 root_cluster[4]; -+ u8 vol_serial[4]; -+ u8 fs_version[2]; -+ u8 vol_flags[2]; -+ u8 sector_size_bits; -+ u8 sectors_per_clu_bits; -+ u8 num_fats; -+ u8 phy_drv_no; -+ u8 perc_in_use; -+ u8 reserved2[7]; -+}; -+ -+/* MS-DOS FAT file system information sector (512 bytes) */ -+struct fsi_sector_t { -+ u8 signature1[4]; -+ u8 reserved1[480]; -+ u8 signature2[4]; -+ u8 free_cluster[4]; -+ u8 next_cluster[4]; -+ u8 reserved2[14]; -+ u8 signature3[2]; -+}; -+ -+/* MS-DOS FAT directory entry (32 bytes) */ -+struct dentry_t { -+ u8 dummy[32]; -+}; -+ -+struct dos_dentry_t { -+ u8 name[DOS_NAME_LENGTH]; -+ u8 attr; -+ u8 lcase; -+ u8 create_time_ms; -+ u8 create_time[2]; -+ u8 create_date[2]; -+ u8 access_date[2]; -+ u8 start_clu_hi[2]; -+ u8 modify_time[2]; -+ u8 modify_date[2]; -+ u8 start_clu_lo[2]; -+ u8 size[4]; -+}; -+ -+/* MS-DOS FAT extended directory entry (32 bytes) */ -+struct ext_dentry_t { -+ u8 order; -+ u8 unicode_0_4[10]; -+ u8 attr; -+ u8 sysid; -+ u8 checksum; -+ u8 unicode_5_10[12]; -+ u8 start_clu[2]; -+ u8 unicode_11_12[4]; -+}; -+ -+/* MS-DOS EXFAT file directory entry (32 bytes) */ -+struct file_dentry_t { -+ u8 type; -+ u8 num_ext; -+ u8 checksum[2]; -+ u8 attr[2]; -+ u8 reserved1[2]; -+ u8 create_time[2]; -+ u8 create_date[2]; -+ u8 modify_time[2]; -+ u8 modify_date[2]; -+ u8 access_time[2]; -+ u8 access_date[2]; -+ u8 create_time_ms; -+ u8 modify_time_ms; -+ u8 access_time_ms; -+ u8 reserved2[9]; -+}; -+ -+/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ -+struct strm_dentry_t { -+ u8 type; -+ u8 flags; -+ u8 reserved1; -+ u8 name_len; -+ u8 name_hash[2]; -+ u8 reserved2[2]; -+ u8 valid_size[8]; -+ u8 reserved3[4]; -+ u8 start_clu[4]; -+ u8 size[8]; -+}; -+ -+/* MS-DOS EXFAT file name directory entry (32 bytes) */ -+struct name_dentry_t { -+ u8 type; -+ u8 flags; -+ u8 unicode_0_14[30]; -+}; -+ -+/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ -+struct bmap_dentry_t { -+ u8 type; -+ u8 flags; -+ u8 reserved[18]; -+ u8 start_clu[4]; -+ u8 size[8]; -+}; -+ -+/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ -+struct case_dentry_t { -+ u8 type; -+ u8 reserved1[3]; -+ u8 checksum[4]; -+ u8 reserved2[12]; -+ u8 start_clu[4]; -+ u8 size[8]; -+}; -+ -+/* MS-DOS EXFAT volume label directory entry (32 bytes) */ -+struct volm_dentry_t { -+ u8 type; -+ u8 label_len; -+ u8 unicode_0_10[22]; -+ u8 reserved[8]; -+}; -+ -+/* unused entry hint information */ -+struct uentry_t { -+ u32 dir; -+ s32 entry; -+ struct chain_t clu; -+}; -+ -+/* DOS name structure */ -+struct dos_name_t { -+ u8 name[DOS_NAME_LENGTH]; -+ u8 name_case; -+}; -+ -+/* unicode name structure */ -+struct uni_name_t { -+ u16 name[MAX_NAME_LENGTH]; -+ u16 name_hash; -+ u8 name_len; -+}; -+ -+struct buf_cache_t { -+ struct buf_cache_t *next; -+ struct buf_cache_t *prev; -+ struct buf_cache_t *hash_next; -+ struct buf_cache_t *hash_prev; -+ s32 drv; -+ sector_t sec; -+ u32 flag; -+ struct buffer_head *buf_bh; -+}; -+ -+struct fs_func { -+ s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, -+ struct chain_t *p_chain); -+ void (*free_cluster)(struct super_block *sb, struct chain_t *p_chain, -+ s32 do_relse); -+ s32 (*count_used_clusters)(struct super_block *sb); -+ -+ s32 (*init_dir_entry)(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, u32 type, u32 start_clu, u64 size); -+ s32 (*init_ext_entry)(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 num_entries, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname); -+ s32 (*find_dir_entry)(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 num_entries, -+ struct dos_name_t *p_dosname, u32 type); -+ void (*delete_dir_entry)(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ s32 offset, s32 num_entries); -+ void (*get_uni_name_from_ext_entry)(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u16 *uniname); -+ s32 (*count_ext_entries)(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ struct dentry_t *p_entry); -+ s32 (*calc_num_entries)(struct uni_name_t *p_uniname); -+ -+ u32 (*get_entry_type)(struct dentry_t *p_entry); -+ void (*set_entry_type)(struct dentry_t *p_entry, u32 type); -+ u32 (*get_entry_attr)(struct dentry_t *p_entry); -+ void (*set_entry_attr)(struct dentry_t *p_entry, u32 attr); -+ u8 (*get_entry_flag)(struct dentry_t *p_entry); -+ void (*set_entry_flag)(struct dentry_t *p_entry, u8 flag); -+ u32 (*get_entry_clu0)(struct dentry_t *p_entry); -+ void (*set_entry_clu0)(struct dentry_t *p_entry, u32 clu0); -+ u64 (*get_entry_size)(struct dentry_t *p_entry); -+ void (*set_entry_size)(struct dentry_t *p_entry, u64 size); -+ void (*get_entry_time)(struct dentry_t *p_entry, -+ struct timestamp_t *tp, u8 mode); -+ void (*set_entry_time)(struct dentry_t *p_entry, -+ struct timestamp_t *tp, u8 mode); -+}; -+ -+struct fs_info_t { -+ u32 drv; /* drive ID */ -+ u32 vol_type; /* volume FAT type */ -+ u32 vol_id; /* volume serial number */ -+ -+ u64 num_sectors; /* num of sectors in volume */ -+ u32 num_clusters; /* num of clusters in volume */ -+ u32 cluster_size; /* cluster size in bytes */ -+ u32 cluster_size_bits; -+ u32 sectors_per_clu; /* cluster size in sectors */ -+ u32 sectors_per_clu_bits; -+ -+ u32 PBR_sector; /* PBR sector */ -+ u32 FAT1_start_sector; /* FAT1 start sector */ -+ u32 FAT2_start_sector; /* FAT2 start sector */ -+ u32 root_start_sector; /* root dir start sector */ -+ u32 data_start_sector; /* data area start sector */ -+ u32 num_FAT_sectors; /* num of FAT sectors */ -+ -+ u32 root_dir; /* root dir cluster */ -+ u32 dentries_in_root; /* num of dentries in root dir */ -+ u32 dentries_per_clu; /* num of dentries per cluster */ -+ -+ u32 vol_flag; /* volume dirty flag */ -+ struct buffer_head *pbr_bh; /* PBR sector */ -+ -+ u32 map_clu; /* allocation bitmap start cluster */ -+ u32 map_sectors; /* num of allocation bitmap sectors */ -+ struct buffer_head **vol_amap; /* allocation bitmap */ -+ -+ u16 **vol_utbl; /* upcase table */ -+ -+ u32 clu_srch_ptr; /* cluster search pointer */ -+ u32 used_clusters; /* number of used clusters */ -+ struct uentry_t hint_uentry; /* unused entry hint information */ -+ -+ u32 dev_ejected; /* block device operation error flag */ -+ -+ struct fs_func *fs_func; -+ struct semaphore v_sem; -+ -+ /* FAT cache */ -+ struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE]; -+ struct buf_cache_t FAT_cache_lru_list; -+ struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; -+ -+ /* buf cache */ -+ struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE]; -+ struct buf_cache_t buf_cache_lru_list; -+ struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; -+}; -+ -+#define ES_2_ENTRIES 2 -+#define ES_3_ENTRIES 3 -+#define ES_ALL_ENTRIES 0 -+ -+struct entry_set_cache_t { -+ /* sector number that contains file_entry */ -+ sector_t sector; -+ -+ /* byte offset in the sector */ -+ s32 offset; -+ -+ /* -+ * flag in stream entry. -+ * 01 for cluster chain, -+ * 03 for contig. clusteres. -+ */ -+ s32 alloc_flag; -+ -+ u32 num_entries; -+ -+ /* __buf should be the last member */ -+ void *__buf; -+}; -+ -+#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ -+#define EXFAT_ERRORS_PANIC 2 /* panic on error */ -+#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ -+ -+/* ioctl command */ -+#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) -+ -+struct exfat_mount_options { -+ kuid_t fs_uid; -+ kgid_t fs_gid; -+ unsigned short fs_fmask; -+ unsigned short fs_dmask; -+ -+ /* permission for setting the [am]time */ -+ unsigned short allow_utime; -+ -+ /* codepage for shortname conversions */ -+ unsigned short codepage; -+ -+ /* charset for filename input/display */ -+ char *iocharset; -+ -+ unsigned char casesensitive; -+ -+ /* on error: continue, panic, remount-ro */ -+ unsigned char errors; -+#ifdef CONFIG_EXFAT_DISCARD -+ /* flag on if -o dicard specified and device support discard() */ -+ unsigned char discard; -+#endif /* CONFIG_EXFAT_DISCARD */ -+}; -+ -+#define EXFAT_HASH_BITS 8 -+#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) -+ -+/* -+ * EXFAT file system in-core superblock data -+ */ -+struct bd_info_t { -+ s32 sector_size; /* in bytes */ -+ s32 sector_size_bits; -+ s32 sector_size_mask; -+ -+ /* total number of sectors in this block device */ -+ s32 num_sectors; -+ -+ /* opened or not */ -+ bool opened; -+}; -+ -+struct exfat_sb_info { -+ struct fs_info_t fs_info; -+ struct bd_info_t bd_info; -+ -+ struct exfat_mount_options options; -+ -+ int s_dirt; -+ struct mutex s_lock; -+ struct nls_table *nls_disk; /* Codepage used on disk */ -+ struct nls_table *nls_io; /* Charset used for input and display */ -+ -+ struct inode *fat_inode; -+ -+ spinlock_t inode_hash_lock; -+ struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ long debug_flags; -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+}; -+ -+/* -+ * EXFAT file system inode data in memory -+ */ -+struct exfat_inode_info { -+ struct file_id_t fid; -+ char *target; -+ /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ -+ loff_t mmu_private; /* physically allocated size */ -+ loff_t i_pos; /* on-disk position of directory entry or 0 */ -+ struct hlist_node i_hash_fat; /* hash by i_location */ -+ struct rw_semaphore truncate_lock; -+ struct inode vfs_inode; -+ struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ -+}; -+ -+#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) -+ -+static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) -+{ -+ return container_of(inode, struct exfat_inode_info, vfs_inode); -+} -+ -+/* NLS management function */ -+u16 nls_upper(struct super_block *sb, u16 a); -+int nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b); -+int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); -+void nls_uniname_to_dosname(struct super_block *sb, -+ struct dos_name_t *p_dosname, -+ struct uni_name_t *p_uniname, bool *p_lossy); -+void nls_dosname_to_uniname(struct super_block *sb, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname); -+void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -+ struct uni_name_t *p_uniname); -+void nls_cstring_to_uniname(struct super_block *sb, -+ struct uni_name_t *p_uniname, u8 *p_cstring, -+ bool *p_lossy); -+ -+/* buffer cache management */ -+void buf_init(struct super_block *sb); -+void buf_shutdown(struct super_block *sb); -+int FAT_read(struct super_block *sb, u32 loc, u32 *content); -+s32 FAT_write(struct super_block *sb, u32 loc, u32 content); -+u8 *FAT_getblk(struct super_block *sb, sector_t sec); -+void FAT_modify(struct super_block *sb, sector_t sec); -+void FAT_release_all(struct super_block *sb); -+void FAT_sync(struct super_block *sb); -+u8 *buf_getblk(struct super_block *sb, sector_t sec); -+void buf_modify(struct super_block *sb, sector_t sec); -+void buf_lock(struct super_block *sb, sector_t sec); -+void buf_unlock(struct super_block *sb, sector_t sec); -+void buf_release(struct super_block *sb, sector_t sec); -+void buf_release_all(struct super_block *sb); -+void buf_sync(struct super_block *sb); -+ -+/* fs management functions */ -+void fs_set_vol_flags(struct super_block *sb, u32 new_flag); -+void fs_error(struct super_block *sb); -+ -+/* cluster management functions */ -+s32 clear_cluster(struct super_block *sb, u32 clu); -+s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, -+ struct chain_t *p_chain); -+s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -+ struct chain_t *p_chain); -+void fat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -+ s32 do_relse); -+void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -+ s32 do_relse); -+u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain); -+s32 count_num_clusters(struct super_block *sb, struct chain_t *dir); -+s32 fat_count_used_clusters(struct super_block *sb); -+s32 exfat_count_used_clusters(struct super_block *sb); -+void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); -+ -+/* allocation bitmap management functions */ -+s32 load_alloc_bitmap(struct super_block *sb); -+void free_alloc_bitmap(struct super_block *sb); -+s32 set_alloc_bitmap(struct super_block *sb, u32 clu); -+s32 clr_alloc_bitmap(struct super_block *sb, u32 clu); -+u32 test_alloc_bitmap(struct super_block *sb, u32 clu); -+void sync_alloc_bitmap(struct super_block *sb); -+ -+/* upcase table management functions */ -+s32 load_upcase_table(struct super_block *sb); -+void free_upcase_table(struct super_block *sb); -+ -+/* dir entry management functions */ -+u32 fat_get_entry_type(struct dentry_t *p_entry); -+u32 exfat_get_entry_type(struct dentry_t *p_entry); -+void fat_set_entry_type(struct dentry_t *p_entry, u32 type); -+void exfat_set_entry_type(struct dentry_t *p_entry, u32 type); -+u32 fat_get_entry_attr(struct dentry_t *p_entry); -+u32 exfat_get_entry_attr(struct dentry_t *p_entry); -+void fat_set_entry_attr(struct dentry_t *p_entry, u32 attr); -+void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr); -+u8 fat_get_entry_flag(struct dentry_t *p_entry); -+u8 exfat_get_entry_flag(struct dentry_t *p_entry); -+void fat_set_entry_flag(struct dentry_t *p_entry, u8 flag); -+void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flag); -+u32 fat_get_entry_clu0(struct dentry_t *p_entry); -+u32 exfat_get_entry_clu0(struct dentry_t *p_entry); -+void fat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); -+void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); -+u64 fat_get_entry_size(struct dentry_t *p_entry); -+u64 exfat_get_entry_size(struct dentry_t *p_entry); -+void fat_set_entry_size(struct dentry_t *p_entry, u64 size); -+void exfat_set_entry_size(struct dentry_t *p_entry, u64 size); -+struct timestamp_t *tm_current(struct timestamp_t *tm); -+void fat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode); -+void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode); -+void fat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode); -+void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode); -+s32 fat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, s32 entry, -+ u32 type, u32 start_clu, u64 size); -+s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, u32 type, u32 start_clu, u64 size); -+s32 fat_init_ext_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 num_entries, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname); -+s32 exfat_init_ext_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 num_entries, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname); -+void init_dos_entry(struct dos_dentry_t *ep, u32 type, u32 start_clu); -+void init_ext_entry(struct ext_dentry_t *ep, s32 order, u8 chksum, -+ u16 *uniname); -+void init_file_entry(struct file_dentry_t *ep, u32 type); -+void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, -+ u64 size); -+void init_name_entry(struct name_dentry_t *ep, u16 *uniname); -+void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 order, s32 num_entries); -+void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 order, s32 num_entries); -+ -+s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, -+ sector_t *sector, s32 *offset); -+struct dentry_t *get_entry_with_sector(struct super_block *sb, sector_t sector, -+ s32 offset); -+struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, sector_t *sector); -+struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u32 type, -+ struct dentry_t **file_ep); -+void release_entry_set(struct entry_set_cache_t *es); -+s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es); -+s32 write_partial_entries_in_entry_set(struct super_block *sb, -+ struct entry_set_cache_t *es, -+ struct dentry_t *ep, u32 count); -+s32 search_deleted_or_unused_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 num_entries); -+s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, -+ s32 num_entries); -+s32 fat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 num_entries, -+ struct dos_name_t *p_dosname, u32 type); -+s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 num_entries, -+ struct dos_name_t *p_dosname, u32 type); -+s32 fat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, struct dentry_t *p_entry); -+s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, struct dentry_t *p_entry); -+s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -+ u32 type); -+void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry); -+void update_dir_checksum_with_entry_set(struct super_block *sb, -+ struct entry_set_cache_t *es); -+bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir); -+ -+/* name conversion functions */ -+s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 *entries, -+ struct dos_name_t *p_dosname); -+void get_uni_name_from_dos_entry(struct super_block *sb, -+ struct dos_dentry_t *ep, -+ struct uni_name_t *p_uniname, u8 mode); -+void fat_get_uni_name_from_ext_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u16 *uniname); -+void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u16 *uniname); -+s32 extract_uni_name_from_ext_entry(struct ext_dentry_t *ep, -+ u16 *uniname, s32 order); -+s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, -+ u16 *uniname, s32 order); -+s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir, -+ struct dos_name_t *p_dosname); -+void fat_attach_count_to_dos_name(u8 *dosname, s32 count); -+s32 fat_calc_num_entries(struct uni_name_t *p_uniname); -+s32 exfat_calc_num_entries(struct uni_name_t *p_uniname); -+u8 calc_checksum_1byte(void *data, s32 len, u8 chksum); -+u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); -+u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type); -+ -+/* name resolution functions */ -+s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname); -+s32 resolve_name(u8 *name, u8 **arg); -+ -+/* file operation functions */ -+s32 fat16_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); -+s32 fat32_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); -+s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); -+s32 create_dir(struct inode *inode, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, struct file_id_t *fid); -+s32 create_file(struct inode *inode, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid); -+void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry); -+s32 rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry, -+ struct uni_name_t *p_uniname, struct file_id_t *fid); -+s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -+ struct chain_t *p_newdir, struct uni_name_t *p_uniname, -+ struct file_id_t *fid); -+ -+/* sector read/write functions */ -+int sector_read(struct super_block *sb, sector_t sec, -+ struct buffer_head **bh, bool read); -+int sector_write(struct super_block *sb, sector_t sec, -+ struct buffer_head *bh, bool sync); -+int multi_sector_read(struct super_block *sb, sector_t sec, -+ struct buffer_head **bh, s32 num_secs, bool read); -+int multi_sector_write(struct super_block *sb, sector_t sec, -+ struct buffer_head *bh, s32 num_secs, bool sync); -+ -+void bdev_open(struct super_block *sb); -+void bdev_close(struct super_block *sb); -+int bdev_read(struct super_block *sb, sector_t secno, -+ struct buffer_head **bh, u32 num_secs, bool read); -+int bdev_write(struct super_block *sb, sector_t secno, -+ struct buffer_head *bh, u32 num_secs, bool sync); -+int bdev_sync(struct super_block *sb); -+ -+extern const u8 uni_upcase[]; -+#endif /* _EXFAT_H */ -diff --git a/drivers/staging/exfat/exfat_blkdev.c b/drivers/staging/exfat/exfat_blkdev.c -new file mode 100644 -index 000000000000..f086c75e7076 ---- /dev/null -+++ b/drivers/staging/exfat/exfat_blkdev.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/blkdev.h> -+#include <linux/buffer_head.h> -+#include <linux/fs.h> -+#include "exfat.h" -+ -+void bdev_open(struct super_block *sb) -+{ -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_bd->opened) -+ return; -+ -+ p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); -+ p_bd->sector_size_bits = ilog2(p_bd->sector_size); -+ p_bd->sector_size_mask = p_bd->sector_size - 1; -+ p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> -+ p_bd->sector_size_bits; -+ p_bd->opened = true; -+} -+ -+void bdev_close(struct super_block *sb) -+{ -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ p_bd->opened = false; -+} -+ -+int bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, -+ u32 num_secs, bool read) -+{ -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ long flags = sbi->debug_flags; -+ -+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -+ return FFS_MEDIAERR; -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+ if (!p_bd->opened) -+ return FFS_MEDIAERR; -+ -+ if (*bh) -+ __brelse(*bh); -+ -+ if (read) -+ *bh = __bread(sb->s_bdev, secno, -+ num_secs << p_bd->sector_size_bits); -+ else -+ *bh = __getblk(sb->s_bdev, secno, -+ num_secs << p_bd->sector_size_bits); -+ -+ if (*bh) -+ return 0; -+ -+ WARN(!p_fs->dev_ejected, -+ "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -+ -+ return FFS_MEDIAERR; -+} -+ -+int bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, -+ u32 num_secs, bool sync) -+{ -+ s32 count; -+ struct buffer_head *bh2; -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ long flags = sbi->debug_flags; -+ -+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -+ return FFS_MEDIAERR; -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+ if (!p_bd->opened) -+ return FFS_MEDIAERR; -+ -+ if (secno == bh->b_blocknr) { -+ lock_buffer(bh); -+ set_buffer_uptodate(bh); -+ mark_buffer_dirty(bh); -+ unlock_buffer(bh); -+ if (sync && (sync_dirty_buffer(bh) != 0)) -+ return FFS_MEDIAERR; -+ } else { -+ count = num_secs << p_bd->sector_size_bits; -+ -+ bh2 = __getblk(sb->s_bdev, secno, count); -+ if (!bh2) -+ goto no_bh; -+ -+ lock_buffer(bh2); -+ memcpy(bh2->b_data, bh->b_data, count); -+ set_buffer_uptodate(bh2); -+ mark_buffer_dirty(bh2); -+ unlock_buffer(bh2); -+ if (sync && (sync_dirty_buffer(bh2) != 0)) { -+ __brelse(bh2); -+ goto no_bh; -+ } -+ __brelse(bh2); -+ } -+ -+ return 0; -+ -+no_bh: -+ WARN(!p_fs->dev_ejected, -+ "[EXFAT] No bh, device seems wrong or to be ejected.\n"); -+ -+ return FFS_MEDIAERR; -+} -+ -+int bdev_sync(struct super_block *sb) -+{ -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ long flags = sbi->debug_flags; -+ -+ if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) -+ return FFS_MEDIAERR; -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+ if (!p_bd->opened) -+ return FFS_MEDIAERR; -+ -+ return sync_blockdev(sb->s_bdev); -+} -diff --git a/drivers/staging/exfat/exfat_cache.c b/drivers/staging/exfat/exfat_cache.c -new file mode 100644 -index 000000000000..f05d692c2b1e ---- /dev/null -+++ b/drivers/staging/exfat/exfat_cache.c -@@ -0,0 +1,722 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/buffer_head.h> -+#include <linux/fs.h> -+#include <linux/mutex.h> -+#include "exfat.h" -+ -+#define LOCKBIT 0x01 -+#define DIRTYBIT 0x02 -+ -+/* Local variables */ -+static DEFINE_SEMAPHORE(f_sem); -+static DEFINE_SEMAPHORE(b_sem); -+ -+static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec) -+{ -+ s32 off; -+ struct buf_cache_t *bp, *hp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ off = (sec + -+ (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); -+ -+ hp = &p_fs->FAT_cache_hash_list[off]; -+ for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { -+ if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { -+ WARN(!bp->buf_bh, -+ "[EXFAT] FAT_cache has no bh. It will make system panic.\n"); -+ -+ touch_buffer(bp->buf_bh); -+ return bp; -+ } -+ } -+ return NULL; -+} -+ -+static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) -+{ -+ bp->next = list->next; -+ bp->prev = list; -+ list->next->prev = bp; -+ list->next = bp; -+} -+ -+static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) -+{ -+ bp->prev = list->prev; -+ bp->next = list; -+ list->prev->next = bp; -+ list->prev = bp; -+} -+ -+static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) -+{ -+ bp->prev->next = bp->next; -+ bp->next->prev = bp->prev; -+ push_to_mru(bp, list); -+} -+ -+static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) -+{ -+ bp->prev->next = bp->next; -+ bp->next->prev = bp->prev; -+ push_to_lru(bp, list); -+} -+ -+static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ bp = p_fs->FAT_cache_lru_list.prev; -+ -+ move_to_mru(bp, &p_fs->FAT_cache_lru_list); -+ return bp; -+} -+ -+static void FAT_cache_insert_hash(struct super_block *sb, -+ struct buf_cache_t *bp) -+{ -+ s32 off; -+ struct buf_cache_t *hp; -+ struct fs_info_t *p_fs; -+ -+ p_fs = &(EXFAT_SB(sb)->fs_info); -+ off = (bp->sec + -+ (bp->sec >> p_fs->sectors_per_clu_bits)) & -+ (FAT_CACHE_HASH_SIZE - 1); -+ -+ hp = &p_fs->FAT_cache_hash_list[off]; -+ bp->hash_next = hp->hash_next; -+ bp->hash_prev = hp; -+ hp->hash_next->hash_prev = bp; -+ hp->hash_next = bp; -+} -+ -+static void FAT_cache_remove_hash(struct buf_cache_t *bp) -+{ -+ (bp->hash_prev)->hash_next = bp->hash_next; -+ (bp->hash_next)->hash_prev = bp->hash_prev; -+} -+ -+static void buf_cache_insert_hash(struct super_block *sb, -+ struct buf_cache_t *bp) -+{ -+ s32 off; -+ struct buf_cache_t *hp; -+ struct fs_info_t *p_fs; -+ -+ p_fs = &(EXFAT_SB(sb)->fs_info); -+ off = (bp->sec + -+ (bp->sec >> p_fs->sectors_per_clu_bits)) & -+ (BUF_CACHE_HASH_SIZE - 1); -+ -+ hp = &p_fs->buf_cache_hash_list[off]; -+ bp->hash_next = hp->hash_next; -+ bp->hash_prev = hp; -+ hp->hash_next->hash_prev = bp; -+ hp->hash_next = bp; -+} -+ -+static void buf_cache_remove_hash(struct buf_cache_t *bp) -+{ -+ (bp->hash_prev)->hash_next = bp->hash_next; -+ (bp->hash_next)->hash_prev = bp->hash_prev; -+} -+ -+void buf_init(struct super_block *sb) -+{ -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ int i; -+ -+ /* LRU list */ -+ p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list; -+ p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; -+ -+ for (i = 0; i < FAT_CACHE_SIZE; i++) { -+ p_fs->FAT_cache_array[i].drv = -1; -+ p_fs->FAT_cache_array[i].sec = ~0; -+ p_fs->FAT_cache_array[i].flag = 0; -+ p_fs->FAT_cache_array[i].buf_bh = NULL; -+ p_fs->FAT_cache_array[i].prev = NULL; -+ p_fs->FAT_cache_array[i].next = NULL; -+ push_to_mru(&p_fs->FAT_cache_array[i], -+ &p_fs->FAT_cache_lru_list); -+ } -+ -+ p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list; -+ p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; -+ -+ for (i = 0; i < BUF_CACHE_SIZE; i++) { -+ p_fs->buf_cache_array[i].drv = -1; -+ p_fs->buf_cache_array[i].sec = ~0; -+ p_fs->buf_cache_array[i].flag = 0; -+ p_fs->buf_cache_array[i].buf_bh = NULL; -+ p_fs->buf_cache_array[i].prev = NULL; -+ p_fs->buf_cache_array[i].next = NULL; -+ push_to_mru(&p_fs->buf_cache_array[i], -+ &p_fs->buf_cache_lru_list); -+ } -+ -+ /* HASH list */ -+ for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { -+ p_fs->FAT_cache_hash_list[i].drv = -1; -+ p_fs->FAT_cache_hash_list[i].sec = ~0; -+ p_fs->FAT_cache_hash_list[i].hash_next = -+ &p_fs->FAT_cache_hash_list[i]; -+ p_fs->FAT_cache_hash_list[i].hash_prev = -+ &p_fs->FAT_cache_hash_list[i]; -+ } -+ -+ for (i = 0; i < FAT_CACHE_SIZE; i++) -+ FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]); -+ -+ for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { -+ p_fs->buf_cache_hash_list[i].drv = -1; -+ p_fs->buf_cache_hash_list[i].sec = ~0; -+ p_fs->buf_cache_hash_list[i].hash_next = -+ &p_fs->buf_cache_hash_list[i]; -+ p_fs->buf_cache_hash_list[i].hash_prev = -+ &p_fs->buf_cache_hash_list[i]; -+ } -+ -+ for (i = 0; i < BUF_CACHE_SIZE; i++) -+ buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]); -+} -+ -+void buf_shutdown(struct super_block *sb) -+{ -+} -+ -+static int __FAT_read(struct super_block *sb, u32 loc, u32 *content) -+{ -+ s32 off; -+ u32 _content; -+ sector_t sec; -+ u8 *fat_sector, *fat_entry; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_fs->vol_type == FAT12) { -+ sec = p_fs->FAT1_start_sector + -+ ((loc + (loc >> 1)) >> p_bd->sector_size_bits); -+ off = (loc + (loc >> 1)) & p_bd->sector_size_mask; -+ -+ if (off == (p_bd->sector_size - 1)) { -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ _content = (u32)fat_sector[off]; -+ -+ fat_sector = FAT_getblk(sb, ++sec); -+ if (!fat_sector) -+ return -1; -+ -+ _content |= (u32)fat_sector[0] << 8; -+ } else { -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ _content = GET16(fat_entry); -+ } -+ -+ if (loc & 1) -+ _content >>= 4; -+ -+ _content &= 0x00000FFF; -+ -+ if (_content >= CLUSTER_16(0x0FF8)) { -+ *content = CLUSTER_32(~0); -+ return 0; -+ } -+ *content = CLUSTER_32(_content); -+ return 0; -+ } else if (p_fs->vol_type == FAT16) { -+ sec = p_fs->FAT1_start_sector + -+ (loc >> (p_bd->sector_size_bits - 1)); -+ off = (loc << 1) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ -+ _content = GET16_A(fat_entry); -+ -+ _content &= 0x0000FFFF; -+ -+ if (_content >= CLUSTER_16(0xFFF8)) { -+ *content = CLUSTER_32(~0); -+ return 0; -+ } -+ *content = CLUSTER_32(_content); -+ return 0; -+ } else if (p_fs->vol_type == FAT32) { -+ sec = p_fs->FAT1_start_sector + -+ (loc >> (p_bd->sector_size_bits - 2)); -+ off = (loc << 2) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ -+ _content = GET32_A(fat_entry); -+ -+ _content &= 0x0FFFFFFF; -+ -+ if (_content >= CLUSTER_32(0x0FFFFFF8)) { -+ *content = CLUSTER_32(~0); -+ return 0; -+ } -+ *content = CLUSTER_32(_content); -+ return 0; -+ } else if (p_fs->vol_type == EXFAT) { -+ sec = p_fs->FAT1_start_sector + -+ (loc >> (p_bd->sector_size_bits - 2)); -+ off = (loc << 2) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ _content = GET32_A(fat_entry); -+ -+ if (_content >= CLUSTER_32(0xFFFFFFF8)) { -+ *content = CLUSTER_32(~0); -+ return 0; -+ } -+ *content = CLUSTER_32(_content); -+ return 0; -+ } -+ -+ /* Unknown volume type, throw in the towel and go home */ -+ *content = CLUSTER_32(~0); -+ return 0; -+} -+ -+/* in : sb, loc -+ * out: content -+ * returns 0 on success -+ * -1 on error -+ */ -+int FAT_read(struct super_block *sb, u32 loc, u32 *content) -+{ -+ s32 ret; -+ -+ down(&f_sem); -+ ret = __FAT_read(sb, loc, content); -+ up(&f_sem); -+ -+ return ret; -+} -+ -+static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content) -+{ -+ s32 off; -+ sector_t sec; -+ u8 *fat_sector, *fat_entry; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_fs->vol_type == FAT12) { -+ content &= 0x00000FFF; -+ -+ sec = p_fs->FAT1_start_sector + -+ ((loc + (loc >> 1)) >> p_bd->sector_size_bits); -+ off = (loc + (loc >> 1)) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ if (loc & 1) { /* odd */ -+ content <<= 4; -+ -+ if (off == (p_bd->sector_size - 1)) { -+ fat_sector[off] = (u8)(content | -+ (fat_sector[off] & -+ 0x0F)); -+ FAT_modify(sb, sec); -+ -+ fat_sector = FAT_getblk(sb, ++sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_sector[0] = (u8)(content >> 8); -+ } else { -+ fat_entry = &fat_sector[off]; -+ content |= GET16(fat_entry) & 0x000F; -+ -+ SET16(fat_entry, content); -+ } -+ } else { /* even */ -+ fat_sector[off] = (u8)(content); -+ -+ if (off == (p_bd->sector_size - 1)) { -+ fat_sector[off] = (u8)(content); -+ FAT_modify(sb, sec); -+ -+ fat_sector = FAT_getblk(sb, ++sec); -+ fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | -+ (content >> 8)); -+ } else { -+ fat_entry = &fat_sector[off]; -+ content |= GET16(fat_entry) & 0xF000; -+ -+ SET16(fat_entry, content); -+ } -+ } -+ } -+ -+ else if (p_fs->vol_type == FAT16) { -+ content &= 0x0000FFFF; -+ -+ sec = p_fs->FAT1_start_sector + (loc >> -+ (p_bd->sector_size_bits - 1)); -+ off = (loc << 1) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ -+ SET16_A(fat_entry, content); -+ } else if (p_fs->vol_type == FAT32) { -+ content &= 0x0FFFFFFF; -+ -+ sec = p_fs->FAT1_start_sector + (loc >> -+ (p_bd->sector_size_bits - 2)); -+ off = (loc << 2) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ -+ content |= GET32_A(fat_entry) & 0xF0000000; -+ -+ SET32_A(fat_entry, content); -+ } else { /* p_fs->vol_type == EXFAT */ -+ sec = p_fs->FAT1_start_sector + (loc >> -+ (p_bd->sector_size_bits - 2)); -+ off = (loc << 2) & p_bd->sector_size_mask; -+ -+ fat_sector = FAT_getblk(sb, sec); -+ if (!fat_sector) -+ return -1; -+ -+ fat_entry = &fat_sector[off]; -+ -+ SET32_A(fat_entry, content); -+ } -+ -+ FAT_modify(sb, sec); -+ return 0; -+} -+ -+int FAT_write(struct super_block *sb, u32 loc, u32 content) -+{ -+ s32 ret; -+ -+ down(&f_sem); -+ ret = __FAT_write(sb, loc, content); -+ up(&f_sem); -+ -+ return ret; -+} -+ -+u8 *FAT_getblk(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ bp = FAT_cache_find(sb, sec); -+ if (bp) { -+ move_to_mru(bp, &p_fs->FAT_cache_lru_list); -+ return bp->buf_bh->b_data; -+ } -+ -+ bp = FAT_cache_get(sb, sec); -+ -+ FAT_cache_remove_hash(bp); -+ -+ bp->drv = p_fs->drv; -+ bp->sec = sec; -+ bp->flag = 0; -+ -+ FAT_cache_insert_hash(sb, bp); -+ -+ if (sector_read(sb, sec, &bp->buf_bh, 1) != FFS_SUCCESS) { -+ FAT_cache_remove_hash(bp); -+ bp->drv = -1; -+ bp->sec = ~0; -+ bp->flag = 0; -+ bp->buf_bh = NULL; -+ -+ move_to_lru(bp, &p_fs->FAT_cache_lru_list); -+ return NULL; -+ } -+ -+ return bp->buf_bh->b_data; -+} -+ -+void FAT_modify(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ -+ bp = FAT_cache_find(sb, sec); -+ if (bp) -+ sector_write(sb, sec, bp->buf_bh, 0); -+} -+ -+void FAT_release_all(struct super_block *sb) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ down(&f_sem); -+ -+ bp = p_fs->FAT_cache_lru_list.next; -+ while (bp != &p_fs->FAT_cache_lru_list) { -+ if (bp->drv == p_fs->drv) { -+ bp->drv = -1; -+ bp->sec = ~0; -+ bp->flag = 0; -+ -+ if (bp->buf_bh) { -+ __brelse(bp->buf_bh); -+ bp->buf_bh = NULL; -+ } -+ } -+ bp = bp->next; -+ } -+ -+ up(&f_sem); -+} -+ -+void FAT_sync(struct super_block *sb) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ down(&f_sem); -+ -+ bp = p_fs->FAT_cache_lru_list.next; -+ while (bp != &p_fs->FAT_cache_lru_list) { -+ if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -+ sync_dirty_buffer(bp->buf_bh); -+ bp->flag &= ~(DIRTYBIT); -+ } -+ bp = bp->next; -+ } -+ -+ up(&f_sem); -+} -+ -+static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec) -+{ -+ s32 off; -+ struct buf_cache_t *bp, *hp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & -+ (BUF_CACHE_HASH_SIZE - 1); -+ -+ hp = &p_fs->buf_cache_hash_list[off]; -+ for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { -+ if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { -+ touch_buffer(bp->buf_bh); -+ return bp; -+ } -+ } -+ return NULL; -+} -+ -+static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ bp = p_fs->buf_cache_lru_list.prev; -+ while (bp->flag & LOCKBIT) -+ bp = bp->prev; -+ -+ move_to_mru(bp, &p_fs->buf_cache_lru_list); -+ return bp; -+} -+ -+static u8 *__buf_getblk(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ bp = buf_cache_find(sb, sec); -+ if (bp) { -+ move_to_mru(bp, &p_fs->buf_cache_lru_list); -+ return bp->buf_bh->b_data; -+ } -+ -+ bp = buf_cache_get(sb, sec); -+ -+ buf_cache_remove_hash(bp); -+ -+ bp->drv = p_fs->drv; -+ bp->sec = sec; -+ bp->flag = 0; -+ -+ buf_cache_insert_hash(sb, bp); -+ -+ if (sector_read(sb, sec, &bp->buf_bh, 1) != FFS_SUCCESS) { -+ buf_cache_remove_hash(bp); -+ bp->drv = -1; -+ bp->sec = ~0; -+ bp->flag = 0; -+ bp->buf_bh = NULL; -+ -+ move_to_lru(bp, &p_fs->buf_cache_lru_list); -+ return NULL; -+ } -+ -+ return bp->buf_bh->b_data; -+} -+ -+u8 *buf_getblk(struct super_block *sb, sector_t sec) -+{ -+ u8 *buf; -+ -+ down(&b_sem); -+ buf = __buf_getblk(sb, sec); -+ up(&b_sem); -+ -+ return buf; -+} -+ -+void buf_modify(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ -+ down(&b_sem); -+ -+ bp = buf_cache_find(sb, sec); -+ if (likely(bp)) -+ sector_write(sb, sec, bp->buf_bh, 0); -+ -+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -+ (unsigned long long)sec); -+ -+ up(&b_sem); -+} -+ -+void buf_lock(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ -+ down(&b_sem); -+ -+ bp = buf_cache_find(sb, sec); -+ if (likely(bp)) -+ bp->flag |= LOCKBIT; -+ -+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -+ (unsigned long long)sec); -+ -+ up(&b_sem); -+} -+ -+void buf_unlock(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ -+ down(&b_sem); -+ -+ bp = buf_cache_find(sb, sec); -+ if (likely(bp)) -+ bp->flag &= ~(LOCKBIT); -+ -+ WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", -+ (unsigned long long)sec); -+ -+ up(&b_sem); -+} -+ -+void buf_release(struct super_block *sb, sector_t sec) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ down(&b_sem); -+ -+ bp = buf_cache_find(sb, sec); -+ if (likely(bp)) { -+ bp->drv = -1; -+ bp->sec = ~0; -+ bp->flag = 0; -+ -+ if (bp->buf_bh) { -+ __brelse(bp->buf_bh); -+ bp->buf_bh = NULL; -+ } -+ -+ move_to_lru(bp, &p_fs->buf_cache_lru_list); -+ } -+ -+ up(&b_sem); -+} -+ -+void buf_release_all(struct super_block *sb) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ down(&b_sem); -+ -+ bp = p_fs->buf_cache_lru_list.next; -+ while (bp != &p_fs->buf_cache_lru_list) { -+ if (bp->drv == p_fs->drv) { -+ bp->drv = -1; -+ bp->sec = ~0; -+ bp->flag = 0; -+ -+ if (bp->buf_bh) { -+ __brelse(bp->buf_bh); -+ bp->buf_bh = NULL; -+ } -+ } -+ bp = bp->next; -+ } -+ -+ up(&b_sem); -+} -+ -+void buf_sync(struct super_block *sb) -+{ -+ struct buf_cache_t *bp; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ down(&b_sem); -+ -+ bp = p_fs->buf_cache_lru_list.next; -+ while (bp != &p_fs->buf_cache_lru_list) { -+ if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { -+ sync_dirty_buffer(bp->buf_bh); -+ bp->flag &= ~(DIRTYBIT); -+ } -+ bp = bp->next; -+ } -+ -+ up(&b_sem); -+} -diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c -new file mode 100644 -index 000000000000..9f76ca175c80 ---- /dev/null -+++ b/drivers/staging/exfat/exfat_core.c -@@ -0,0 +1,3704 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/types.h> -+#include <linux/buffer_head.h> -+#include <linux/fs.h> -+#include <linux/mutex.h> -+#include <linux/blkdev.h> -+#include <linux/slab.h> -+#include "exfat.h" -+ -+ -+static void __set_sb_dirty(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ sbi->s_dirt = 1; -+} -+ -+static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; -+ -+static char *reserved_names[] = { -+ "AUX ", "CON ", "NUL ", "PRN ", -+ "COM1 ", "COM2 ", "COM3 ", "COM4 ", -+ "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ", -+ "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ", -+ "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ", -+ NULL -+}; -+ -+static u8 free_bit[] = { -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ -+ 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ -+ 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ -+ 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ -+ 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ -+ 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ -+ 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ -+ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ -+}; -+ -+static u8 used_bit[] = { -+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ -+ 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ -+ 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ -+ 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ -+ 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ -+ 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ -+ 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ -+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ -+ 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ -+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ -+ 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ -+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ -+}; -+ -+#define BITMAP_LOC(v) ((v) >> 3) -+#define BITMAP_SHIFT(v) ((v) & 0x07) -+ -+static inline s32 exfat_bitmap_test(u8 *bitmap, int i) -+{ -+ u8 data; -+ -+ data = bitmap[BITMAP_LOC(i)]; -+ if ((data >> BITMAP_SHIFT(i)) & 0x01) -+ return 1; -+ return 0; -+} -+ -+static inline void exfat_bitmap_set(u8 *bitmap, int i) -+{ -+ bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); -+} -+ -+static inline void exfat_bitmap_clear(u8 *bitmap, int i) -+{ -+ bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); -+} -+ -+/* -+ * File System Management Functions -+ */ -+ -+void fs_set_vol_flags(struct super_block *sb, u32 new_flag) -+{ -+ struct pbr_sector_t *p_pbr; -+ struct bpbex_t *p_bpb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_fs->vol_flag == new_flag) -+ return; -+ -+ p_fs->vol_flag = new_flag; -+ -+ if (p_fs->vol_type == EXFAT) { -+ if (p_fs->pbr_bh == NULL) { -+ if (sector_read(sb, p_fs->PBR_sector, -+ &p_fs->pbr_bh, 1) != FFS_SUCCESS) -+ return; -+ } -+ -+ p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data; -+ p_bpb = (struct bpbex_t *)p_pbr->bpb; -+ SET16(p_bpb->vol_flags, (u16)new_flag); -+ -+ /* XXX duyoung -+ * what can we do here? (cuz fs_set_vol_flags() is void) -+ */ -+ if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) -+ sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); -+ else -+ sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); -+ } -+} -+ -+void fs_error(struct super_block *sb) -+{ -+ struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; -+ -+ if (opts->errors == EXFAT_ERRORS_PANIC) { -+ panic("[EXFAT] Filesystem panic from previous error\n"); -+ } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) { -+ sb->s_flags |= SB_RDONLY; -+ pr_err("[EXFAT] Filesystem has been set read-only\n"); -+ } -+} -+ -+/* -+ * Cluster Management Functions -+ */ -+ -+s32 clear_cluster(struct super_block *sb, u32 clu) -+{ -+ sector_t s, n; -+ s32 ret = FFS_SUCCESS; -+ struct buffer_head *tmp_bh = NULL; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ -+ s = p_fs->root_start_sector; -+ n = p_fs->data_start_sector; -+ } else { -+ s = START_SECTOR(clu); -+ n = s + p_fs->sectors_per_clu; -+ } -+ -+ for (; s < n; s++) { -+ ret = sector_read(sb, s, &tmp_bh, 0); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size); -+ ret = sector_write(sb, s, tmp_bh, 0); -+ if (ret != FFS_SUCCESS) -+ break; -+ } -+ -+ brelse(tmp_bh); -+ return ret; -+} -+ -+s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, -+ struct chain_t *p_chain) -+{ -+ int i, num_clusters = 0; -+ u32 new_clu, last_clu = CLUSTER_32(~0), read_clu; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ new_clu = p_chain->dir; -+ if (new_clu == CLUSTER_32(~0)) -+ new_clu = p_fs->clu_srch_ptr; -+ else if (new_clu >= p_fs->num_clusters) -+ new_clu = 2; -+ -+ __set_sb_dirty(sb); -+ -+ p_chain->dir = CLUSTER_32(~0); -+ -+ for (i = 2; i < p_fs->num_clusters; i++) { -+ if (FAT_read(sb, new_clu, &read_clu) != 0) -+ return -1; -+ -+ if (read_clu == CLUSTER_32(0)) { -+ if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) -+ return -1; -+ num_clusters++; -+ -+ if (p_chain->dir == CLUSTER_32(~0)) { -+ p_chain->dir = new_clu; -+ } else { -+ if (FAT_write(sb, last_clu, new_clu) < 0) -+ return -1; -+ } -+ -+ last_clu = new_clu; -+ -+ if ((--num_alloc) == 0) { -+ p_fs->clu_srch_ptr = new_clu; -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters += num_clusters; -+ -+ return num_clusters; -+ } -+ } -+ if ((++new_clu) >= p_fs->num_clusters) -+ new_clu = 2; -+ } -+ -+ p_fs->clu_srch_ptr = new_clu; -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters += num_clusters; -+ -+ return num_clusters; -+} -+ -+s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, -+ struct chain_t *p_chain) -+{ -+ s32 num_clusters = 0; -+ u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ hint_clu = p_chain->dir; -+ if (hint_clu == CLUSTER_32(~0)) { -+ hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr-2); -+ if (hint_clu == CLUSTER_32(~0)) -+ return 0; -+ } else if (hint_clu >= p_fs->num_clusters) { -+ hint_clu = 2; -+ p_chain->flags = 0x01; -+ } -+ -+ __set_sb_dirty(sb); -+ -+ p_chain->dir = CLUSTER_32(~0); -+ -+ while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUSTER_32(~0)) { -+ if (new_clu != hint_clu) { -+ if (p_chain->flags == 0x03) { -+ exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters); -+ p_chain->flags = 0x01; -+ } -+ } -+ -+ if (set_alloc_bitmap(sb, new_clu-2) != FFS_SUCCESS) -+ return -1; -+ -+ num_clusters++; -+ -+ if (p_chain->flags == 0x01) { -+ if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) -+ return -1; -+ } -+ -+ if (p_chain->dir == CLUSTER_32(~0)) { -+ p_chain->dir = new_clu; -+ } else { -+ if (p_chain->flags == 0x01) { -+ if (FAT_write(sb, last_clu, new_clu) < 0) -+ return -1; -+ } -+ } -+ last_clu = new_clu; -+ -+ if ((--num_alloc) == 0) { -+ p_fs->clu_srch_ptr = hint_clu; -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters += num_clusters; -+ -+ p_chain->size += num_clusters; -+ return num_clusters; -+ } -+ -+ hint_clu = new_clu + 1; -+ if (hint_clu >= p_fs->num_clusters) { -+ hint_clu = 2; -+ -+ if (p_chain->flags == 0x03) { -+ exfat_chain_cont_cluster(sb, p_chain->dir, -+ num_clusters); -+ p_chain->flags = 0x01; -+ } -+ } -+ } -+ -+ p_fs->clu_srch_ptr = hint_clu; -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters += num_clusters; -+ -+ p_chain->size += num_clusters; -+ return num_clusters; -+} -+ -+void fat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -+ s32 do_relse) -+{ -+ s32 num_clusters = 0; -+ u32 clu, prev; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ int i; -+ sector_t sector; -+ -+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -+ return; -+ __set_sb_dirty(sb); -+ clu = p_chain->dir; -+ -+ if (p_chain->size <= 0) -+ return; -+ -+ do { -+ if (p_fs->dev_ejected) -+ break; -+ -+ if (do_relse) { -+ sector = START_SECTOR(clu); -+ for (i = 0; i < p_fs->sectors_per_clu; i++) -+ buf_release(sb, sector+i); -+ } -+ -+ prev = clu; -+ if (FAT_read(sb, clu, &clu) == -1) -+ break; -+ -+ if (FAT_write(sb, prev, CLUSTER_32(0)) < 0) -+ break; -+ num_clusters++; -+ -+ } while (clu != CLUSTER_32(~0)); -+ -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters -= num_clusters; -+} -+ -+void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, -+ s32 do_relse) -+{ -+ s32 num_clusters = 0; -+ u32 clu; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ int i; -+ sector_t sector; -+ -+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -+ return; -+ -+ if (p_chain->size <= 0) { -+ pr_err("[EXFAT] free_cluster : skip free-req clu:%u, because of zero-size truncation\n", -+ p_chain->dir); -+ return; -+ } -+ -+ __set_sb_dirty(sb); -+ clu = p_chain->dir; -+ -+ if (p_chain->flags == 0x03) { -+ do { -+ if (do_relse) { -+ sector = START_SECTOR(clu); -+ for (i = 0; i < p_fs->sectors_per_clu; i++) -+ buf_release(sb, sector+i); -+ } -+ -+ if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) -+ break; -+ clu++; -+ -+ num_clusters++; -+ } while (num_clusters < p_chain->size); -+ } else { -+ do { -+ if (p_fs->dev_ejected) -+ break; -+ -+ if (do_relse) { -+ sector = START_SECTOR(clu); -+ for (i = 0; i < p_fs->sectors_per_clu; i++) -+ buf_release(sb, sector+i); -+ } -+ -+ if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) -+ break; -+ -+ if (FAT_read(sb, clu, &clu) == -1) -+ break; -+ num_clusters++; -+ } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); -+ } -+ -+ if (p_fs->used_clusters != (u32) ~0) -+ p_fs->used_clusters -= num_clusters; -+} -+ -+u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain) -+{ -+ u32 clu, next; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ clu = p_chain->dir; -+ -+ if (p_chain->flags == 0x03) { -+ clu += p_chain->size - 1; -+ } else { -+ while ((FAT_read(sb, clu, &next) == 0) && -+ (next != CLUSTER_32(~0))) { -+ if (p_fs->dev_ejected) -+ break; -+ clu = next; -+ } -+ } -+ -+ return clu; -+} -+ -+s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain) -+{ -+ int i, count = 0; -+ u32 clu; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) -+ return 0; -+ -+ clu = p_chain->dir; -+ -+ if (p_chain->flags == 0x03) { -+ count = p_chain->size; -+ } else { -+ for (i = 2; i < p_fs->num_clusters; i++) { -+ count++; -+ if (FAT_read(sb, clu, &clu) != 0) -+ return 0; -+ if (clu == CLUSTER_32(~0)) -+ break; -+ } -+ } -+ -+ return count; -+} -+ -+s32 fat_count_used_clusters(struct super_block *sb) -+{ -+ int i, count = 0; -+ u32 clu; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ for (i = 2; i < p_fs->num_clusters; i++) { -+ if (FAT_read(sb, i, &clu) != 0) -+ break; -+ if (clu != CLUSTER_32(0)) -+ count++; -+ } -+ -+ return count; -+} -+ -+s32 exfat_count_used_clusters(struct super_block *sb) -+{ -+ int i, map_i, map_b, count = 0; -+ u8 k; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ map_i = map_b = 0; -+ -+ for (i = 2; i < p_fs->num_clusters; i += 8) { -+ k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); -+ count += used_bit[k]; -+ -+ if ((++map_b) >= p_bd->sector_size) { -+ map_i++; -+ map_b = 0; -+ } -+ } -+ -+ return count; -+} -+ -+void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) -+{ -+ if (len == 0) -+ return; -+ -+ while (len > 1) { -+ if (FAT_write(sb, chain, chain+1) < 0) -+ break; -+ chain++; -+ len--; -+ } -+ FAT_write(sb, chain, CLUSTER_32(~0)); -+} -+ -+/* -+ * Allocation Bitmap Management Functions -+ */ -+ -+s32 load_alloc_bitmap(struct super_block *sb) -+{ -+ int i, j, ret; -+ u32 map_size; -+ u32 type; -+ sector_t sector; -+ struct chain_t clu; -+ struct bmap_dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ clu.dir = p_fs->root_dir; -+ clu.flags = 0x01; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ for (i = 0; i < p_fs->dentries_per_clu; i++) { -+ ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu, -+ i, NULL); -+ if (!ep) -+ return FFS_MEDIAERR; -+ -+ type = p_fs->fs_func->get_entry_type((struct dentry_t *)ep); -+ -+ if (type == TYPE_UNUSED) -+ break; -+ if (type != TYPE_BITMAP) -+ continue; -+ -+ if (ep->flags == 0x0) { -+ p_fs->map_clu = GET32_A(ep->start_clu); -+ map_size = (u32) GET64_A(ep->size); -+ -+ p_fs->map_sectors = ((map_size-1) >> p_bd->sector_size_bits) + 1; -+ -+ p_fs->vol_amap = kmalloc_array(p_fs->map_sectors, -+ sizeof(struct buffer_head *), -+ GFP_KERNEL); -+ if (p_fs->vol_amap == NULL) -+ return FFS_MEMORYERR; -+ -+ sector = START_SECTOR(p_fs->map_clu); -+ -+ for (j = 0; j < p_fs->map_sectors; j++) { -+ p_fs->vol_amap[j] = NULL; -+ ret = sector_read(sb, sector+j, &(p_fs->vol_amap[j]), 1); -+ if (ret != FFS_SUCCESS) { -+ /* release all buffers and free vol_amap */ -+ i = 0; -+ while (i < j) -+ brelse(p_fs->vol_amap[i++]); -+ -+ kfree(p_fs->vol_amap); -+ p_fs->vol_amap = NULL; -+ return ret; -+ } -+ } -+ -+ p_fs->pbr_bh = NULL; -+ return FFS_SUCCESS; -+ } -+ } -+ -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return FFS_MEDIAERR; -+ } -+ -+ return FFS_FORMATERR; -+} -+ -+void free_alloc_bitmap(struct super_block *sb) -+{ -+ int i; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ brelse(p_fs->pbr_bh); -+ -+ for (i = 0; i < p_fs->map_sectors; i++) -+ __brelse(p_fs->vol_amap[i]); -+ -+ kfree(p_fs->vol_amap); -+ p_fs->vol_amap = NULL; -+} -+ -+s32 set_alloc_bitmap(struct super_block *sb, u32 clu) -+{ -+ int i, b; -+ sector_t sector; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ i = clu >> (p_bd->sector_size_bits + 3); -+ b = clu & ((p_bd->sector_size << 3) - 1); -+ -+ sector = START_SECTOR(p_fs->map_clu) + i; -+ -+ exfat_bitmap_set((u8 *) p_fs->vol_amap[i]->b_data, b); -+ -+ return sector_write(sb, sector, p_fs->vol_amap[i], 0); -+} -+ -+s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) -+{ -+ int i, b; -+ sector_t sector; -+#ifdef CONFIG_EXFAT_DISCARD -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ int ret; -+#endif /* CONFIG_EXFAT_DISCARD */ -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ i = clu >> (p_bd->sector_size_bits + 3); -+ b = clu & ((p_bd->sector_size << 3) - 1); -+ -+ sector = START_SECTOR(p_fs->map_clu) + i; -+ -+ exfat_bitmap_clear((u8 *) p_fs->vol_amap[i]->b_data, b); -+ -+ return sector_write(sb, sector, p_fs->vol_amap[i], 0); -+ -+#ifdef CONFIG_EXFAT_DISCARD -+ if (opts->discard) { -+ ret = sb_issue_discard(sb, START_SECTOR(clu), -+ (1 << p_fs->sectors_per_clu_bits), -+ GFP_NOFS, 0); -+ if (ret == -EOPNOTSUPP) { -+ pr_warn("discard not supported by device, disabling"); -+ opts->discard = 0; -+ } -+ } -+#endif /* CONFIG_EXFAT_DISCARD */ -+} -+ -+u32 test_alloc_bitmap(struct super_block *sb, u32 clu) -+{ -+ int i, map_i, map_b; -+ u32 clu_base, clu_free; -+ u8 k, clu_mask; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ clu_base = (clu & ~(0x7)) + 2; -+ clu_mask = (1 << (clu - clu_base + 2)) - 1; -+ -+ map_i = clu >> (p_bd->sector_size_bits + 3); -+ map_b = (clu >> 3) & p_bd->sector_size_mask; -+ -+ for (i = 2; i < p_fs->num_clusters; i += 8) { -+ k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); -+ if (clu_mask > 0) { -+ k |= clu_mask; -+ clu_mask = 0; -+ } -+ if (k < 0xFF) { -+ clu_free = clu_base + free_bit[k]; -+ if (clu_free < p_fs->num_clusters) -+ return clu_free; -+ } -+ clu_base += 8; -+ -+ if (((++map_b) >= p_bd->sector_size) || -+ (clu_base >= p_fs->num_clusters)) { -+ if ((++map_i) >= p_fs->map_sectors) { -+ clu_base = 2; -+ map_i = 0; -+ } -+ map_b = 0; -+ } -+ } -+ -+ return CLUSTER_32(~0); -+} -+ -+void sync_alloc_bitmap(struct super_block *sb) -+{ -+ int i; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_fs->vol_amap == NULL) -+ return; -+ -+ for (i = 0; i < p_fs->map_sectors; i++) -+ sync_dirty_buffer(p_fs->vol_amap[i]); -+} -+ -+/* -+ * Upcase table Management Functions -+ */ -+static s32 __load_upcase_table(struct super_block *sb, sector_t sector, -+ u32 num_sectors, u32 utbl_checksum) -+{ -+ int i, ret = FFS_ERROR; -+ u32 j; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct buffer_head *tmp_bh = NULL; -+ sector_t end_sector = num_sectors + sector; -+ -+ u8 skip = FALSE; -+ u32 index = 0; -+ u16 uni = 0; -+ u16 **upcase_table; -+ -+ u32 checksum = 0; -+ -+ upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *), -+ GFP_KERNEL); -+ if (upcase_table == NULL) -+ return FFS_MEMORYERR; -+ memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -+ -+ while (sector < end_sector) { -+ ret = sector_read(sb, sector, &tmp_bh, 1); -+ if (ret != FFS_SUCCESS) { -+ pr_debug("sector read (0x%llX)fail\n", -+ (unsigned long long)sector); -+ goto error; -+ } -+ sector++; -+ -+ for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { -+ uni = GET16(((u8 *) tmp_bh->b_data)+i); -+ -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -+ i); -+ checksum = ((checksum & 1) ? 0x80000000 : 0) + -+ (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + -+ (i + 1)); -+ -+ if (skip) { -+ pr_debug("skip from 0x%X ", index); -+ index += uni; -+ pr_debug("to 0x%X (amount of 0x%X)\n", -+ index, uni); -+ skip = FALSE; -+ } else if (uni == index) -+ index++; -+ else if (uni == 0xFFFF) -+ skip = TRUE; -+ else { /* uni != index , uni != 0xFFFF */ -+ u16 col_index = get_col_index(index); -+ -+ if (upcase_table[col_index] == NULL) { -+ pr_debug("alloc = 0x%X\n", col_index); -+ upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -+ sizeof(u16), GFP_KERNEL); -+ if (upcase_table[col_index] == NULL) { -+ ret = FFS_MEMORYERR; -+ goto error; -+ } -+ -+ for (j = 0; j < UTBL_ROW_COUNT; j++) -+ upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -+ } -+ -+ upcase_table[col_index][get_row_index(index)] = uni; -+ index++; -+ } -+ } -+ } -+ if (index >= 0xFFFF && utbl_checksum == checksum) { -+ if (tmp_bh) -+ brelse(tmp_bh); -+ return FFS_SUCCESS; -+ } -+ ret = FFS_ERROR; -+error: -+ if (tmp_bh) -+ brelse(tmp_bh); -+ free_upcase_table(sb); -+ return ret; -+} -+ -+static s32 __load_default_upcase_table(struct super_block *sb) -+{ -+ int i, ret = FFS_ERROR; -+ u32 j; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ u8 skip = FALSE; -+ u32 index = 0; -+ u16 uni = 0; -+ u16 **upcase_table; -+ -+ upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *), -+ GFP_KERNEL); -+ if (upcase_table == NULL) -+ return FFS_MEMORYERR; -+ memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); -+ -+ for (i = 0; index <= 0xFFFF && i < NUM_UPCASE*2; i += 2) { -+ uni = GET16(uni_upcase + i); -+ if (skip) { -+ pr_debug("skip from 0x%X ", index); -+ index += uni; -+ pr_debug("to 0x%X (amount of 0x%X)\n", index, uni); -+ skip = FALSE; -+ } else if (uni == index) -+ index++; -+ else if (uni == 0xFFFF) -+ skip = TRUE; -+ else { /* uni != index , uni != 0xFFFF */ -+ u16 col_index = get_col_index(index); -+ -+ if (upcase_table[col_index] == NULL) { -+ pr_debug("alloc = 0x%X\n", col_index); -+ upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, -+ sizeof(u16), -+ GFP_KERNEL); -+ if (upcase_table[col_index] == NULL) { -+ ret = FFS_MEMORYERR; -+ goto error; -+ } -+ -+ for (j = 0; j < UTBL_ROW_COUNT; j++) -+ upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; -+ } -+ -+ upcase_table[col_index][get_row_index(index)] = uni; -+ index++; -+ } -+ } -+ -+ if (index >= 0xFFFF) -+ return FFS_SUCCESS; -+ -+error: -+ /* FATAL error: default upcase table has error */ -+ free_upcase_table(sb); -+ return ret; -+} -+ -+s32 load_upcase_table(struct super_block *sb) -+{ -+ int i; -+ u32 tbl_clu, tbl_size; -+ sector_t sector; -+ u32 type, num_sectors; -+ struct chain_t clu; -+ struct case_dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ clu.dir = p_fs->root_dir; -+ clu.flags = 0x01; -+ -+ if (p_fs->dev_ejected) -+ return FFS_MEDIAERR; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ for (i = 0; i < p_fs->dentries_per_clu; i++) { -+ ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu, -+ i, NULL); -+ if (!ep) -+ return FFS_MEDIAERR; -+ -+ type = p_fs->fs_func->get_entry_type((struct dentry_t *)ep); -+ -+ if (type == TYPE_UNUSED) -+ break; -+ if (type != TYPE_UPCASE) -+ continue; -+ -+ tbl_clu = GET32_A(ep->start_clu); -+ tbl_size = (u32) GET64_A(ep->size); -+ -+ sector = START_SECTOR(tbl_clu); -+ num_sectors = ((tbl_size-1) >> p_bd->sector_size_bits) + 1; -+ if (__load_upcase_table(sb, sector, num_sectors, -+ GET32_A(ep->checksum)) != FFS_SUCCESS) -+ break; -+ return FFS_SUCCESS; -+ } -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return FFS_MEDIAERR; -+ } -+ /* load default upcase table */ -+ return __load_default_upcase_table(sb); -+} -+ -+void free_upcase_table(struct super_block *sb) -+{ -+ u32 i; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ u16 **upcase_table; -+ -+ upcase_table = p_fs->vol_utbl; -+ for (i = 0; i < UTBL_COL_COUNT; i++) -+ kfree(upcase_table[i]); -+ -+ kfree(p_fs->vol_utbl); -+ p_fs->vol_utbl = NULL; -+} -+ -+/* -+ * Directory Entry Management Functions -+ */ -+ -+u32 fat_get_entry_type(struct dentry_t *p_entry) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *) p_entry; -+ -+ if (*(ep->name) == 0x0) -+ return TYPE_UNUSED; -+ -+ else if (*(ep->name) == 0xE5) -+ return TYPE_DELETED; -+ -+ else if (ep->attr == ATTR_EXTEND) -+ return TYPE_EXTEND; -+ -+ else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_VOLUME) -+ return TYPE_VOLUME; -+ -+ else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_SUBDIR) -+ return TYPE_DIR; -+ -+ return TYPE_FILE; -+} -+ -+u32 exfat_get_entry_type(struct dentry_t *p_entry) -+{ -+ struct file_dentry_t *ep = (struct file_dentry_t *) p_entry; -+ -+ if (ep->type == 0x0) { -+ return TYPE_UNUSED; -+ } else if (ep->type < 0x80) { -+ return TYPE_DELETED; -+ } else if (ep->type == 0x80) { -+ return TYPE_INVALID; -+ } else if (ep->type < 0xA0) { -+ if (ep->type == 0x81) { -+ return TYPE_BITMAP; -+ } else if (ep->type == 0x82) { -+ return TYPE_UPCASE; -+ } else if (ep->type == 0x83) { -+ return TYPE_VOLUME; -+ } else if (ep->type == 0x85) { -+ if (GET16_A(ep->attr) & ATTR_SUBDIR) -+ return TYPE_DIR; -+ else -+ return TYPE_FILE; -+ } -+ return TYPE_CRITICAL_PRI; -+ } else if (ep->type < 0xC0) { -+ if (ep->type == 0xA0) -+ return TYPE_GUID; -+ else if (ep->type == 0xA1) -+ return TYPE_PADDING; -+ else if (ep->type == 0xA2) -+ return TYPE_ACLTAB; -+ return TYPE_BENIGN_PRI; -+ } else if (ep->type < 0xE0) { -+ if (ep->type == 0xC0) -+ return TYPE_STREAM; -+ else if (ep->type == 0xC1) -+ return TYPE_EXTEND; -+ else if (ep->type == 0xC2) -+ return TYPE_ACL; -+ return TYPE_CRITICAL_SEC; -+ } -+ -+ return TYPE_BENIGN_SEC; -+} -+ -+void fat_set_entry_type(struct dentry_t *p_entry, u32 type) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *) p_entry; -+ -+ if (type == TYPE_UNUSED) -+ *(ep->name) = 0x0; -+ -+ else if (type == TYPE_DELETED) -+ *(ep->name) = 0xE5; -+ -+ else if (type == TYPE_EXTEND) -+ ep->attr = ATTR_EXTEND; -+ -+ else if (type == TYPE_DIR) -+ ep->attr = ATTR_SUBDIR; -+ -+ else if (type == TYPE_FILE) -+ ep->attr = ATTR_ARCHIVE; -+ -+ else if (type == TYPE_SYMLINK) -+ ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK; -+} -+ -+void exfat_set_entry_type(struct dentry_t *p_entry, u32 type) -+{ -+ struct file_dentry_t *ep = (struct file_dentry_t *) p_entry; -+ -+ if (type == TYPE_UNUSED) { -+ ep->type = 0x0; -+ } else if (type == TYPE_DELETED) { -+ ep->type &= ~0x80; -+ } else if (type == TYPE_STREAM) { -+ ep->type = 0xC0; -+ } else if (type == TYPE_EXTEND) { -+ ep->type = 0xC1; -+ } else if (type == TYPE_BITMAP) { -+ ep->type = 0x81; -+ } else if (type == TYPE_UPCASE) { -+ ep->type = 0x82; -+ } else if (type == TYPE_VOLUME) { -+ ep->type = 0x83; -+ } else if (type == TYPE_DIR) { -+ ep->type = 0x85; -+ SET16_A(ep->attr, ATTR_SUBDIR); -+ } else if (type == TYPE_FILE) { -+ ep->type = 0x85; -+ SET16_A(ep->attr, ATTR_ARCHIVE); -+ } else if (type == TYPE_SYMLINK) { -+ ep->type = 0x85; -+ SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); -+ } -+} -+ -+u32 fat_get_entry_attr(struct dentry_t *p_entry) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *) p_entry; -+ -+ return (u32) ep->attr; -+} -+ -+u32 exfat_get_entry_attr(struct dentry_t *p_entry) -+{ -+ struct file_dentry_t *ep = (struct file_dentry_t *) p_entry; -+ -+ return (u32) GET16_A(ep->attr); -+} -+ -+void fat_set_entry_attr(struct dentry_t *p_entry, u32 attr) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *) p_entry; -+ -+ ep->attr = (u8) attr; -+} -+ -+void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr) -+{ -+ struct file_dentry_t *ep = (struct file_dentry_t *) p_entry; -+ -+ SET16_A(ep->attr, (u16) attr); -+} -+ -+u8 fat_get_entry_flag(struct dentry_t *p_entry) -+{ -+ return 0x01; -+} -+ -+u8 exfat_get_entry_flag(struct dentry_t *p_entry) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *) p_entry; -+ -+ return ep->flags; -+} -+ -+void fat_set_entry_flag(struct dentry_t *p_entry, u8 flags) -+{ -+} -+ -+void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *) p_entry; -+ -+ ep->flags = flags; -+} -+ -+u32 fat_get_entry_clu0(struct dentry_t *p_entry) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *) p_entry; -+ -+ return ((u32)GET16_A(ep->start_clu_hi) << 16) | -+ GET16_A(ep->start_clu_lo); -+} -+ -+u32 exfat_get_entry_clu0(struct dentry_t *p_entry) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *) p_entry; -+ -+ return GET32_A(ep->start_clu); -+} -+ -+void fat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; -+ -+ SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); -+ SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); -+} -+ -+void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -+ -+ SET32_A(ep->start_clu, start_clu); -+} -+ -+u64 fat_get_entry_size(struct dentry_t *p_entry) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; -+ -+ return (u64) GET32_A(ep->size); -+} -+ -+u64 exfat_get_entry_size(struct dentry_t *p_entry) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -+ -+ return GET64_A(ep->valid_size); -+} -+ -+void fat_set_entry_size(struct dentry_t *p_entry, u64 size) -+{ -+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; -+ -+ SET32_A(ep->size, (u32) size); -+} -+ -+void exfat_set_entry_size(struct dentry_t *p_entry, u64 size) -+{ -+ struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; -+ -+ SET64_A(ep->valid_size, size); -+ SET64_A(ep->size, size); -+} -+ -+void fat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode) -+{ -+ u16 t = 0x00, d = 0x21; -+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; -+ -+ switch (mode) { -+ case TM_CREATE: -+ t = GET16_A(ep->create_time); -+ d = GET16_A(ep->create_date); -+ break; -+ case TM_MODIFY: -+ t = GET16_A(ep->modify_time); -+ d = GET16_A(ep->modify_date); -+ break; -+ } -+ -+ tp->sec = (t & 0x001F) << 1; -+ tp->min = (t >> 5) & 0x003F; -+ tp->hour = (t >> 11); -+ tp->day = (d & 0x001F); -+ tp->mon = (d >> 5) & 0x000F; -+ tp->year = (d >> 9); -+} -+ -+void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode) -+{ -+ u16 t = 0x00, d = 0x21; -+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -+ -+ switch (mode) { -+ case TM_CREATE: -+ t = GET16_A(ep->create_time); -+ d = GET16_A(ep->create_date); -+ break; -+ case TM_MODIFY: -+ t = GET16_A(ep->modify_time); -+ d = GET16_A(ep->modify_date); -+ break; -+ case TM_ACCESS: -+ t = GET16_A(ep->access_time); -+ d = GET16_A(ep->access_date); -+ break; -+ } -+ -+ tp->sec = (t & 0x001F) << 1; -+ tp->min = (t >> 5) & 0x003F; -+ tp->hour = (t >> 11); -+ tp->day = (d & 0x001F); -+ tp->mon = (d >> 5) & 0x000F; -+ tp->year = (d >> 9); -+} -+ -+void fat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode) -+{ -+ u16 t, d; -+ struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; -+ -+ t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); -+ d = (tp->year << 9) | (tp->mon << 5) | tp->day; -+ -+ switch (mode) { -+ case TM_CREATE: -+ SET16_A(ep->create_time, t); -+ SET16_A(ep->create_date, d); -+ break; -+ case TM_MODIFY: -+ SET16_A(ep->modify_time, t); -+ SET16_A(ep->modify_date, d); -+ break; -+ } -+} -+ -+void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, -+ u8 mode) -+{ -+ u16 t, d; -+ struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; -+ -+ t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); -+ d = (tp->year << 9) | (tp->mon << 5) | tp->day; -+ -+ switch (mode) { -+ case TM_CREATE: -+ SET16_A(ep->create_time, t); -+ SET16_A(ep->create_date, d); -+ break; -+ case TM_MODIFY: -+ SET16_A(ep->modify_time, t); -+ SET16_A(ep->modify_date, d); -+ break; -+ case TM_ACCESS: -+ SET16_A(ep->access_time, t); -+ SET16_A(ep->access_date, d); -+ break; -+ } -+} -+ -+s32 fat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, s32 entry, -+ u32 type, u32 start_clu, u64 size) -+{ -+ sector_t sector; -+ struct dos_dentry_t *dos_ep; -+ -+ dos_ep = (struct dos_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ §or); -+ if (!dos_ep) -+ return FFS_MEDIAERR; -+ -+ init_dos_entry(dos_ep, type, start_clu); -+ buf_modify(sb, sector); -+ -+ return FFS_SUCCESS; -+} -+ -+s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, u32 type, u32 start_clu, u64 size) -+{ -+ sector_t sector; -+ u8 flags; -+ struct file_dentry_t *file_ep; -+ struct strm_dentry_t *strm_ep; -+ -+ flags = (type == TYPE_FILE) ? 0x01 : 0x03; -+ -+ /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ -+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ §or); -+ if (!file_ep) -+ return FFS_MEDIAERR; -+ -+ strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry+1, -+ §or); -+ if (!strm_ep) -+ return FFS_MEDIAERR; -+ -+ init_file_entry(file_ep, type); -+ buf_modify(sb, sector); -+ -+ init_strm_entry(strm_ep, flags, start_clu, size); -+ buf_modify(sb, sector); -+ -+ return FFS_SUCCESS; -+} -+ -+static s32 fat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 num_entries, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname) -+{ -+ int i; -+ sector_t sector; -+ u8 chksum; -+ u16 *uniname = p_uniname->name; -+ struct dos_dentry_t *dos_ep; -+ struct ext_dentry_t *ext_ep; -+ -+ dos_ep = (struct dos_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ §or); -+ if (!dos_ep) -+ return FFS_MEDIAERR; -+ -+ dos_ep->lcase = p_dosname->name_case; -+ memcpy(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH); -+ buf_modify(sb, sector); -+ -+ if ((--num_entries) > 0) { -+ chksum = calc_checksum_1byte((void *)dos_ep->name, -+ DOS_NAME_LENGTH, 0); -+ -+ for (i = 1; i < num_entries; i++) { -+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb, -+ p_dir, -+ entry - i, -+ §or); -+ if (!ext_ep) -+ return FFS_MEDIAERR; -+ -+ init_ext_entry(ext_ep, i, chksum, uniname); -+ buf_modify(sb, sector); -+ uniname += 13; -+ } -+ -+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir, -+ entry - i, -+ §or); -+ if (!ext_ep) -+ return FFS_MEDIAERR; -+ -+ init_ext_entry(ext_ep, i+0x40, chksum, uniname); -+ buf_modify(sb, sector); -+ } -+ -+ return FFS_SUCCESS; -+} -+ -+static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 num_entries, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname) -+{ -+ int i; -+ sector_t sector; -+ u16 *uniname = p_uniname->name; -+ struct file_dentry_t *file_ep; -+ struct strm_dentry_t *strm_ep; -+ struct name_dentry_t *name_ep; -+ -+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ §or); -+ if (!file_ep) -+ return FFS_MEDIAERR; -+ -+ file_ep->num_ext = (u8)(num_entries - 1); -+ buf_modify(sb, sector); -+ -+ strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry+1, -+ §or); -+ if (!strm_ep) -+ return FFS_MEDIAERR; -+ -+ strm_ep->name_len = p_uniname->name_len; -+ SET16_A(strm_ep->name_hash, p_uniname->name_hash); -+ buf_modify(sb, sector); -+ -+ for (i = 2; i < num_entries; i++) { -+ name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir, -+ entry + i, -+ §or); -+ if (!name_ep) -+ return FFS_MEDIAERR; -+ -+ init_name_entry(name_ep, uniname); -+ buf_modify(sb, sector); -+ uniname += 15; -+ } -+ -+ update_dir_checksum(sb, p_dir, entry); -+ -+ return FFS_SUCCESS; -+} -+ -+void init_dos_entry(struct dos_dentry_t *ep, u32 type, u32 start_clu) -+{ -+ struct timestamp_t tm, *tp; -+ -+ fat_set_entry_type((struct dentry_t *) ep, type); -+ SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); -+ SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); -+ SET32_A(ep->size, 0); -+ -+ tp = tm_current(&tm); -+ fat_set_entry_time((struct dentry_t *) ep, tp, TM_CREATE); -+ fat_set_entry_time((struct dentry_t *) ep, tp, TM_MODIFY); -+ SET16_A(ep->access_date, 0); -+ ep->create_time_ms = 0; -+} -+ -+void init_ext_entry(struct ext_dentry_t *ep, s32 order, u8 chksum, u16 *uniname) -+{ -+ int i; -+ u8 end = FALSE; -+ -+ fat_set_entry_type((struct dentry_t *) ep, TYPE_EXTEND); -+ ep->order = (u8) order; -+ ep->sysid = 0; -+ ep->checksum = chksum; -+ SET16_A(ep->start_clu, 0); -+ -+ for (i = 0; i < 10; i += 2) { -+ if (!end) { -+ SET16(ep->unicode_0_4+i, *uniname); -+ if (*uniname == 0x0) -+ end = TRUE; -+ else -+ uniname++; -+ } else { -+ SET16(ep->unicode_0_4+i, 0xFFFF); -+ } -+ } -+ -+ for (i = 0; i < 12; i += 2) { -+ if (!end) { -+ SET16_A(ep->unicode_5_10 + i, *uniname); -+ if (*uniname == 0x0) -+ end = TRUE; -+ else -+ uniname++; -+ } else { -+ SET16_A(ep->unicode_5_10 + i, 0xFFFF); -+ } -+ } -+ -+ for (i = 0; i < 4; i += 2) { -+ if (!end) { -+ SET16_A(ep->unicode_11_12 + i, *uniname); -+ if (*uniname == 0x0) -+ end = TRUE; -+ else -+ uniname++; -+ } else { -+ SET16_A(ep->unicode_11_12 + i, 0xFFFF); -+ } -+ } -+} -+ -+void init_file_entry(struct file_dentry_t *ep, u32 type) -+{ -+ struct timestamp_t tm, *tp; -+ -+ exfat_set_entry_type((struct dentry_t *)ep, type); -+ -+ tp = tm_current(&tm); -+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE); -+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY); -+ exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS); -+ ep->create_time_ms = 0; -+ ep->modify_time_ms = 0; -+ ep->access_time_ms = 0; -+} -+ -+void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size) -+{ -+ exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM); -+ ep->flags = flags; -+ SET32_A(ep->start_clu, start_clu); -+ SET64_A(ep->valid_size, size); -+ SET64_A(ep->size, size); -+} -+ -+void init_name_entry(struct name_dentry_t *ep, u16 *uniname) -+{ -+ int i; -+ -+ exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND); -+ ep->flags = 0x0; -+ -+ for (i = 0; i < 30; i++, i++) { -+ SET16_A(ep->unicode_0_14+i, *uniname); -+ if (*uniname == 0x0) -+ break; -+ uniname++; -+ } -+} -+ -+void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 order, s32 num_entries) -+{ -+ int i; -+ sector_t sector; -+ struct dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ for (i = num_entries-1; i >= order; i--) { -+ ep = get_entry_in_dir(sb, p_dir, entry-i, §or); -+ if (!ep) -+ return; -+ -+ p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); -+ buf_modify(sb, sector); -+ } -+} -+ -+void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, s32 order, s32 num_entries) -+{ -+ int i; -+ sector_t sector; -+ struct dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ for (i = order; i < num_entries; i++) { -+ ep = get_entry_in_dir(sb, p_dir, entry+i, §or); -+ if (!ep) -+ return; -+ -+ p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); -+ buf_modify(sb, sector); -+ } -+} -+ -+void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry) -+{ -+ int i, num_entries; -+ sector_t sector; -+ u16 chksum; -+ struct file_dentry_t *file_ep; -+ struct dentry_t *ep; -+ -+ file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ §or); -+ if (!file_ep) -+ return; -+ -+ buf_lock(sb, sector); -+ -+ num_entries = (s32) file_ep->num_ext + 1; -+ chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0, -+ CS_DIR_ENTRY); -+ -+ for (i = 1; i < num_entries; i++) { -+ ep = get_entry_in_dir(sb, p_dir, entry+i, NULL); -+ if (!ep) { -+ buf_unlock(sb, sector); -+ return; -+ } -+ -+ chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -+ CS_DEFAULT); -+ } -+ -+ SET16_A(file_ep->checksum, chksum); -+ buf_modify(sb, sector); -+ buf_unlock(sb, sector); -+} -+ -+void update_dir_checksum_with_entry_set(struct super_block *sb, -+ struct entry_set_cache_t *es) -+{ -+ struct dentry_t *ep; -+ u16 chksum = 0; -+ s32 chksum_type = CS_DIR_ENTRY, i; -+ -+ ep = (struct dentry_t *)&(es->__buf); -+ for (i = 0; i < es->num_entries; i++) { -+ pr_debug("%s ep %p\n", __func__, ep); -+ chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, -+ chksum_type); -+ ep++; -+ chksum_type = CS_DEFAULT; -+ } -+ -+ ep = (struct dentry_t *)&(es->__buf); -+ SET16_A(((struct file_dentry_t *)ep)->checksum, chksum); -+ write_whole_entry_set(sb, es); -+} -+ -+static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir, -+ s32 byte_offset, u32 *clu) -+{ -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ s32 clu_offset; -+ u32 cur_clu; -+ -+ clu_offset = byte_offset >> p_fs->cluster_size_bits; -+ cur_clu = p_dir->dir; -+ -+ if (p_dir->flags == 0x03) { -+ cur_clu += clu_offset; -+ } else { -+ while (clu_offset > 0) { -+ if (FAT_read(sb, cur_clu, &cur_clu) == -1) -+ return FFS_MEDIAERR; -+ clu_offset--; -+ } -+ } -+ -+ if (clu) -+ *clu = cur_clu; -+ return FFS_SUCCESS; -+} -+ -+s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, -+ sector_t *sector, s32 *offset) -+{ -+ s32 off, ret; -+ u32 clu = 0; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ off = entry << DENTRY_SIZE_BITS; -+ -+ if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -+ *offset = off & p_bd->sector_size_mask; -+ *sector = off >> p_bd->sector_size_bits; -+ *sector += p_fs->root_start_sector; -+ } else { -+ ret = _walk_fat_chain(sb, p_dir, off, &clu); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ /* byte offset in cluster */ -+ off &= p_fs->cluster_size - 1; -+ -+ /* byte offset in sector */ -+ *offset = off & p_bd->sector_size_mask; -+ -+ /* sector offset in cluster */ -+ *sector = off >> p_bd->sector_size_bits; -+ *sector += START_SECTOR(clu); -+ } -+ return FFS_SUCCESS; -+} -+ -+struct dentry_t *get_entry_with_sector(struct super_block *sb, sector_t sector, -+ s32 offset) -+{ -+ u8 *buf; -+ -+ buf = buf_getblk(sb, sector); -+ -+ if (buf == NULL) -+ return NULL; -+ -+ return (struct dentry_t *)(buf + offset); -+} -+ -+struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, sector_t *sector) -+{ -+ s32 off; -+ sector_t sec; -+ u8 *buf; -+ -+ if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS) -+ return NULL; -+ -+ buf = buf_getblk(sb, sec); -+ -+ if (buf == NULL) -+ return NULL; -+ -+ if (sector != NULL) -+ *sector = sec; -+ return (struct dentry_t *)(buf + off); -+} -+ -+/* returns a set of dentries for a file or dir. -+ * Note that this is a copy (dump) of dentries so that user should call write_entry_set() -+ * to apply changes made in this entry set to the real device. -+ * in: -+ * sb+p_dir+entry: indicates a file/dir -+ * type: specifies how many dentries should be included. -+ * out: -+ * file_ep: will point the first dentry(= file dentry) on success -+ * return: -+ * pointer of entry set on success, -+ * NULL on failure. -+ */ -+ -+#define ES_MODE_STARTED 0 -+#define ES_MODE_GET_FILE_ENTRY 1 -+#define ES_MODE_GET_STRM_ENTRY 2 -+#define ES_MODE_GET_NAME_ENTRY 3 -+#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 -+struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u32 type, -+ struct dentry_t **file_ep) -+{ -+ s32 off, ret, byte_offset; -+ u32 clu = 0; -+ sector_t sec; -+ u32 entry_type; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct entry_set_cache_t *es = NULL; -+ struct dentry_t *ep, *pos; -+ u8 *buf; -+ u8 num_entries; -+ s32 mode = ES_MODE_STARTED; -+ size_t bufsize; -+ -+ pr_debug("%s entered p_dir dir %u flags %x size %d\n", -+ __func__, p_dir->dir, p_dir->flags, p_dir->size); -+ -+ byte_offset = entry << DENTRY_SIZE_BITS; -+ ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); -+ if (ret != FFS_SUCCESS) -+ return NULL; -+ -+ -+ /* byte offset in cluster */ -+ byte_offset &= p_fs->cluster_size - 1; -+ -+ /* byte offset in sector */ -+ off = byte_offset & p_bd->sector_size_mask; -+ -+ /* sector offset in cluster */ -+ sec = byte_offset >> p_bd->sector_size_bits; -+ sec += START_SECTOR(clu); -+ -+ buf = buf_getblk(sb, sec); -+ if (buf == NULL) -+ goto err_out; -+ -+ -+ ep = (struct dentry_t *)(buf + off); -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ -+ if ((entry_type != TYPE_FILE) -+ && (entry_type != TYPE_DIR)) -+ goto err_out; -+ -+ if (type == ES_ALL_ENTRIES) -+ num_entries = ((struct file_dentry_t *)ep)->num_ext+1; -+ else -+ num_entries = type; -+ -+ bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) * -+ sizeof(struct dentry_t); -+ pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__, -+ bufsize, num_entries); -+ es = kmalloc(bufsize, GFP_KERNEL); -+ if (es == NULL) -+ goto err_out; -+ -+ es->num_entries = num_entries; -+ es->sector = sec; -+ es->offset = off; -+ es->alloc_flag = p_dir->flags; -+ -+ pos = (struct dentry_t *) &(es->__buf); -+ -+ while (num_entries) { -+ /* -+ * instead of copying whole sector, we will check every entry. -+ * this will provide minimum stablity and consistancy. -+ */ -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ -+ if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) -+ goto err_out; -+ -+ switch (mode) { -+ case ES_MODE_STARTED: -+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) -+ mode = ES_MODE_GET_FILE_ENTRY; -+ else -+ goto err_out; -+ break; -+ case ES_MODE_GET_FILE_ENTRY: -+ if (entry_type == TYPE_STREAM) -+ mode = ES_MODE_GET_STRM_ENTRY; -+ else -+ goto err_out; -+ break; -+ case ES_MODE_GET_STRM_ENTRY: -+ if (entry_type == TYPE_EXTEND) -+ mode = ES_MODE_GET_NAME_ENTRY; -+ else -+ goto err_out; -+ break; -+ case ES_MODE_GET_NAME_ENTRY: -+ if (entry_type == TYPE_EXTEND) -+ break; -+ else if (entry_type == TYPE_STREAM) -+ goto err_out; -+ else if (entry_type & TYPE_CRITICAL_SEC) -+ mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; -+ else -+ goto err_out; -+ break; -+ case ES_MODE_GET_CRITICAL_SEC_ENTRY: -+ if ((entry_type == TYPE_EXTEND) || -+ (entry_type == TYPE_STREAM)) -+ goto err_out; -+ else if ((entry_type & TYPE_CRITICAL_SEC) != -+ TYPE_CRITICAL_SEC) -+ goto err_out; -+ break; -+ } -+ -+ memcpy(pos, ep, sizeof(struct dentry_t)); -+ -+ if (--num_entries == 0) -+ break; -+ -+ if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < -+ (off & p_bd->sector_size_mask)) { -+ /* get the next sector */ -+ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -+ if (es->alloc_flag == 0x03) { -+ clu++; -+ } else { -+ if (FAT_read(sb, clu, &clu) == -1) -+ goto err_out; -+ } -+ sec = START_SECTOR(clu); -+ } else { -+ sec++; -+ } -+ buf = buf_getblk(sb, sec); -+ if (buf == NULL) -+ goto err_out; -+ off = 0; -+ ep = (struct dentry_t *)(buf); -+ } else { -+ ep++; -+ off += DENTRY_SIZE; -+ } -+ pos++; -+ } -+ -+ if (file_ep) -+ *file_ep = (struct dentry_t *)&(es->__buf); -+ -+ pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", -+ __func__, es, (unsigned long long)es->sector, es->offset, -+ es->alloc_flag, es->num_entries, &es->__buf); -+ return es; -+err_out: -+ pr_debug("%s exited NULL (es %p)\n", __func__, es); -+ kfree(es); -+ return NULL; -+} -+ -+void release_entry_set(struct entry_set_cache_t *es) -+{ -+ pr_debug("%s es=%p\n", __func__, es); -+ kfree(es); -+} -+ -+ -+static s32 __write_partial_entries_in_entry_set(struct super_block *sb, -+ struct entry_set_cache_t *es, -+ sector_t sec, s32 off, u32 count) -+{ -+ s32 num_entries, buf_off = (off - es->offset); -+ u32 remaining_byte_in_sector, copy_entries; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ u32 clu; -+ u8 *buf, *esbuf = (u8 *)&(es->__buf); -+ -+ pr_debug("%s entered es %p sec %llu off %d count %d\n", -+ __func__, es, (unsigned long long)sec, off, count); -+ num_entries = count; -+ -+ while (num_entries) { -+ /* white per sector base */ -+ remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; -+ copy_entries = min_t(s32, -+ remaining_byte_in_sector >> DENTRY_SIZE_BITS, -+ num_entries); -+ buf = buf_getblk(sb, sec); -+ if (buf == NULL) -+ goto err_out; -+ pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off); -+ pr_debug("copying %d entries from %p to sector %llu\n", -+ copy_entries, (esbuf + buf_off), -+ (unsigned long long)sec); -+ memcpy(buf + off, esbuf + buf_off, -+ copy_entries << DENTRY_SIZE_BITS); -+ buf_modify(sb, sec); -+ num_entries -= copy_entries; -+ -+ if (num_entries) { -+ /* get next sector */ -+ if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { -+ clu = GET_CLUSTER_FROM_SECTOR(sec); -+ if (es->alloc_flag == 0x03) { -+ clu++; -+ } else { -+ if (FAT_read(sb, clu, &clu) == -1) -+ goto err_out; -+ } -+ sec = START_SECTOR(clu); -+ } else { -+ sec++; -+ } -+ off = 0; -+ buf_off += copy_entries << DENTRY_SIZE_BITS; -+ } -+ } -+ -+ pr_debug("%s exited successfully\n", __func__); -+ return FFS_SUCCESS; -+err_out: -+ pr_debug("%s failed\n", __func__); -+ return FFS_ERROR; -+} -+ -+/* write back all entries in entry set */ -+s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es) -+{ -+ return __write_partial_entries_in_entry_set(sb, es, es->sector, -+ es->offset, -+ es->num_entries); -+} -+ -+/* write back some entries in entry set */ -+s32 write_partial_entries_in_entry_set(struct super_block *sb, -+ struct entry_set_cache_t *es, struct dentry_t *ep, u32 count) -+{ -+ s32 ret, byte_offset, off; -+ u32 clu = 0; -+ sector_t sec; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct chain_t dir; -+ -+ /* vaidity check */ -+ if (ep + count > ((struct dentry_t *)&(es->__buf)) + es->num_entries) -+ return FFS_ERROR; -+ -+ dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); -+ dir.flags = es->alloc_flag; -+ dir.size = 0xffffffff; /* XXX */ -+ -+ byte_offset = (es->sector - START_SECTOR(dir.dir)) << -+ p_bd->sector_size_bits; -+ byte_offset += ((void **)ep - &(es->__buf)) + es->offset; -+ -+ ret = _walk_fat_chain(sb, &dir, byte_offset, &clu); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ /* byte offset in cluster */ -+ byte_offset &= p_fs->cluster_size - 1; -+ -+ /* byte offset in sector */ -+ off = byte_offset & p_bd->sector_size_mask; -+ -+ /* sector offset in cluster */ -+ sec = byte_offset >> p_bd->sector_size_bits; -+ sec += START_SECTOR(clu); -+ return __write_partial_entries_in_entry_set(sb, es, sec, off, count); -+} -+ -+/* search EMPTY CONTINUOUS "num_entries" entries */ -+s32 search_deleted_or_unused_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 num_entries) -+{ -+ int i, dentry, num_empty = 0; -+ s32 dentries_per_clu; -+ u32 type; -+ struct chain_t clu; -+ struct dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ if (p_fs->hint_uentry.dir == p_dir->dir) { -+ if (p_fs->hint_uentry.entry == -1) -+ return -1; -+ -+ clu.dir = p_fs->hint_uentry.clu.dir; -+ clu.size = p_fs->hint_uentry.clu.size; -+ clu.flags = p_fs->hint_uentry.clu.flags; -+ -+ dentry = p_fs->hint_uentry.entry; -+ } else { -+ p_fs->hint_uentry.entry = -1; -+ -+ clu.dir = p_dir->dir; -+ clu.size = p_dir->size; -+ clu.flags = p_dir->flags; -+ -+ dentry = 0; -+ } -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ i = dentry % dentries_per_clu; -+ else -+ i = dentry & (dentries_per_clu-1); -+ -+ for (; i < dentries_per_clu; i++, dentry++) { -+ ep = get_entry_in_dir(sb, &clu, i, NULL); -+ if (!ep) -+ return -1; -+ -+ type = p_fs->fs_func->get_entry_type(ep); -+ -+ if (type == TYPE_UNUSED) { -+ num_empty++; -+ if (p_fs->hint_uentry.entry == -1) { -+ p_fs->hint_uentry.dir = p_dir->dir; -+ p_fs->hint_uentry.entry = dentry; -+ -+ p_fs->hint_uentry.clu.dir = clu.dir; -+ p_fs->hint_uentry.clu.size = clu.size; -+ p_fs->hint_uentry.clu.flags = clu.flags; -+ } -+ } else if (type == TYPE_DELETED) { -+ num_empty++; -+ } else { -+ num_empty = 0; -+ } -+ -+ if (num_empty >= num_entries) { -+ p_fs->hint_uentry.dir = CLUSTER_32(~0); -+ p_fs->hint_uentry.entry = -1; -+ -+ if (p_fs->vol_type == EXFAT) -+ return dentry - (num_entries-1); -+ else -+ return dentry; -+ } -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (clu.flags == 0x03) { -+ if ((--clu.size) > 0) -+ clu.dir++; -+ else -+ clu.dir = CLUSTER_32(~0); -+ } else { -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return -1; -+ } -+ } -+ -+ return -1; -+} -+ -+s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries) -+{ -+ s32 ret, dentry; -+ u32 last_clu; -+ sector_t sector; -+ u64 size = 0; -+ struct chain_t clu; -+ struct dentry_t *ep = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ return search_deleted_or_unused_entry(sb, p_dir, num_entries); -+ -+ while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ if (p_fs->vol_type == EXFAT) { -+ if (p_dir->dir != p_fs->root_dir) -+ size = i_size_read(inode); -+ } -+ -+ last_clu = find_last_cluster(sb, p_dir); -+ clu.dir = last_clu + 1; -+ clu.size = 0; -+ clu.flags = p_dir->flags; -+ -+ /* (1) allocate a cluster */ -+ ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); -+ if (ret < 1) -+ return -1; -+ -+ if (clear_cluster(sb, clu.dir) != FFS_SUCCESS) -+ return -1; -+ -+ /* (2) append to the FAT chain */ -+ if (clu.flags != p_dir->flags) { -+ exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); -+ p_dir->flags = 0x01; -+ p_fs->hint_uentry.clu.flags = 0x01; -+ } -+ if (clu.flags == 0x01) -+ if (FAT_write(sb, last_clu, clu.dir) < 0) -+ return -1; -+ -+ if (p_fs->hint_uentry.entry == -1) { -+ p_fs->hint_uentry.dir = p_dir->dir; -+ p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); -+ -+ p_fs->hint_uentry.clu.dir = clu.dir; -+ p_fs->hint_uentry.clu.size = 0; -+ p_fs->hint_uentry.clu.flags = clu.flags; -+ } -+ p_fs->hint_uentry.clu.size++; -+ p_dir->size++; -+ -+ /* (3) update the directory entry */ -+ if (p_fs->vol_type == EXFAT) { -+ if (p_dir->dir != p_fs->root_dir) { -+ size += p_fs->cluster_size; -+ -+ ep = get_entry_in_dir(sb, &fid->dir, -+ fid->entry + 1, §or); -+ if (!ep) -+ return -1; -+ p_fs->fs_func->set_entry_size(ep, size); -+ p_fs->fs_func->set_entry_flag(ep, p_dir->flags); -+ buf_modify(sb, sector); -+ -+ update_dir_checksum(sb, &(fid->dir), -+ fid->entry); -+ } -+ } -+ -+ i_size_write(inode, i_size_read(inode)+p_fs->cluster_size); -+ EXFAT_I(inode)->mmu_private += p_fs->cluster_size; -+ EXFAT_I(inode)->fid.size += p_fs->cluster_size; -+ EXFAT_I(inode)->fid.flags = p_dir->flags; -+ inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); -+ } -+ -+ return dentry; -+} -+ -+/* return values of fat_find_dir_entry() -+ * >= 0 : return dir entiry position with the name in dir -+ * -1 : (root dir, ".") it is the root dir itself -+ * -2 : entry with the name does not exist -+ */ -+s32 fat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 num_entries, -+ struct dos_name_t *p_dosname, u32 type) -+{ -+ int i, dentry = 0, lossy = FALSE, len; -+ s32 order = 0, is_feasible_entry = TRUE, has_ext_entry = FALSE; -+ s32 dentries_per_clu; -+ u32 entry_type; -+ u16 entry_uniname[14], *uniname = NULL, unichar; -+ struct chain_t clu; -+ struct dentry_t *ep; -+ struct dos_dentry_t *dos_ep; -+ struct ext_dentry_t *ext_ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_dir->dir == p_fs->root_dir) { -+ if ((!nls_uniname_cmp(sb, p_uniname->name, -+ (u16 *)UNI_CUR_DIR_NAME)) || -+ (!nls_uniname_cmp(sb, p_uniname->name, -+ (u16 *)UNI_PAR_DIR_NAME))) -+ return -1; // special case, root directory itself -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ clu.dir = p_dir->dir; -+ clu.flags = p_dir->flags; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ for (i = 0; i < dentries_per_clu; i++, dentry++) { -+ ep = get_entry_in_dir(sb, &clu, i, NULL); -+ if (!ep) -+ return -2; -+ -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ -+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { -+ if ((type == TYPE_ALL) || (type == entry_type)) { -+ if (is_feasible_entry && has_ext_entry) -+ return dentry; -+ -+ dos_ep = (struct dos_dentry_t *) ep; -+ if ((!lossy) && (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))) -+ return dentry; -+ } -+ is_feasible_entry = TRUE; -+ has_ext_entry = FALSE; -+ } else if (entry_type == TYPE_EXTEND) { -+ if (is_feasible_entry) { -+ ext_ep = (struct ext_dentry_t *) ep; -+ if (ext_ep->order > 0x40) { -+ order = (s32)(ext_ep->order - 0x40); -+ uniname = p_uniname->name + 13 * (order-1); -+ } else { -+ order = (s32) ext_ep->order; -+ uniname -= 13; -+ } -+ -+ len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order); -+ -+ unichar = *(uniname+len); -+ *(uniname+len) = 0x0; -+ -+ if (nls_uniname_cmp(sb, uniname, entry_uniname)) -+ is_feasible_entry = FALSE; -+ -+ *(uniname+len) = unichar; -+ } -+ has_ext_entry = TRUE; -+ } else if (entry_type == TYPE_UNUSED) { -+ return -2; -+ } -+ is_feasible_entry = TRUE; -+ has_ext_entry = FALSE; -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return -2; -+ } -+ -+ return -2; -+} -+ -+/* return values of exfat_find_dir_entry() -+ * >= 0 : return dir entiry position with the name in dir -+ * -1 : (root dir, ".") it is the root dir itself -+ * -2 : entry with the name does not exist -+ */ -+s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 num_entries, -+ struct dos_name_t *p_dosname, u32 type) -+{ -+ int i = 0, dentry = 0, num_ext_entries = 0, len, step; -+ s32 order = 0, is_feasible_entry = FALSE; -+ s32 dentries_per_clu, num_empty = 0; -+ u32 entry_type; -+ u16 entry_uniname[16], *uniname = NULL, unichar; -+ struct chain_t clu; -+ struct dentry_t *ep; -+ struct file_dentry_t *file_ep; -+ struct strm_dentry_t *strm_ep; -+ struct name_dentry_t *name_ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_dir->dir == p_fs->root_dir) { -+ if ((!nls_uniname_cmp(sb, p_uniname->name, -+ (u16 *)UNI_CUR_DIR_NAME)) || -+ (!nls_uniname_cmp(sb, p_uniname->name, -+ (u16 *)UNI_PAR_DIR_NAME))) -+ return -1; // special case, root directory itself -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ clu.dir = p_dir->dir; -+ clu.size = p_dir->size; -+ clu.flags = p_dir->flags; -+ -+ p_fs->hint_uentry.dir = p_dir->dir; -+ p_fs->hint_uentry.entry = -1; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ while (i < dentries_per_clu) { -+ ep = get_entry_in_dir(sb, &clu, i, NULL); -+ if (!ep) -+ return -2; -+ -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ step = 1; -+ -+ if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { -+ is_feasible_entry = FALSE; -+ -+ if (p_fs->hint_uentry.entry == -1) { -+ num_empty++; -+ -+ if (num_empty == 1) { -+ p_fs->hint_uentry.clu.dir = clu.dir; -+ p_fs->hint_uentry.clu.size = clu.size; -+ p_fs->hint_uentry.clu.flags = clu.flags; -+ } -+ if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) -+ p_fs->hint_uentry.entry = dentry - (num_empty-1); -+ } -+ -+ if (entry_type == TYPE_UNUSED) -+ return -2; -+ } else { -+ num_empty = 0; -+ -+ if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { -+ file_ep = (struct file_dentry_t *) ep; -+ if ((type == TYPE_ALL) || (type == entry_type)) { -+ num_ext_entries = file_ep->num_ext; -+ is_feasible_entry = TRUE; -+ } else { -+ is_feasible_entry = FALSE; -+ step = file_ep->num_ext + 1; -+ } -+ } else if (entry_type == TYPE_STREAM) { -+ if (is_feasible_entry) { -+ strm_ep = (struct strm_dentry_t *)ep; -+ if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && -+ p_uniname->name_len == strm_ep->name_len) { -+ order = 1; -+ } else { -+ is_feasible_entry = FALSE; -+ step = num_ext_entries; -+ } -+ } -+ } else if (entry_type == TYPE_EXTEND) { -+ if (is_feasible_entry) { -+ name_ep = (struct name_dentry_t *)ep; -+ -+ if ((++order) == 2) -+ uniname = p_uniname->name; -+ else -+ uniname += 15; -+ -+ len = extract_uni_name_from_name_entry(name_ep, -+ entry_uniname, order); -+ -+ unichar = *(uniname+len); -+ *(uniname+len) = 0x0; -+ -+ if (nls_uniname_cmp(sb, uniname, entry_uniname)) { -+ is_feasible_entry = FALSE; -+ step = num_ext_entries - order + 1; -+ } else if (order == num_ext_entries) { -+ p_fs->hint_uentry.dir = CLUSTER_32(~0); -+ p_fs->hint_uentry.entry = -1; -+ return dentry - (num_ext_entries); -+ } -+ -+ *(uniname+len) = unichar; -+ } -+ } else { -+ is_feasible_entry = FALSE; -+ } -+ } -+ -+ i += step; -+ dentry += step; -+ } -+ -+ i -= dentries_per_clu; -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (clu.flags == 0x03) { -+ if ((--clu.size) > 0) -+ clu.dir++; -+ else -+ clu.dir = CLUSTER_32(~0); -+ } else { -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return -2; -+ } -+ } -+ -+ return -2; -+} -+ -+s32 fat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, struct dentry_t *p_entry) -+{ -+ s32 count = 0; -+ u8 chksum; -+ struct dos_dentry_t *dos_ep = (struct dos_dentry_t *) p_entry; -+ struct ext_dentry_t *ext_ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); -+ -+ for (entry--; entry >= 0; entry--) { -+ ext_ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir, -+ entry, NULL); -+ if (!ext_ep) -+ return -1; -+ -+ if ((p_fs->fs_func->get_entry_type((struct dentry_t *)ext_ep) == -+ TYPE_EXTEND) && (ext_ep->checksum == chksum)) { -+ count++; -+ if (ext_ep->order > 0x40) -+ return count; -+ } else { -+ return count; -+ } -+ } -+ -+ return count; -+} -+ -+s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, -+ s32 entry, struct dentry_t *p_entry) -+{ -+ int i, count = 0; -+ u32 type; -+ struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry; -+ struct dentry_t *ext_ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { -+ ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); -+ if (!ext_ep) -+ return -1; -+ -+ type = p_fs->fs_func->get_entry_type(ext_ep); -+ if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) -+ count++; -+ else -+ return count; -+ } -+ -+ return count; -+} -+ -+s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, -+ u32 type) -+{ -+ int i, count = 0; -+ s32 dentries_per_clu; -+ u32 entry_type; -+ struct chain_t clu; -+ struct dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ clu.dir = p_dir->dir; -+ clu.size = p_dir->size; -+ clu.flags = p_dir->flags; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = get_entry_in_dir(sb, &clu, i, NULL); -+ if (!ep) -+ return -1; -+ -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ -+ if (entry_type == TYPE_UNUSED) -+ return count; -+ if (!(type & TYPE_CRITICAL_PRI) && -+ !(type & TYPE_BENIGN_PRI)) -+ continue; -+ -+ if ((type == TYPE_ALL) || (type == entry_type)) -+ count++; -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (clu.flags == 0x03) { -+ if ((--clu.size) > 0) -+ clu.dir++; -+ else -+ clu.dir = CLUSTER_32(~0); -+ } else { -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return -1; -+ } -+ } -+ -+ return count; -+} -+ -+bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir) -+{ -+ int i, count = 0; -+ s32 dentries_per_clu; -+ u32 type; -+ struct chain_t clu; -+ struct dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ clu.dir = p_dir->dir; -+ clu.size = p_dir->size; -+ clu.flags = p_dir->flags; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = get_entry_in_dir(sb, &clu, i, NULL); -+ if (!ep) -+ break; -+ -+ type = p_fs->fs_func->get_entry_type(ep); -+ -+ if (type == TYPE_UNUSED) -+ return TRUE; -+ if ((type != TYPE_FILE) && (type != TYPE_DIR)) -+ continue; -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ return FALSE; -+ -+ if (p_fs->vol_type == EXFAT) -+ return FALSE; -+ if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) -+ return FALSE; -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (clu.flags == 0x03) { -+ if ((--clu.size) > 0) -+ clu.dir++; -+ else -+ clu.dir = CLUSTER_32(~0); -+ } -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ break; -+ } -+ -+ return TRUE; -+} -+ -+/* -+ * Name Conversion Functions -+ */ -+ -+/* input : dir, uni_name -+ * output : num_of_entry, dos_name(format : aaaaaa~1.bbb) -+ */ -+s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, s32 *entries, -+ struct dos_name_t *p_dosname) -+{ -+ s32 ret, num_entries; -+ bool lossy = false; -+ char **r; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ num_entries = p_fs->fs_func->calc_num_entries(p_uniname); -+ if (num_entries == 0) -+ return FFS_INVALIDPATH; -+ -+ if (p_fs->vol_type != EXFAT) { -+ nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy); -+ -+ if (lossy) { -+ ret = fat_generate_dos_name(sb, p_dir, p_dosname); -+ if (ret) -+ return ret; -+ } else { -+ for (r = reserved_names; *r; r++) { -+ if (!strncmp((void *)p_dosname->name, *r, 8)) -+ return FFS_INVALIDPATH; -+ } -+ -+ if (p_dosname->name_case != 0xFF) -+ num_entries = 1; -+ } -+ -+ if (num_entries > 1) -+ p_dosname->name_case = 0x0; -+ } -+ -+ *entries = num_entries; -+ -+ return FFS_SUCCESS; -+} -+ -+void get_uni_name_from_dos_entry(struct super_block *sb, -+ struct dos_dentry_t *ep, -+ struct uni_name_t *p_uniname, u8 mode) -+{ -+ struct dos_name_t dos_name; -+ -+ if (mode == 0x0) -+ dos_name.name_case = 0x0; -+ else -+ dos_name.name_case = ep->lcase; -+ -+ memcpy(dos_name.name, ep->name, DOS_NAME_LENGTH); -+ nls_dosname_to_uniname(sb, p_uniname, &dos_name); -+} -+ -+void fat_get_uni_name_from_ext_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u16 *uniname) -+{ -+ int i; -+ struct ext_dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ for (entry--, i = 1; entry >= 0; entry--, i++) { -+ ep = (struct ext_dentry_t *)get_entry_in_dir(sb, p_dir, entry, -+ NULL); -+ if (!ep) -+ return; -+ -+ if (p_fs->fs_func->get_entry_type((struct dentry_t *)ep) == -+ TYPE_EXTEND) { -+ extract_uni_name_from_ext_entry(ep, uniname, i); -+ if (ep->order > 0x40) -+ return; -+ } else { -+ return; -+ } -+ -+ uniname += 13; -+ } -+} -+ -+void exfat_get_uni_name_from_ext_entry(struct super_block *sb, -+ struct chain_t *p_dir, s32 entry, -+ u16 *uniname) -+{ -+ int i; -+ struct dentry_t *ep; -+ struct entry_set_cache_t *es; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); -+ if (es == NULL || es->num_entries < 3) { -+ if (es) -+ release_entry_set(es); -+ return; -+ } -+ -+ ep += 2; -+ -+ /* -+ * First entry : file entry -+ * Second entry : stream-extension entry -+ * Third entry : first file-name entry -+ * So, the index of first file-name dentry should start from 2. -+ */ -+ for (i = 2; i < es->num_entries; i++, ep++) { -+ if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) -+ extract_uni_name_from_name_entry((struct name_dentry_t *) -+ ep, uniname, i); -+ else -+ goto out; -+ uniname += 15; -+ } -+ -+out: -+ release_entry_set(es); -+} -+ -+s32 extract_uni_name_from_ext_entry(struct ext_dentry_t *ep, u16 *uniname, -+ s32 order) -+{ -+ int i, len = 0; -+ -+ for (i = 0; i < 10; i += 2) { -+ *uniname = GET16(ep->unicode_0_4 + i); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ -+ if (order < 20) { -+ for (i = 0; i < 12; i += 2) { -+ *uniname = GET16_A(ep->unicode_5_10 + i); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ } else { -+ for (i = 0; i < 8; i += 2) { -+ *uniname = GET16_A(ep->unicode_5_10 + i); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */ -+ return len; -+ } -+ -+ for (i = 0; i < 4; i += 2) { -+ *uniname = GET16_A(ep->unicode_11_12 + i); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ -+ *uniname = 0x0; -+ return len; -+} -+ -+s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname, -+ s32 order) -+{ -+ int i, len = 0; -+ -+ for (i = 0; i < 30; i += 2) { -+ *uniname = GET16_A(ep->unicode_0_14 + i); -+ if (*uniname == 0x0) -+ return len; -+ uniname++; -+ len++; -+ } -+ -+ *uniname = 0x0; -+ return len; -+} -+ -+s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir, -+ struct dos_name_t *p_dosname) -+{ -+ int i, j, count = 0, count_begin = FALSE; -+ s32 dentries_per_clu; -+ u32 type; -+ u8 bmap[128/* 1 ~ 1023 */]; -+ struct chain_t clu; -+ struct dos_dentry_t *ep; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ memset(bmap, 0, sizeof(bmap)); -+ exfat_bitmap_set(bmap, 0); -+ -+ if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ else -+ dentries_per_clu = p_fs->dentries_per_clu; -+ -+ clu.dir = p_dir->dir; -+ clu.flags = p_dir->flags; -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ for (i = 0; i < dentries_per_clu; i++) { -+ ep = (struct dos_dentry_t *)get_entry_in_dir(sb, &clu, -+ i, NULL); -+ if (!ep) -+ return FFS_MEDIAERR; -+ -+ type = p_fs->fs_func->get_entry_type((struct dentry_t *) -+ ep); -+ -+ if (type == TYPE_UNUSED) -+ break; -+ if ((type != TYPE_FILE) && (type != TYPE_DIR)) -+ continue; -+ -+ count = 0; -+ count_begin = FALSE; -+ -+ for (j = 0; j < 8; j++) { -+ if (ep->name[j] == ' ') -+ break; -+ -+ if (ep->name[j] == '~') { -+ count_begin = TRUE; -+ } else if (count_begin) { -+ if ((ep->name[j] >= '0') && -+ (ep->name[j] <= '9')) { -+ count = count * 10 + -+ (ep->name[j] - '0'); -+ } else { -+ count = 0; -+ count_begin = FALSE; -+ } -+ } -+ } -+ -+ if ((count > 0) && (count < 1024)) -+ exfat_bitmap_set(bmap, count); -+ } -+ -+ if (p_dir->dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (FAT_read(sb, clu.dir, &clu.dir) != 0) -+ return FFS_MEDIAERR; -+ } -+ -+ count = 0; -+ for (i = 0; i < 128; i++) { -+ if (bmap[i] != 0xFF) { -+ for (j = 0; j < 8; j++) { -+ if (exfat_bitmap_test(&bmap[i], j) == 0) { -+ count = (i << 3) + j; -+ break; -+ } -+ } -+ if (count != 0) -+ break; -+ } -+ } -+ -+ if ((count == 0) || (count >= 1024)) -+ return FFS_FILEEXIST; -+ fat_attach_count_to_dos_name(p_dosname->name, count); -+ -+ /* Now dos_name has DOS~????.EXT */ -+ return FFS_SUCCESS; -+} -+ -+void fat_attach_count_to_dos_name(u8 *dosname, s32 count) -+{ -+ int i, j, length; -+ char str_count[6]; -+ -+ snprintf(str_count, sizeof(str_count), "~%d", count); -+ length = strlen(str_count); -+ -+ i = 0; -+ j = 0; -+ while (j <= (8 - length)) { -+ i = j; -+ if (dosname[j] == ' ') -+ break; -+ if (dosname[j] & 0x80) -+ j += 2; -+ else -+ j++; -+ } -+ -+ for (j = 0; j < length; i++, j++) -+ dosname[i] = (u8)str_count[j]; -+ -+ if (i == 7) -+ dosname[7] = ' '; -+} -+ -+s32 fat_calc_num_entries(struct uni_name_t *p_uniname) -+{ -+ s32 len; -+ -+ len = p_uniname->name_len; -+ if (len == 0) -+ return 0; -+ -+ /* 1 dos name entry + extended entries */ -+ return (len - 1) / 13 + 2; -+} -+ -+s32 exfat_calc_num_entries(struct uni_name_t *p_uniname) -+{ -+ s32 len; -+ -+ len = p_uniname->name_len; -+ if (len == 0) -+ return 0; -+ -+ /* 1 file entry + 1 stream entry + name entries */ -+ return (len - 1) / 15 + 3; -+} -+ -+u8 calc_checksum_1byte(void *data, s32 len, u8 chksum) -+{ -+ int i; -+ u8 *c = (u8 *)data; -+ -+ for (i = 0; i < len; i++, c++) -+ chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; -+ -+ return chksum; -+} -+ -+u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) -+{ -+ int i; -+ u8 *c = (u8 *)data; -+ -+ switch (type) { -+ case CS_DIR_ENTRY: -+ for (i = 0; i < len; i++, c++) { -+ if ((i == 2) || (i == 3)) -+ continue; -+ chksum = (((chksum & 1) << 15) | -+ ((chksum & 0xFFFE) >> 1)) + (u16)*c; -+ } -+ break; -+ default -+ : -+ for (i = 0; i < len; i++, c++) -+ chksum = (((chksum & 1) << 15) | -+ ((chksum & 0xFFFE) >> 1)) + (u16)*c; -+ } -+ -+ return chksum; -+} -+ -+u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type) -+{ -+ int i; -+ u8 *c = (u8 *)data; -+ -+ switch (type) { -+ case CS_PBR_SECTOR: -+ for (i = 0; i < len; i++, c++) { -+ if ((i == 106) || (i == 107) || (i == 112)) -+ continue; -+ chksum = (((chksum & 1) << 31) | -+ ((chksum & 0xFFFFFFFE) >> 1)) + (u32)*c; -+ } -+ break; -+ default -+ : -+ for (i = 0; i < len; i++, c++) -+ chksum = (((chksum & 1) << 31) | -+ ((chksum & 0xFFFFFFFE) >> 1)) + (u32)*c; -+ } -+ -+ return chksum; -+} -+ -+/* -+ * Name Resolution Functions -+ */ -+ -+/* return values of resolve_path() -+ * > 0 : return the length of the path -+ * < 0 : return error -+ */ -+s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname) -+{ -+ bool lossy = false; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ -+ if (strlen(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) -+ return FFS_INVALIDPATH; -+ -+ strcpy(name_buf, path); -+ -+ nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); -+ if (lossy) -+ return FFS_INVALIDPATH; -+ -+ fid->size = i_size_read(inode); -+ -+ p_dir->dir = fid->start_clu; -+ p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); -+ p_dir->flags = fid->flags; -+ -+ return FFS_SUCCESS; -+} -+ -+/* -+ * File Operation Functions -+ */ -+static struct fs_func fat_fs_func = { -+ .alloc_cluster = fat_alloc_cluster, -+ .free_cluster = fat_free_cluster, -+ .count_used_clusters = fat_count_used_clusters, -+ -+ .init_dir_entry = fat_init_dir_entry, -+ .init_ext_entry = fat_init_ext_entry, -+ .find_dir_entry = fat_find_dir_entry, -+ .delete_dir_entry = fat_delete_dir_entry, -+ .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry, -+ .count_ext_entries = fat_count_ext_entries, -+ .calc_num_entries = fat_calc_num_entries, -+ -+ .get_entry_type = fat_get_entry_type, -+ .set_entry_type = fat_set_entry_type, -+ .get_entry_attr = fat_get_entry_attr, -+ .set_entry_attr = fat_set_entry_attr, -+ .get_entry_flag = fat_get_entry_flag, -+ .set_entry_flag = fat_set_entry_flag, -+ .get_entry_clu0 = fat_get_entry_clu0, -+ .set_entry_clu0 = fat_set_entry_clu0, -+ .get_entry_size = fat_get_entry_size, -+ .set_entry_size = fat_set_entry_size, -+ .get_entry_time = fat_get_entry_time, -+ .set_entry_time = fat_set_entry_time, -+}; -+ -+s32 fat16_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) -+{ -+ s32 num_reserved, num_root_sectors; -+ struct bpb16_t *p_bpb = (struct bpb16_t *)p_pbr->bpb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_bpb->num_fats == 0) -+ return FFS_FORMATERR; -+ -+ num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; -+ num_root_sectors = ((num_root_sectors - 1) >> -+ p_bd->sector_size_bits) + 1; -+ -+ p_fs->sectors_per_clu = p_bpb->sectors_per_clu; -+ p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); -+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + -+ p_bd->sector_size_bits; -+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits; -+ -+ p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors); -+ -+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); -+ if (p_bpb->num_fats == 1) -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; -+ else -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + -+ p_fs->num_FAT_sectors; -+ -+ p_fs->root_start_sector = p_fs->FAT2_start_sector + -+ p_fs->num_FAT_sectors; -+ p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors; -+ -+ p_fs->num_sectors = GET16(p_bpb->num_sectors); -+ if (p_fs->num_sectors == 0) -+ p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); -+ -+ num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; -+ p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> -+ p_fs->sectors_per_clu_bits) + 2; -+ /* because the cluster index starts with 2 */ -+ -+ if (p_fs->num_clusters < FAT12_THRESHOLD) -+ p_fs->vol_type = FAT12; -+ else -+ p_fs->vol_type = FAT16; -+ p_fs->vol_id = GET32(p_bpb->vol_serial); -+ -+ p_fs->root_dir = 0; -+ p_fs->dentries_in_root = GET16(p_bpb->num_root_entries); -+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - -+ DENTRY_SIZE_BITS); -+ -+ p_fs->vol_flag = VOL_CLEAN; -+ p_fs->clu_srch_ptr = 2; -+ p_fs->used_clusters = (u32)~0; -+ -+ p_fs->fs_func = &fat_fs_func; -+ -+ return FFS_SUCCESS; -+} -+ -+s32 fat32_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) -+{ -+ s32 num_reserved; -+ struct bpb32_t *p_bpb = (struct bpb32_t *)p_pbr->bpb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_bpb->num_fats == 0) -+ return FFS_FORMATERR; -+ -+ p_fs->sectors_per_clu = p_bpb->sectors_per_clu; -+ p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); -+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + -+ p_bd->sector_size_bits; -+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits; -+ -+ p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors); -+ -+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); -+ if (p_bpb->num_fats == 1) -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; -+ else -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + -+ p_fs->num_FAT_sectors; -+ -+ p_fs->root_start_sector = p_fs->FAT2_start_sector + -+ p_fs->num_FAT_sectors; -+ p_fs->data_start_sector = p_fs->root_start_sector; -+ -+ p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); -+ num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; -+ -+ p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> -+ p_fs->sectors_per_clu_bits) + 2; -+ /* because the cluster index starts with 2 */ -+ -+ p_fs->vol_type = FAT32; -+ p_fs->vol_id = GET32(p_bpb->vol_serial); -+ -+ p_fs->root_dir = GET32(p_bpb->root_cluster); -+ p_fs->dentries_in_root = 0; -+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - -+ DENTRY_SIZE_BITS); -+ -+ p_fs->vol_flag = VOL_CLEAN; -+ p_fs->clu_srch_ptr = 2; -+ p_fs->used_clusters = (u32)~0; -+ -+ p_fs->fs_func = &fat_fs_func; -+ -+ return FFS_SUCCESS; -+} -+ -+static struct fs_func exfat_fs_func = { -+ .alloc_cluster = exfat_alloc_cluster, -+ .free_cluster = exfat_free_cluster, -+ .count_used_clusters = exfat_count_used_clusters, -+ -+ .init_dir_entry = exfat_init_dir_entry, -+ .init_ext_entry = exfat_init_ext_entry, -+ .find_dir_entry = exfat_find_dir_entry, -+ .delete_dir_entry = exfat_delete_dir_entry, -+ .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry, -+ .count_ext_entries = exfat_count_ext_entries, -+ .calc_num_entries = exfat_calc_num_entries, -+ -+ .get_entry_type = exfat_get_entry_type, -+ .set_entry_type = exfat_set_entry_type, -+ .get_entry_attr = exfat_get_entry_attr, -+ .set_entry_attr = exfat_set_entry_attr, -+ .get_entry_flag = exfat_get_entry_flag, -+ .set_entry_flag = exfat_set_entry_flag, -+ .get_entry_clu0 = exfat_get_entry_clu0, -+ .set_entry_clu0 = exfat_set_entry_clu0, -+ .get_entry_size = exfat_get_entry_size, -+ .set_entry_size = exfat_set_entry_size, -+ .get_entry_time = exfat_get_entry_time, -+ .set_entry_time = exfat_set_entry_time, -+}; -+ -+s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) -+{ -+ struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ if (p_bpb->num_fats == 0) -+ return FFS_FORMATERR; -+ -+ p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; -+ p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; -+ p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + -+ p_bd->sector_size_bits; -+ p_fs->cluster_size = 1 << p_fs->cluster_size_bits; -+ -+ p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); -+ -+ p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); -+ if (p_bpb->num_fats == 1) -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; -+ else -+ p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + -+ p_fs->num_FAT_sectors; -+ -+ p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); -+ p_fs->data_start_sector = p_fs->root_start_sector; -+ -+ p_fs->num_sectors = GET64(p_bpb->vol_length); -+ p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; -+ /* because the cluster index starts with 2 */ -+ -+ p_fs->vol_type = EXFAT; -+ p_fs->vol_id = GET32(p_bpb->vol_serial); -+ -+ p_fs->root_dir = GET32(p_bpb->root_cluster); -+ p_fs->dentries_in_root = 0; -+ p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - -+ DENTRY_SIZE_BITS); -+ -+ p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags); -+ p_fs->clu_srch_ptr = 2; -+ p_fs->used_clusters = (u32)~0; -+ -+ p_fs->fs_func = &exfat_fs_func; -+ -+ return FFS_SUCCESS; -+} -+ -+s32 create_dir(struct inode *inode, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, struct file_id_t *fid) -+{ -+ s32 ret, dentry, num_entries; -+ u64 size; -+ struct chain_t clu; -+ struct dos_name_t dos_name, dot_name; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ -+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -+ &dos_name); -+ if (ret) -+ return ret; -+ -+ /* find_empty_entry must be called before alloc_cluster */ -+ dentry = find_empty_entry(inode, p_dir, num_entries); -+ if (dentry < 0) -+ return FFS_FULL; -+ -+ clu.dir = CLUSTER_32(~0); -+ clu.size = 0; -+ clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ -+ /* (1) allocate a cluster */ -+ ret = fs_func->alloc_cluster(sb, 1, &clu); -+ if (ret < 0) -+ return FFS_MEDIAERR; -+ else if (ret == 0) -+ return FFS_FULL; -+ -+ ret = clear_cluster(sb, clu.dir); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ if (p_fs->vol_type == EXFAT) { -+ size = p_fs->cluster_size; -+ } else { -+ size = 0; -+ -+ /* initialize the . and .. entry -+ * Information for . points to itself -+ * Information for .. points to parent dir -+ */ -+ -+ dot_name.name_case = 0x0; -+ memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH); -+ -+ ret = fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir, -+ 0); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ ret = fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ memcpy(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH); -+ -+ if (p_dir->dir == p_fs->root_dir) -+ ret = fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, -+ CLUSTER_32(0), 0); -+ else -+ ret = fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, -+ p_dir->dir, 0); -+ -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL, -+ &dot_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ } -+ -+ /* (2) update the directory entry */ -+ /* make sub-dir entry in parent directory */ -+ ret = fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, -+ size); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ ret = fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -+ &dos_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ fid->dir.dir = p_dir->dir; -+ fid->dir.size = p_dir->size; -+ fid->dir.flags = p_dir->flags; -+ fid->entry = dentry; -+ -+ fid->attr = ATTR_SUBDIR; -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ fid->size = size; -+ fid->start_clu = clu.dir; -+ -+ fid->type = TYPE_DIR; -+ fid->rwoffset = 0; -+ fid->hint_last_off = -1; -+ -+ return FFS_SUCCESS; -+} -+ -+s32 create_file(struct inode *inode, struct chain_t *p_dir, -+ struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid) -+{ -+ s32 ret, dentry, num_entries; -+ struct dos_name_t dos_name; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ -+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, -+ &dos_name); -+ if (ret) -+ return ret; -+ -+ /* find_empty_entry must be called before alloc_cluster() */ -+ dentry = find_empty_entry(inode, p_dir, num_entries); -+ if (dentry < 0) -+ return FFS_FULL; -+ -+ /* (1) update the directory entry */ -+ /* fill the dos name directory entry information of the created file. -+ * the first cluster is not determined yet. (0) -+ */ -+ ret = fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, -+ CLUSTER_32(0), 0); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ ret = fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, -+ &dos_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ fid->dir.dir = p_dir->dir; -+ fid->dir.size = p_dir->size; -+ fid->dir.flags = p_dir->flags; -+ fid->entry = dentry; -+ -+ fid->attr = ATTR_ARCHIVE | mode; -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ fid->size = 0; -+ fid->start_clu = CLUSTER_32(~0); -+ -+ fid->type = TYPE_FILE; -+ fid->rwoffset = 0; -+ fid->hint_last_off = -1; -+ -+ return FFS_SUCCESS; -+} -+ -+void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry) -+{ -+ s32 num_entries; -+ sector_t sector; -+ struct dentry_t *ep; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ -+ ep = get_entry_in_dir(sb, p_dir, entry, §or); -+ if (!ep) -+ return; -+ -+ buf_lock(sb, sector); -+ -+ /* buf_lock() before call count_ext_entries() */ -+ num_entries = fs_func->count_ext_entries(sb, p_dir, entry, ep); -+ if (num_entries < 0) { -+ buf_unlock(sb, sector); -+ return; -+ } -+ num_entries++; -+ -+ buf_unlock(sb, sector); -+ -+ /* (1) update the directory entry */ -+ fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries); -+} -+ -+s32 rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry, -+ struct uni_name_t *p_uniname, struct file_id_t *fid) -+{ -+ s32 ret, newentry = -1, num_old_entries, num_new_entries; -+ sector_t sector_old, sector_new; -+ struct dos_name_t dos_name; -+ struct dentry_t *epold, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ -+ epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); -+ if (!epold) -+ return FFS_MEDIAERR; -+ -+ buf_lock(sb, sector_old); -+ -+ /* buf_lock() before call count_ext_entries() */ -+ num_old_entries = fs_func->count_ext_entries(sb, p_dir, oldentry, -+ epold); -+ if (num_old_entries < 0) { -+ buf_unlock(sb, sector_old); -+ return FFS_MEDIAERR; -+ } -+ num_old_entries++; -+ -+ ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, -+ &num_new_entries, &dos_name); -+ if (ret) { -+ buf_unlock(sb, sector_old); -+ return ret; -+ } -+ -+ if (num_old_entries < num_new_entries) { -+ newentry = find_empty_entry(inode, p_dir, num_new_entries); -+ if (newentry < 0) { -+ buf_unlock(sb, sector_old); -+ return FFS_FULL; -+ } -+ -+ epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); -+ if (!epnew) { -+ buf_unlock(sb, sector_old); -+ return FFS_MEDIAERR; -+ } -+ -+ memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -+ if (fs_func->get_entry_type(epnew) == TYPE_FILE) { -+ fs_func->set_entry_attr(epnew, -+ fs_func->get_entry_attr(epnew) | -+ ATTR_ARCHIVE); -+ fid->attr |= ATTR_ARCHIVE; -+ } -+ buf_modify(sb, sector_new); -+ buf_unlock(sb, sector_old); -+ -+ if (p_fs->vol_type == EXFAT) { -+ epold = get_entry_in_dir(sb, p_dir, oldentry + 1, -+ §or_old); -+ buf_lock(sb, sector_old); -+ epnew = get_entry_in_dir(sb, p_dir, newentry + 1, -+ §or_new); -+ -+ if (!epold || !epnew) { -+ buf_unlock(sb, sector_old); -+ return FFS_MEDIAERR; -+ } -+ -+ memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); -+ buf_modify(sb, sector_new); -+ buf_unlock(sb, sector_old); -+ } -+ -+ ret = fs_func->init_ext_entry(sb, p_dir, newentry, -+ num_new_entries, p_uniname, -+ &dos_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ fs_func->delete_dir_entry(sb, p_dir, oldentry, 0, -+ num_old_entries); -+ fid->entry = newentry; -+ } else { -+ if (fs_func->get_entry_type(epold) == TYPE_FILE) { -+ fs_func->set_entry_attr(epold, -+ fs_func->get_entry_attr(epold) | -+ ATTR_ARCHIVE); -+ fid->attr |= ATTR_ARCHIVE; -+ } -+ buf_modify(sb, sector_old); -+ buf_unlock(sb, sector_old); -+ -+ ret = fs_func->init_ext_entry(sb, p_dir, oldentry, -+ num_new_entries, p_uniname, -+ &dos_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries, -+ num_old_entries); -+ } -+ -+ return FFS_SUCCESS; -+} -+ -+s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, -+ struct chain_t *p_newdir, struct uni_name_t *p_uniname, -+ struct file_id_t *fid) -+{ -+ s32 ret, newentry, num_new_entries, num_old_entries; -+ sector_t sector_mov, sector_new; -+ struct chain_t clu; -+ struct dos_name_t dos_name; -+ struct dentry_t *epmov, *epnew; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ -+ epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); -+ if (!epmov) -+ return FFS_MEDIAERR; -+ -+ /* check if the source and target directory is the same */ -+ if (fs_func->get_entry_type(epmov) == TYPE_DIR && -+ fs_func->get_entry_clu0(epmov) == p_newdir->dir) -+ return FFS_INVALIDPATH; -+ -+ buf_lock(sb, sector_mov); -+ -+ /* buf_lock() before call count_ext_entries() */ -+ num_old_entries = fs_func->count_ext_entries(sb, p_olddir, oldentry, -+ epmov); -+ if (num_old_entries < 0) { -+ buf_unlock(sb, sector_mov); -+ return FFS_MEDIAERR; -+ } -+ num_old_entries++; -+ -+ ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, -+ &num_new_entries, &dos_name); -+ if (ret) { -+ buf_unlock(sb, sector_mov); -+ return ret; -+ } -+ -+ newentry = find_empty_entry(inode, p_newdir, num_new_entries); -+ if (newentry < 0) { -+ buf_unlock(sb, sector_mov); -+ return FFS_FULL; -+ } -+ -+ epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); -+ if (!epnew) { -+ buf_unlock(sb, sector_mov); -+ return FFS_MEDIAERR; -+ } -+ -+ memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -+ if (fs_func->get_entry_type(epnew) == TYPE_FILE) { -+ fs_func->set_entry_attr(epnew, fs_func->get_entry_attr(epnew) | -+ ATTR_ARCHIVE); -+ fid->attr |= ATTR_ARCHIVE; -+ } -+ buf_modify(sb, sector_new); -+ buf_unlock(sb, sector_mov); -+ -+ if (p_fs->vol_type == EXFAT) { -+ epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1, -+ §or_mov); -+ buf_lock(sb, sector_mov); -+ epnew = get_entry_in_dir(sb, p_newdir, newentry + 1, -+ §or_new); -+ if (!epmov || !epnew) { -+ buf_unlock(sb, sector_mov); -+ return FFS_MEDIAERR; -+ } -+ -+ memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); -+ buf_modify(sb, sector_new); -+ buf_unlock(sb, sector_mov); -+ } else if (fs_func->get_entry_type(epnew) == TYPE_DIR) { -+ /* change ".." pointer to new parent dir */ -+ clu.dir = fs_func->get_entry_clu0(epnew); -+ clu.flags = 0x01; -+ -+ epnew = get_entry_in_dir(sb, &clu, 1, §or_new); -+ if (!epnew) -+ return FFS_MEDIAERR; -+ -+ if (p_newdir->dir == p_fs->root_dir) -+ fs_func->set_entry_clu0(epnew, CLUSTER_32(0)); -+ else -+ fs_func->set_entry_clu0(epnew, p_newdir->dir); -+ buf_modify(sb, sector_new); -+ } -+ -+ ret = fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries, -+ p_uniname, &dos_name); -+ if (ret != FFS_SUCCESS) -+ return ret; -+ -+ fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); -+ -+ fid->dir.dir = p_newdir->dir; -+ fid->dir.size = p_newdir->size; -+ fid->dir.flags = p_newdir->flags; -+ -+ fid->entry = newentry; -+ -+ return FFS_SUCCESS; -+} -+ -+/* -+ * Sector Read/Write Functions -+ */ -+ -+int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, -+ bool read) -+{ -+ s32 ret = FFS_MEDIAERR; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if ((sec >= (p_fs->PBR_sector + p_fs->num_sectors)) && -+ (p_fs->num_sectors > 0)) { -+ pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -+ __func__, (unsigned long long)sec); -+ fs_error(sb); -+ return ret; -+ } -+ -+ if (!p_fs->dev_ejected) { -+ ret = bdev_read(sb, sec, bh, 1, read); -+ if (ret != FFS_SUCCESS) -+ p_fs->dev_ejected = TRUE; -+ } -+ -+ return ret; -+} -+ -+int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, -+ bool sync) -+{ -+ s32 ret = FFS_MEDIAERR; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (sec >= (p_fs->PBR_sector + p_fs->num_sectors) && -+ (p_fs->num_sectors > 0)) { -+ pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", -+ __func__, (unsigned long long)sec); -+ fs_error(sb); -+ return ret; -+ } -+ -+ if (!bh) { -+ pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -+ fs_error(sb); -+ return ret; -+ } -+ -+ if (!p_fs->dev_ejected) { -+ ret = bdev_write(sb, sec, bh, 1, sync); -+ if (ret != FFS_SUCCESS) -+ p_fs->dev_ejected = TRUE; -+ } -+ -+ return ret; -+} -+ -+int multi_sector_read(struct super_block *sb, sector_t sec, -+ struct buffer_head **bh, s32 num_secs, bool read) -+{ -+ s32 ret = FFS_MEDIAERR; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors)) && -+ (p_fs->num_sectors > 0)) { -+ pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -+ __func__, (unsigned long long)sec, num_secs); -+ fs_error(sb); -+ return ret; -+ } -+ -+ if (!p_fs->dev_ejected) { -+ ret = bdev_read(sb, sec, bh, num_secs, read); -+ if (ret != FFS_SUCCESS) -+ p_fs->dev_ejected = TRUE; -+ } -+ -+ return ret; -+} -+ -+int multi_sector_write(struct super_block *sb, sector_t sec, -+ struct buffer_head *bh, s32 num_secs, bool sync) -+{ -+ s32 ret = FFS_MEDIAERR; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if ((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors) && -+ (p_fs->num_sectors > 0)) { -+ pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", -+ __func__, (unsigned long long)sec, num_secs); -+ fs_error(sb); -+ return ret; -+ } -+ if (!bh) { -+ pr_err("[EXFAT] %s: bh is NULL!\n", __func__); -+ fs_error(sb); -+ return ret; -+ } -+ -+ if (!p_fs->dev_ejected) { -+ ret = bdev_write(sb, sec, bh, num_secs, sync); -+ if (ret != FFS_SUCCESS) -+ p_fs->dev_ejected = TRUE; -+ } -+ -+ return ret; -+} -diff --git a/drivers/staging/exfat/exfat_nls.c b/drivers/staging/exfat/exfat_nls.c -new file mode 100644 -index 000000000000..2ca58616159b ---- /dev/null -+++ b/drivers/staging/exfat/exfat_nls.c -@@ -0,0 +1,404 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/string.h> -+#include <linux/nls.h> -+#include "exfat.h" -+ -+static u16 bad_dos_chars[] = { -+ /* + , ; = [ ] */ -+ 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D, -+ 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D, -+ 0 -+}; -+ -+static u16 bad_uni_chars[] = { -+ /* " * / : < > ? \ | */ -+ 0x0022, 0x002A, 0x002F, 0x003A, -+ 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, -+ 0 -+}; -+ -+static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, -+ bool *lossy) -+{ -+ int len; -+ -+ *uni = 0x0; -+ -+ if (ch[0] < 0x80) { -+ *uni = (u16)ch[0]; -+ return 1; -+ } -+ -+ len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); -+ if (len < 0) { -+ /* conversion failed */ -+ pr_info("%s: fail to use nls\n", __func__); -+ if (lossy) -+ *lossy = true; -+ *uni = (u16)'_'; -+ if (!strcmp(nls->charset, "utf8")) -+ return 1; -+ else -+ return 2; -+ } -+ -+ return len; -+} -+ -+static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, -+ bool *lossy) -+{ -+ int len; -+ -+ ch[0] = 0x0; -+ -+ if (uni < 0x0080) { -+ ch[0] = (u8)uni; -+ return 1; -+ } -+ -+ len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); -+ if (len < 0) { -+ /* conversion failed */ -+ pr_info("%s: fail to use nls\n", __func__); -+ if (lossy) -+ *lossy = true; -+ ch[0] = '_'; -+ return 1; -+ } -+ -+ return len; -+} -+ -+u16 nls_upper(struct super_block *sb, u16 a) -+{ -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ if (EXFAT_SB(sb)->options.casesensitive) -+ return a; -+ if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)]) -+ return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)]; -+ else -+ return a; -+} -+ -+static u16 *nls_wstrchr(u16 *str, u16 wchar) -+{ -+ while (*str) { -+ if (*(str++) == wchar) -+ return str; -+ } -+ -+ return NULL; -+} -+ -+int nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b) -+{ -+ return strncmp(a, b, DOS_NAME_LENGTH); -+} -+ -+int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { -+ if (nls_upper(sb, *a) != nls_upper(sb, *b)) -+ return 1; -+ if (*a == 0x0) -+ return 0; -+ } -+ return 0; -+} -+ -+void nls_uniname_to_dosname(struct super_block *sb, -+ struct dos_name_t *p_dosname, -+ struct uni_name_t *p_uniname, bool *p_lossy) -+{ -+ int i, j, len; -+ bool lossy = false; -+ u8 buf[MAX_CHARSET_SIZE]; -+ u8 lower = 0, upper = 0; -+ u8 *dosname = p_dosname->name; -+ u16 *uniname = p_uniname->name; -+ u16 *p, *last_period; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_disk; -+ -+ for (i = 0; i < DOS_NAME_LENGTH; i++) -+ *(dosname + i) = ' '; -+ -+ if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_CUR_DIR_NAME)) { -+ *(dosname) = '.'; -+ p_dosname->name_case = 0x0; -+ if (p_lossy) -+ *p_lossy = false; -+ return; -+ } -+ -+ if (!nls_uniname_cmp(sb, uniname, (u16 *)UNI_PAR_DIR_NAME)) { -+ *(dosname) = '.'; -+ *(dosname + 1) = '.'; -+ p_dosname->name_case = 0x0; -+ if (p_lossy) -+ *p_lossy = false; -+ return; -+ } -+ -+ /* search for the last embedded period */ -+ last_period = NULL; -+ for (p = uniname; *p; p++) { -+ if (*p == (u16)'.') -+ last_period = p; -+ } -+ -+ i = 0; -+ while (i < DOS_NAME_LENGTH) { -+ if (i == 8) { -+ if (!last_period) -+ break; -+ -+ if (uniname <= last_period) { -+ if (uniname < last_period) -+ lossy = true; -+ uniname = last_period + 1; -+ } -+ } -+ -+ if (*uniname == (u16)'\0') { -+ break; -+ } else if (*uniname == (u16)' ') { -+ lossy = true; -+ } else if (*uniname == (u16)'.') { -+ if (uniname < last_period) -+ lossy = true; -+ else -+ i = 8; -+ } else if (nls_wstrchr(bad_dos_chars, *uniname)) { -+ lossy = true; -+ *(dosname + i) = '_'; -+ i++; -+ } else { -+ len = convert_uni_to_ch(nls, buf, *uniname, &lossy); -+ -+ if (len > 1) { -+ if ((i >= 8) && ((i + len) > DOS_NAME_LENGTH)) -+ break; -+ -+ if ((i < 8) && ((i + len) > 8)) { -+ i = 8; -+ continue; -+ } -+ -+ lower = 0xFF; -+ -+ for (j = 0; j < len; j++, i++) -+ *(dosname + i) = *(buf + j); -+ } else { /* len == 1 */ -+ if ((*buf >= 'a') && (*buf <= 'z')) { -+ *(dosname + i) = *buf - ('a' - 'A'); -+ -+ if (i < 8) -+ lower |= 0x08; -+ else -+ lower |= 0x10; -+ } else if ((*buf >= 'A') && (*buf <= 'Z')) { -+ *(dosname + i) = *buf; -+ -+ if (i < 8) -+ upper |= 0x08; -+ else -+ upper |= 0x10; -+ } else { -+ *(dosname + i) = *buf; -+ } -+ i++; -+ } -+ } -+ -+ uniname++; -+ } -+ -+ if (*dosname == 0xE5) -+ *dosname = 0x05; -+ -+ if (*uniname != 0x0) -+ lossy = TRUE; -+ -+ if (upper & lower) -+ p_dosname->name_case = 0xFF; -+ else -+ p_dosname->name_case = lower; -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+} -+ -+void nls_dosname_to_uniname(struct super_block *sb, -+ struct uni_name_t *p_uniname, -+ struct dos_name_t *p_dosname) -+{ -+ int i = 0, j, n = 0; -+ u8 buf[DOS_NAME_LENGTH + 2]; -+ u8 *dosname = p_dosname->name; -+ u16 *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_disk; -+ -+ if (*dosname == 0x05) { -+ *buf = 0xE5; -+ i++; -+ n++; -+ } -+ -+ for (; i < 8; i++, n++) { -+ if (*(dosname + i) == ' ') -+ break; -+ -+ if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') && -+ (p_dosname->name_case & 0x08)) -+ *(buf + n) = *(dosname + i) + ('a' - 'A'); -+ else -+ *(buf + n) = *(dosname + i); -+ } -+ if (*(dosname + 8) != ' ') { -+ *(buf + n) = '.'; -+ n++; -+ } -+ -+ for (i = 8; i < DOS_NAME_LENGTH; i++, n++) { -+ if (*(dosname + i) == ' ') -+ break; -+ -+ if ((*(dosname + i) >= 'A') && (*(dosname + i) <= 'Z') && -+ (p_dosname->name_case & 0x10)) -+ *(buf + n) = *(dosname + i) + ('a' - 'A'); -+ else -+ *(buf + n) = *(dosname + i); -+ } -+ *(buf + n) = '\0'; -+ -+ i = 0; -+ j = 0; -+ while (j < (MAX_NAME_LENGTH - 1)) { -+ if (*(buf + i) == '\0') -+ break; -+ -+ i += convert_ch_to_uni(nls, uniname, (buf + i), NULL); -+ -+ uniname++; -+ j++; -+ } -+ -+ *uniname = (u16)'\0'; -+} -+ -+void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, -+ struct uni_name_t *p_uniname) -+{ -+ int i, j, len; -+ u8 buf[MAX_CHARSET_SIZE]; -+ u16 *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ if (!nls) { -+ len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, -+ UTF16_HOST_ENDIAN, p_cstring, -+ MAX_NAME_LENGTH); -+ p_cstring[len] = 0; -+ return; -+ } -+ -+ i = 0; -+ while (i < (MAX_NAME_LENGTH - 1)) { -+ if (*uniname == (u16)'\0') -+ break; -+ -+ len = convert_uni_to_ch(nls, buf, *uniname, NULL); -+ -+ if (len > 1) { -+ for (j = 0; j < len; j++) -+ *p_cstring++ = (char)*(buf + j); -+ } else { /* len == 1 */ -+ *p_cstring++ = (char)*buf; -+ } -+ -+ uniname++; -+ i++; -+ } -+ -+ *p_cstring = '\0'; -+} -+ -+void nls_cstring_to_uniname(struct super_block *sb, -+ struct uni_name_t *p_uniname, u8 *p_cstring, -+ bool *p_lossy) -+{ -+ int i, j; -+ bool lossy = false; -+ u8 *end_of_name; -+ u8 upname[MAX_NAME_LENGTH * 2]; -+ u16 *uniname = p_uniname->name; -+ struct nls_table *nls = EXFAT_SB(sb)->nls_io; -+ -+ /* strip all trailing spaces */ -+ end_of_name = p_cstring + strlen(p_cstring); -+ -+ while (*(--end_of_name) == ' ') { -+ if (end_of_name < p_cstring) -+ break; -+ } -+ *(++end_of_name) = '\0'; -+ -+ if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) { -+ /* strip all trailing periods */ -+ while (*(--end_of_name) == '.') { -+ if (end_of_name < p_cstring) -+ break; -+ } -+ *(++end_of_name) = '\0'; -+ } -+ -+ if (*p_cstring == '\0') -+ lossy = true; -+ -+ if (!nls) { -+ i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, -+ UTF16_HOST_ENDIAN, uniname, -+ MAX_NAME_LENGTH); -+ for (j = 0; j < i; j++) -+ SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); -+ uniname[i] = '\0'; -+ } else { -+ i = 0; -+ j = 0; -+ while (j < (MAX_NAME_LENGTH - 1)) { -+ if (*(p_cstring + i) == '\0') -+ break; -+ -+ i += convert_ch_to_uni(nls, uniname, -+ (u8 *)(p_cstring + i), &lossy); -+ -+ if ((*uniname < 0x0020) || -+ nls_wstrchr(bad_uni_chars, *uniname)) -+ lossy = true; -+ -+ SET16_A(upname + j * 2, nls_upper(sb, *uniname)); -+ -+ uniname++; -+ j++; -+ } -+ -+ if (*(p_cstring + i) != '\0') -+ lossy = true; -+ *uniname = (u16)'\0'; -+ } -+ -+ p_uniname->name_len = j; -+ p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0, -+ CS_DEFAULT); -+ -+ if (p_lossy) -+ *p_lossy = lossy; -+} -diff --git a/drivers/staging/exfat/exfat_super.c b/drivers/staging/exfat/exfat_super.c -new file mode 100644 -index 000000000000..5b5c2ca8c9aa ---- /dev/null -+++ b/drivers/staging/exfat/exfat_super.c -@@ -0,0 +1,4137 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/time.h> -+#include <linux/slab.h> -+#include <linux/seq_file.h> -+#include <linux/pagemap.h> -+#include <linux/mpage.h> -+#include <linux/buffer_head.h> -+#include <linux/exportfs.h> -+#include <linux/mount.h> -+#include <linux/vfs.h> -+#include <linux/aio.h> -+#include <linux/iversion.h> -+#include <linux/parser.h> -+#include <linux/uio.h> -+#include <linux/writeback.h> -+#include <linux/log2.h> -+#include <linux/hash.h> -+#include <linux/backing-dev.h> -+#include <linux/sched.h> -+#include <linux/fs_struct.h> -+#include <linux/namei.h> -+#include <linux/time.h> -+ -+#include <linux/string.h> -+#include <linux/nls.h> -+#include <linux/mutex.h> -+#include <linux/swap.h> -+ -+#define EXFAT_VERSION "1.3.0" -+ -+#include "exfat.h" -+ -+static struct kmem_cache *exfat_inode_cachep; -+ -+// FIXME use commented lines -+// static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE; -+// static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; -+static int exfat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE; -+static char exfat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; -+ -+#define INC_IVERSION(x) (inode_inc_iversion(x)) -+#define GET_IVERSION(x) (inode_peek_iversion_raw(x)) -+#define SET_IVERSION(x, y) (inode_set_iversion(x, y)) -+ -+static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); -+static int exfat_sync_inode(struct inode *inode); -+static struct inode *exfat_build_inode(struct super_block *sb, -+ struct file_id_t *fid, loff_t i_pos); -+static int exfat_write_inode(struct inode *inode, -+ struct writeback_control *wbc); -+static void exfat_write_super(struct super_block *sb); -+ -+#define UNIX_SECS_1980 315532800L -+ -+#if BITS_PER_LONG == 64 -+#define UNIX_SECS_2108 4354819200L -+#endif -+ -+/* days between 1.1.70 and 1.1.80 (2 leap days) */ -+#define DAYS_DELTA_DECADE (365 * 10 + 2) -+/* 120 (2100 - 1980) isn't leap year */ -+#define NO_LEAP_YEAR_2100 (120) -+#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) -+ -+#define SECS_PER_MIN (60) -+#define SECS_PER_HOUR (60 * SECS_PER_MIN) -+#define SECS_PER_DAY (24 * SECS_PER_HOUR) -+ -+#define MAKE_LEAP_YEAR(leap_year, year) \ -+ do { \ -+ if (unlikely(year > NO_LEAP_YEAR_2100)) \ -+ leap_year = ((year + 3) / 4) - 1; \ -+ else \ -+ leap_year = ((year + 3) / 4); \ -+ } while (0) -+ -+/* Linear day numbers of the respective 1sts in non-leap years. */ -+static time_t accum_days_in_year[] = { -+ /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ -+ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, -+}; -+ -+/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ -+static void exfat_time_fat2unix(struct exfat_sb_info *sbi, -+ struct timespec64 *ts, struct date_time_t *tp) -+{ -+ time_t year = tp->Year; -+ time_t ld; -+ -+ MAKE_LEAP_YEAR(ld, year); -+ -+ if (IS_LEAP_YEAR(year) && (tp->Month) > 2) -+ ld++; -+ -+ ts->tv_sec = tp->Second + -+ tp->Minute * SECS_PER_MIN + -+ tp->Hour * SECS_PER_HOUR + -+ (ld + accum_days_in_year[(tp->Month)] + -+ (tp->Day - 1)) * SECS_PER_DAY + -+ (year * 365 + DAYS_DELTA_DECADE) * SECS_PER_DAY + -+ sys_tz.tz_minuteswest * SECS_PER_MIN; -+ -+ ts->tv_nsec = 0; -+} -+ -+/* Convert linear UNIX date to a FAT time/date pair. */ -+static void exfat_time_unix2fat(struct exfat_sb_info *sbi, -+ struct timespec64 *ts, struct date_time_t *tp) -+{ -+ time_t second = ts->tv_sec; -+ time_t day, month, year; -+ time_t ld; -+ -+ second -= sys_tz.tz_minuteswest * SECS_PER_MIN; -+ -+ /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ -+ if (second < UNIX_SECS_1980) { -+ tp->Second = 0; -+ tp->Minute = 0; -+ tp->Hour = 0; -+ tp->Day = 1; -+ tp->Month = 1; -+ tp->Year = 0; -+ return; -+ } -+#if (BITS_PER_LONG == 64) -+ if (second >= UNIX_SECS_2108) { -+ tp->Second = 59; -+ tp->Minute = 59; -+ tp->Hour = 23; -+ tp->Day = 31; -+ tp->Month = 12; -+ tp->Year = 127; -+ return; -+ } -+#endif -+ day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; -+ year = day / 365; -+ MAKE_LEAP_YEAR(ld, year); -+ if (year * 365 + ld > day) -+ year--; -+ -+ MAKE_LEAP_YEAR(ld, year); -+ day -= year * 365 + ld; -+ -+ if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { -+ month = 2; -+ } else { -+ if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) -+ day--; -+ for (month = 1; month < 12; month++) { -+ if (accum_days_in_year[month + 1] > day) -+ break; -+ } -+ } -+ day -= accum_days_in_year[month]; -+ -+ tp->Second = second % SECS_PER_MIN; -+ tp->Minute = (second / SECS_PER_MIN) % 60; -+ tp->Hour = (second / SECS_PER_HOUR) % 24; -+ tp->Day = day + 1; -+ tp->Month = month; -+ tp->Year = year; -+} -+ -+struct timestamp_t *tm_current(struct timestamp_t *tp) -+{ -+ struct timespec64 ts; -+ time_t second, day, leap_day, month, year; -+ -+ ktime_get_real_ts64(&ts); -+ -+ second = ts.tv_sec; -+ second -= sys_tz.tz_minuteswest * SECS_PER_MIN; -+ -+ /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ -+ if (second < UNIX_SECS_1980) { -+ tp->sec = 0; -+ tp->min = 0; -+ tp->hour = 0; -+ tp->day = 1; -+ tp->mon = 1; -+ tp->year = 0; -+ return tp; -+ } -+#if BITS_PER_LONG == 64 -+ if (second >= UNIX_SECS_2108) { -+ tp->sec = 59; -+ tp->min = 59; -+ tp->hour = 23; -+ tp->day = 31; -+ tp->mon = 12; -+ tp->year = 127; -+ return tp; -+ } -+#endif -+ -+ day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; -+ year = day / 365; -+ -+ MAKE_LEAP_YEAR(leap_day, year); -+ if (year * 365 + leap_day > day) -+ year--; -+ -+ MAKE_LEAP_YEAR(leap_day, year); -+ -+ day -= year * 365 + leap_day; -+ -+ if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { -+ month = 2; -+ } else { -+ if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) -+ day--; -+ for (month = 1; month < 12; month++) { -+ if (accum_days_in_year[month + 1] > day) -+ break; -+ } -+ } -+ day -= accum_days_in_year[month]; -+ -+ tp->sec = second % SECS_PER_MIN; -+ tp->min = (second / SECS_PER_MIN) % 60; -+ tp->hour = (second / SECS_PER_HOUR) % 24; -+ tp->day = day + 1; -+ tp->mon = month; -+ tp->year = year; -+ -+ return tp; -+} -+ -+static void __lock_super(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ mutex_lock(&sbi->s_lock); -+} -+ -+static void __unlock_super(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ mutex_unlock(&sbi->s_lock); -+} -+ -+static int __is_sb_dirty(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ return sbi->s_dirt; -+} -+ -+static void __set_sb_clean(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ sbi->s_dirt = 0; -+} -+ -+static int __exfat_revalidate(struct dentry *dentry) -+{ -+ return 0; -+} -+ -+static int exfat_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ if (dentry->d_inode) -+ return 1; -+ return __exfat_revalidate(dentry); -+} -+ -+static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) -+{ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ if (dentry->d_inode) -+ return 1; -+ -+ if (!flags) -+ return 0; -+ -+ if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) -+ return 0; -+ -+ return __exfat_revalidate(dentry); -+} -+ -+static unsigned int __exfat_striptail_len(unsigned int len, const char *name) -+{ -+ while (len && name[len - 1] == '.') -+ len--; -+ return len; -+} -+ -+static unsigned int exfat_striptail_len(const struct qstr *qstr) -+{ -+ return __exfat_striptail_len(qstr->len, qstr->name); -+} -+ -+static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) -+{ -+ qstr->hash = full_name_hash(dentry, qstr->name, -+ exfat_striptail_len(qstr)); -+ return 0; -+} -+ -+static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) -+{ -+ struct super_block *sb = dentry->d_sb; -+ const unsigned char *name; -+ unsigned int len; -+ unsigned long hash; -+ -+ name = qstr->name; -+ len = exfat_striptail_len(qstr); -+ -+ hash = init_name_hash(dentry); -+ while (len--) -+ hash = partial_name_hash(nls_upper(sb, *name++), hash); -+ qstr->hash = end_name_hash(hash); -+ -+ return 0; -+} -+ -+static int exfat_cmpi(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; -+ unsigned int alen, blen; -+ -+ alen = exfat_striptail_len(name); -+ blen = __exfat_striptail_len(len, str); -+ if (alen == blen) { -+ if (t == NULL) { -+ if (strncasecmp(name->name, str, alen) == 0) -+ return 0; -+ } else if (nls_strnicmp(t, name->name, str, alen) == 0) -+ return 0; -+ } -+ return 1; -+} -+ -+static int exfat_cmp(const struct dentry *dentry, unsigned int len, -+ const char *str, const struct qstr *name) -+{ -+ unsigned int alen, blen; -+ -+ alen = exfat_striptail_len(name); -+ blen = __exfat_striptail_len(len, str); -+ if (alen == blen) { -+ if (strncmp(name->name, str, alen) == 0) -+ return 0; -+ } -+ return 1; -+} -+ -+static const struct dentry_operations exfat_ci_dentry_ops = { -+ .d_revalidate = exfat_revalidate_ci, -+ .d_hash = exfat_d_hashi, -+ .d_compare = exfat_cmpi, -+}; -+ -+static const struct dentry_operations exfat_dentry_ops = { -+ .d_revalidate = exfat_revalidate, -+ .d_hash = exfat_d_hash, -+ .d_compare = exfat_cmp, -+}; -+ -+static DEFINE_SEMAPHORE(z_sem); -+ -+static inline void fs_sync(struct super_block *sb, bool do_sync) -+{ -+ if (do_sync) -+ bdev_sync(sb); -+} -+ -+/* -+ * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to -+ * save ATTR_RO instead of ->i_mode. -+ * -+ * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only -+ * bit, it's just used as flag for app. -+ */ -+static inline int exfat_mode_can_hold_ro(struct inode *inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ -+ if (S_ISDIR(inode->i_mode)) -+ return 0; -+ -+ if ((~sbi->options.fs_fmask) & 0222) -+ return 1; -+ return 0; -+} -+ -+/* Convert attribute bits and a mask to the UNIX mode. */ -+static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, u32 attr, -+ mode_t mode) -+{ -+ if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) -+ mode &= ~0222; -+ -+ if (attr & ATTR_SUBDIR) -+ return (mode & ~sbi->options.fs_dmask) | S_IFDIR; -+ else if (attr & ATTR_SYMLINK) -+ return (mode & ~sbi->options.fs_dmask) | S_IFLNK; -+ else -+ return (mode & ~sbi->options.fs_fmask) | S_IFREG; -+} -+ -+/* Return the FAT attribute byte for this inode */ -+static inline u32 exfat_make_attr(struct inode *inode) -+{ -+ if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) -+ return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; -+ else -+ return EXFAT_I(inode)->fid.attr; -+} -+ -+static inline void exfat_save_attr(struct inode *inode, u32 attr) -+{ -+ if (exfat_mode_can_hold_ro(inode)) -+ EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; -+ else -+ EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); -+} -+ -+static int ffsMountVol(struct super_block *sb) -+{ -+ int i, ret; -+ struct pbr_sector_t *p_pbr; -+ struct buffer_head *tmp_bh = NULL; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ pr_info("[EXFAT] trying to mount...\n"); -+ -+ down(&z_sem); -+ -+ buf_init(sb); -+ -+ sema_init(&p_fs->v_sem, 1); -+ p_fs->dev_ejected = FALSE; -+ -+ /* open the block device */ -+ bdev_open(sb); -+ -+ if (p_bd->sector_size < sb->s_blocksize) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ if (p_bd->sector_size > sb->s_blocksize) -+ sb_set_blocksize(sb, p_bd->sector_size); -+ -+ /* read Sector 0 */ -+ if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ -+ p_fs->PBR_sector = 0; -+ -+ p_pbr = (struct pbr_sector_t *) tmp_bh->b_data; -+ -+ /* check the validity of PBR */ -+ if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { -+ brelse(tmp_bh); -+ bdev_close(sb); -+ ret = FFS_FORMATERR; -+ goto out; -+ } -+ -+ /* fill fs_stuct */ -+ for (i = 0; i < 53; i++) -+ if (p_pbr->bpb[i]) -+ break; -+ -+ if (i < 53) { -+ if (GET16(p_pbr->bpb + 11)) /* num_fat_sectors */ -+ ret = fat16_mount(sb, p_pbr); -+ else -+ ret = fat32_mount(sb, p_pbr); -+ } else { -+ ret = exfat_mount(sb, p_pbr); -+ } -+ -+ brelse(tmp_bh); -+ -+ if (ret) { -+ bdev_close(sb); -+ goto out; -+ } -+ -+ if (p_fs->vol_type == EXFAT) { -+ ret = load_alloc_bitmap(sb); -+ if (ret) { -+ bdev_close(sb); -+ goto out; -+ } -+ ret = load_upcase_table(sb); -+ if (ret) { -+ free_alloc_bitmap(sb); -+ bdev_close(sb); -+ goto out; -+ } -+ } -+ -+ if (p_fs->dev_ejected) { -+ if (p_fs->vol_type == EXFAT) { -+ free_upcase_table(sb); -+ free_alloc_bitmap(sb); -+ } -+ bdev_close(sb); -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ -+ pr_info("[EXFAT] mounted successfully\n"); -+ -+out: -+ up(&z_sem); -+ -+ return ret; -+} -+ -+static int ffsUmountVol(struct super_block *sb) -+{ -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ int err = FFS_SUCCESS; -+ -+ pr_info("[EXFAT] trying to unmount...\n"); -+ -+ down(&z_sem); -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+ -+ if (p_fs->vol_type == EXFAT) { -+ free_upcase_table(sb); -+ free_alloc_bitmap(sb); -+ } -+ -+ FAT_release_all(sb); -+ buf_release_all(sb); -+ -+ /* close the block device */ -+ bdev_close(sb); -+ -+ if (p_fs->dev_ejected) { -+ pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n"); -+ err = FFS_MEDIAERR; -+ } -+ -+ buf_shutdown(sb); -+ -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ up(&z_sem); -+ -+ pr_info("[EXFAT] unmounted successfully\n"); -+ -+ return err; -+} -+ -+static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) -+{ -+ int err = FFS_SUCCESS; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ /* check the validity of pointer parameters */ -+ if (info == NULL) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ if (p_fs->used_clusters == (u32) ~0) -+ p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb); -+ -+ info->FatType = p_fs->vol_type; -+ info->ClusterSize = p_fs->cluster_size; -+ info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ -+ info->UsedClusters = p_fs->used_clusters; -+ info->FreeClusters = info->NumClusters - info->UsedClusters; -+ -+ if (p_fs->dev_ejected) -+ err = FFS_MEDIAERR; -+ -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return err; -+} -+ -+static int ffsSyncVol(struct super_block *sb, bool do_sync) -+{ -+ int err = FFS_SUCCESS; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* synchronize the file system */ -+ fs_sync(sb, do_sync); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+ -+ if (p_fs->dev_ejected) -+ err = FFS_MEDIAERR; -+ -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return err; -+} -+ -+/*----------------------------------------------------------------------*/ -+/* File Operation Functions */ -+/*----------------------------------------------------------------------*/ -+ -+static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) -+{ -+ int ret, dentry, num_entries; -+ struct chain_t dir; -+ struct uni_name_t uni_name; -+ struct dos_name_t dos_name; -+ struct dentry_t *ep, *ep2; -+ struct entry_set_cache_t *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ /* check the validity of pointer parameters */ -+ if ((fid == NULL) || (path == NULL) || (*path == '\0')) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check the validity of directory name in the given pathname */ -+ ret = resolve_path(inode, path, &dir, &uni_name); -+ if (ret) -+ goto out; -+ -+ ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, -+ &dos_name); -+ if (ret) -+ goto out; -+ -+ /* search the file name for directories */ -+ dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, -+ &dos_name, TYPE_ALL); -+ if (dentry < -1) { -+ return FFS_NOTFOUND; -+ goto out; -+ } -+ -+ fid->dir.dir = dir.dir; -+ fid->dir.size = dir.size; -+ fid->dir.flags = dir.flags; -+ fid->entry = dentry; -+ -+ if (dentry == -1) { -+ fid->type = TYPE_DIR; -+ fid->rwoffset = 0; -+ fid->hint_last_off = -1; -+ -+ fid->attr = ATTR_SUBDIR; -+ fid->flags = 0x01; -+ fid->size = 0; -+ fid->start_clu = p_fs->root_dir; -+ } else { -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &dir, dentry, -+ ES_2_ENTRIES, &ep); -+ if (!es) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep+1; -+ } else { -+ ep = get_entry_in_dir(sb, &dir, dentry, NULL); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep; -+ } -+ -+ fid->type = p_fs->fs_func->get_entry_type(ep); -+ fid->rwoffset = 0; -+ fid->hint_last_off = -1; -+ fid->attr = p_fs->fs_func->get_entry_attr(ep); -+ -+ fid->size = p_fs->fs_func->get_entry_size(ep2); -+ if ((fid->type == TYPE_FILE) && (fid->size == 0)) { -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ fid->start_clu = CLUSTER_32(~0); -+ } else { -+ fid->flags = p_fs->fs_func->get_entry_flag(ep2); -+ fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2); -+ } -+ -+ if (p_fs->vol_type == EXFAT) -+ release_entry_set(es); -+ } -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsCreateFile(struct inode *inode, char *path, u8 mode, -+ struct file_id_t *fid) -+{ -+ struct chain_t dir; -+ struct uni_name_t uni_name; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ int ret; -+ -+ /* check the validity of pointer parameters */ -+ if ((fid == NULL) || (path == NULL) || (*path == '\0')) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check the validity of directory name in the given pathname */ -+ ret = resolve_path(inode, path, &dir, &uni_name); -+ if (ret) -+ goto out; -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* create a new file */ -+ ret = create_file(inode, &dir, &uni_name, mode, fid); -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, -+ u64 count, u64 *rcount) -+{ -+ s32 offset, sec_offset, clu_offset; -+ u32 clu; -+ int ret; -+ sector_t LogSector; -+ u64 oneblkread, read_bytes; -+ struct buffer_head *tmp_bh = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ /* check the validity of the given file id */ -+ if (fid == NULL) -+ return FFS_INVALIDFID; -+ -+ /* check the validity of pointer parameters */ -+ if (buffer == NULL) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check if the given file ID is opened */ -+ if (fid->type != TYPE_FILE) { -+ ret = FFS_PERMISSIONERR; -+ goto out; -+ } -+ -+ if (fid->rwoffset > fid->size) -+ fid->rwoffset = fid->size; -+ -+ if (count > (fid->size - fid->rwoffset)) -+ count = fid->size - fid->rwoffset; -+ -+ if (count == 0) { -+ if (rcount != NULL) -+ *rcount = 0; -+ ret = FFS_EOF; -+ goto out; -+ } -+ -+ read_bytes = 0; -+ -+ while (count > 0) { -+ clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -+ clu = fid->start_clu; -+ -+ if (fid->flags == 0x03) { -+ clu += clu_offset; -+ } else { -+ /* hint information */ -+ if ((clu_offset > 0) && (fid->hint_last_off > 0) && -+ (clu_offset >= fid->hint_last_off)) { -+ clu_offset -= fid->hint_last_off; -+ clu = fid->hint_last_clu; -+ } -+ -+ while (clu_offset > 0) { -+ /* clu = FAT_read(sb, clu); */ -+ if (FAT_read(sb, clu, &clu) == -1) -+ return FFS_MEDIAERR; -+ -+ clu_offset--; -+ } -+ } -+ -+ /* hint information */ -+ fid->hint_last_off = (s32)(fid->rwoffset >> -+ p_fs->cluster_size_bits); -+ fid->hint_last_clu = clu; -+ -+ /* byte offset in cluster */ -+ offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); -+ -+ /* sector offset in cluster */ -+ sec_offset = offset >> p_bd->sector_size_bits; -+ -+ /* byte offset in sector */ -+ offset &= p_bd->sector_size_mask; -+ -+ LogSector = START_SECTOR(clu) + sec_offset; -+ -+ oneblkread = (u64)(p_bd->sector_size - offset); -+ if (oneblkread > count) -+ oneblkread = count; -+ -+ if ((offset == 0) && (oneblkread == p_bd->sector_size)) { -+ if (sector_read(sb, LogSector, &tmp_bh, 1) != -+ FFS_SUCCESS) -+ goto err_out; -+ memcpy((char *)buffer + read_bytes, -+ (char *)tmp_bh->b_data, (s32)oneblkread); -+ } else { -+ if (sector_read(sb, LogSector, &tmp_bh, 1) != -+ FFS_SUCCESS) -+ goto err_out; -+ memcpy((char *)buffer + read_bytes, -+ (char *)tmp_bh->b_data + offset, -+ (s32)oneblkread); -+ } -+ count -= oneblkread; -+ read_bytes += oneblkread; -+ fid->rwoffset += oneblkread; -+ } -+ brelse(tmp_bh); -+ -+/* How did this ever work and not leak a brlse()?? */ -+err_out: -+ /* set the size of read bytes */ -+ if (rcount != NULL) -+ *rcount = read_bytes; -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, -+ void *buffer, u64 count, u64 *wcount) -+{ -+ s32 modified = FALSE, offset, sec_offset, clu_offset; -+ s32 num_clusters, num_alloc, num_alloced = (s32) ~0; -+ int ret = 0; -+ u32 clu, last_clu; -+ sector_t LogSector, sector = 0; -+ u64 oneblkwrite, write_bytes; -+ struct chain_t new_clu; -+ struct timestamp_t tm; -+ struct dentry_t *ep, *ep2; -+ struct entry_set_cache_t *es = NULL; -+ struct buffer_head *tmp_bh = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ -+ /* check the validity of the given file id */ -+ if (fid == NULL) -+ return FFS_INVALIDFID; -+ -+ /* check the validity of pointer parameters */ -+ if (buffer == NULL) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check if the given file ID is opened */ -+ if (fid->type != TYPE_FILE) { -+ ret = FFS_PERMISSIONERR; -+ goto out; -+ } -+ -+ if (fid->rwoffset > fid->size) -+ fid->rwoffset = fid->size; -+ -+ if (count == 0) { -+ if (wcount != NULL) -+ *wcount = 0; -+ ret = FFS_SUCCESS; -+ goto out; -+ } -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ if (fid->size == 0) -+ num_clusters = 0; -+ else -+ num_clusters = (s32)((fid->size-1) >> -+ p_fs->cluster_size_bits) + 1; -+ -+ write_bytes = 0; -+ -+ while (count > 0) { -+ clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -+ clu = last_clu = fid->start_clu; -+ -+ if (fid->flags == 0x03) { -+ if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -+ last_clu += clu_offset - 1; -+ -+ if (clu_offset == num_clusters) -+ clu = CLUSTER_32(~0); -+ else -+ clu += clu_offset; -+ } -+ } else { -+ /* hint information */ -+ if ((clu_offset > 0) && (fid->hint_last_off > 0) && -+ (clu_offset >= fid->hint_last_off)) { -+ clu_offset -= fid->hint_last_off; -+ clu = fid->hint_last_clu; -+ } -+ -+ while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { -+ last_clu = clu; -+ /* clu = FAT_read(sb, clu); */ -+ if (FAT_read(sb, clu, &clu) == -1) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ clu_offset--; -+ } -+ } -+ -+ if (clu == CLUSTER_32(~0)) { -+ num_alloc = (s32)((count - 1) >> -+ p_fs->cluster_size_bits) + 1; -+ new_clu.dir = (last_clu == CLUSTER_32(~0)) ? -+ CLUSTER_32(~0) : last_clu+1; -+ new_clu.size = 0; -+ new_clu.flags = fid->flags; -+ -+ /* (1) allocate a chain of clusters */ -+ num_alloced = p_fs->fs_func->alloc_cluster(sb, -+ num_alloc, -+ &new_clu); -+ if (num_alloced == 0) -+ break; -+ else if (num_alloced < 0) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ -+ /* (2) append to the FAT chain */ -+ if (last_clu == CLUSTER_32(~0)) { -+ if (new_clu.flags == 0x01) -+ fid->flags = 0x01; -+ fid->start_clu = new_clu.dir; -+ modified = TRUE; -+ } else { -+ if (new_clu.flags != fid->flags) { -+ exfat_chain_cont_cluster(sb, -+ fid->start_clu, -+ num_clusters); -+ fid->flags = 0x01; -+ modified = TRUE; -+ } -+ if (new_clu.flags == 0x01) -+ FAT_write(sb, last_clu, new_clu.dir); -+ } -+ -+ num_clusters += num_alloced; -+ clu = new_clu.dir; -+ } -+ -+ /* hint information */ -+ fid->hint_last_off = (s32)(fid->rwoffset >> -+ p_fs->cluster_size_bits); -+ fid->hint_last_clu = clu; -+ -+ /* byte offset in cluster */ -+ offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); -+ -+ /* sector offset in cluster */ -+ sec_offset = offset >> p_bd->sector_size_bits; -+ -+ /* byte offset in sector */ -+ offset &= p_bd->sector_size_mask; -+ -+ LogSector = START_SECTOR(clu) + sec_offset; -+ -+ oneblkwrite = (u64)(p_bd->sector_size - offset); -+ if (oneblkwrite > count) -+ oneblkwrite = count; -+ -+ if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { -+ if (sector_read(sb, LogSector, &tmp_bh, 0) != -+ FFS_SUCCESS) -+ goto err_out; -+ memcpy((char *)tmp_bh->b_data, -+ (char *)buffer + write_bytes, (s32)oneblkwrite); -+ if (sector_write(sb, LogSector, tmp_bh, 0) != -+ FFS_SUCCESS) { -+ brelse(tmp_bh); -+ goto err_out; -+ } -+ } else { -+ if ((offset > 0) || -+ ((fid->rwoffset+oneblkwrite) < fid->size)) { -+ if (sector_read(sb, LogSector, &tmp_bh, 1) != -+ FFS_SUCCESS) -+ goto err_out; -+ } else { -+ if (sector_read(sb, LogSector, &tmp_bh, 0) != -+ FFS_SUCCESS) -+ goto err_out; -+ } -+ -+ memcpy((char *)tmp_bh->b_data + offset, -+ (char *)buffer + write_bytes, (s32)oneblkwrite); -+ if (sector_write(sb, LogSector, tmp_bh, 0) != -+ FFS_SUCCESS) { -+ brelse(tmp_bh); -+ goto err_out; -+ } -+ } -+ -+ count -= oneblkwrite; -+ write_bytes += oneblkwrite; -+ fid->rwoffset += oneblkwrite; -+ -+ fid->attr |= ATTR_ARCHIVE; -+ -+ if (fid->size < fid->rwoffset) { -+ fid->size = fid->rwoffset; -+ modified = TRUE; -+ } -+ } -+ -+ brelse(tmp_bh); -+ -+ /* (3) update the direcoty entry */ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (es == NULL) -+ goto err_out; -+ ep2 = ep+1; -+ } else { -+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); -+ if (!ep) -+ goto err_out; -+ ep2 = ep; -+ } -+ -+ p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); -+ p_fs->fs_func->set_entry_attr(ep, fid->attr); -+ -+ if (p_fs->vol_type != EXFAT) -+ buf_modify(sb, sector); -+ -+ if (modified) { -+ if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags) -+ p_fs->fs_func->set_entry_flag(ep2, fid->flags); -+ -+ if (p_fs->fs_func->get_entry_size(ep2) != fid->size) -+ p_fs->fs_func->set_entry_size(ep2, fid->size); -+ -+ if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu) -+ p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu); -+ -+ if (p_fs->vol_type != EXFAT) -+ buf_modify(sb, sector); -+ } -+ -+ if (p_fs->vol_type == EXFAT) { -+ update_dir_checksum_with_entry_set(sb, es); -+ release_entry_set(es); -+ } -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+err_out: -+ /* set the size of written bytes */ -+ if (wcount != NULL) -+ *wcount = write_bytes; -+ -+ if (num_alloced == 0) -+ ret = FFS_FULL; -+ -+ else if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) -+{ -+ s32 num_clusters; -+ u32 last_clu = CLUSTER_32(0); -+ int ret = 0; -+ sector_t sector = 0; -+ struct chain_t clu; -+ struct timestamp_t tm; -+ struct dentry_t *ep, *ep2; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ struct entry_set_cache_t *es = NULL; -+ -+ pr_debug("%s entered (inode %p size %llu)\n", __func__, inode, -+ new_size); -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check if the given file ID is opened */ -+ if (fid->type != TYPE_FILE) { -+ ret = FFS_PERMISSIONERR; -+ goto out; -+ } -+ -+ if (fid->size != old_size) { -+ pr_err("[EXFAT] truncate : can't skip it because of size-mismatch(old:%lld->fid:%lld).\n", -+ old_size, fid->size); -+ } -+ -+ if (old_size <= new_size) { -+ ret = FFS_SUCCESS; -+ goto out; -+ } -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ clu.dir = fid->start_clu; -+ clu.size = (s32)((old_size-1) >> p_fs->cluster_size_bits) + 1; -+ clu.flags = fid->flags; -+ -+ if (new_size > 0) { -+ num_clusters = (s32)((new_size-1) >> -+ p_fs->cluster_size_bits) + 1; -+ -+ if (clu.flags == 0x03) { -+ clu.dir += num_clusters; -+ } else { -+ while (num_clusters > 0) { -+ last_clu = clu.dir; -+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) -+ return FFS_MEDIAERR; -+ num_clusters--; -+ } -+ } -+ -+ clu.size -= num_clusters; -+ } -+ -+ fid->size = new_size; -+ fid->attr |= ATTR_ARCHIVE; -+ if (new_size == 0) { -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ fid->start_clu = CLUSTER_32(~0); -+ } -+ -+ /* (1) update the directory entry */ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (es == NULL) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep+1; -+ } else { -+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep; -+ } -+ -+ p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); -+ p_fs->fs_func->set_entry_attr(ep, fid->attr); -+ -+ p_fs->fs_func->set_entry_size(ep2, new_size); -+ if (new_size == 0) { -+ p_fs->fs_func->set_entry_flag(ep2, 0x01); -+ p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0)); -+ } -+ -+ if (p_fs->vol_type != EXFAT) -+ buf_modify(sb, sector); -+ else { -+ update_dir_checksum_with_entry_set(sb, es); -+ release_entry_set(es); -+ } -+ -+ /* (2) cut off from the FAT chain */ -+ if (last_clu != CLUSTER_32(0)) { -+ if (fid->flags == 0x01) -+ FAT_write(sb, last_clu, CLUSTER_32(~0)); -+ } -+ -+ /* (3) free the clusters */ -+ p_fs->fs_func->free_cluster(sb, &clu, 0); -+ -+ /* hint information */ -+ fid->hint_last_off = -1; -+ if (fid->rwoffset > fid->size) -+ fid->rwoffset = fid->size; -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ pr_debug("%s exited (%d)\n", __func__, ret); -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static void update_parent_info(struct file_id_t *fid, -+ struct inode *parent_inode) -+{ -+ struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); -+ struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid); -+ -+ if (unlikely((parent_fid->flags != fid->dir.flags) || -+ (parent_fid->size != -+ (fid->dir.size << p_fs->cluster_size_bits)) || -+ (parent_fid->start_clu != fid->dir.dir))) { -+ fid->dir.dir = parent_fid->start_clu; -+ fid->dir.flags = parent_fid->flags; -+ fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1)) -+ >> p_fs->cluster_size_bits); -+ } -+} -+ -+static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, -+ struct inode *new_parent_inode, struct dentry *new_dentry) -+{ -+ s32 ret; -+ s32 dentry; -+ struct chain_t olddir, newdir; -+ struct chain_t *p_dir = NULL; -+ struct uni_name_t uni_name; -+ struct dentry_t *ep; -+ struct super_block *sb = old_parent_inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ u8 *new_path = (u8 *) new_dentry->d_name.name; -+ struct inode *new_inode = new_dentry->d_inode; -+ int num_entries; -+ struct file_id_t *new_fid = NULL; -+ s32 new_entry = 0; -+ -+ /* check the validity of the given file id */ -+ if (fid == NULL) -+ return FFS_INVALIDFID; -+ -+ /* check the validity of pointer parameters */ -+ if ((new_path == NULL) || (*new_path == '\0')) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ update_parent_info(fid, old_parent_inode); -+ -+ olddir.dir = fid->dir.dir; -+ olddir.size = fid->dir.size; -+ olddir.flags = fid->dir.flags; -+ -+ dentry = fid->entry; -+ -+ /* check if the old file is "." or ".." */ -+ if (p_fs->vol_type != EXFAT) { -+ if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) { -+ ret = FFS_PERMISSIONERR; -+ goto out2; -+ } -+ } -+ -+ ep = get_entry_in_dir(sb, &olddir, dentry, NULL); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out2; -+ } -+ -+ if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) { -+ ret = FFS_PERMISSIONERR; -+ goto out2; -+ } -+ -+ /* check whether new dir is existing directory and empty */ -+ if (new_inode) { -+ u32 entry_type; -+ -+ ret = FFS_MEDIAERR; -+ new_fid = &EXFAT_I(new_inode)->fid; -+ -+ update_parent_info(new_fid, new_parent_inode); -+ -+ p_dir = &(new_fid->dir); -+ new_entry = new_fid->entry; -+ ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); -+ if (!ep) -+ goto out; -+ -+ entry_type = p_fs->fs_func->get_entry_type(ep); -+ -+ if (entry_type == TYPE_DIR) { -+ struct chain_t new_clu; -+ -+ new_clu.dir = new_fid->start_clu; -+ new_clu.size = (s32)((new_fid->size - 1) >> -+ p_fs->cluster_size_bits) + 1; -+ new_clu.flags = new_fid->flags; -+ -+ if (!is_dir_empty(sb, &new_clu)) { -+ ret = FFS_FILEEXIST; -+ goto out; -+ } -+ } -+ } -+ -+ /* check the validity of directory name in the given new pathname */ -+ ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); -+ if (ret) -+ goto out2; -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ if (olddir.dir == newdir.dir) -+ ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name, -+ fid); -+ else -+ ret = move_file(new_parent_inode, &olddir, dentry, &newdir, -+ &uni_name, fid); -+ -+ if ((ret == FFS_SUCCESS) && new_inode) { -+ /* delete entries of new_dir */ -+ ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); -+ if (!ep) -+ goto out; -+ -+ num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, -+ new_entry, ep); -+ if (num_entries < 0) -+ goto out; -+ p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0, -+ num_entries+1); -+ } -+out: -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+out2: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) -+{ -+ s32 dentry; -+ int ret = FFS_SUCCESS; -+ struct chain_t dir, clu_to_free; -+ struct dentry_t *ep; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ /* check the validity of the given file id */ -+ if (fid == NULL) -+ return FFS_INVALIDFID; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ dir.dir = fid->dir.dir; -+ dir.size = fid->dir.size; -+ dir.flags = fid->dir.flags; -+ -+ dentry = fid->entry; -+ -+ ep = get_entry_in_dir(sb, &dir, dentry, NULL); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ -+ if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) { -+ ret = FFS_PERMISSIONERR; -+ goto out; -+ } -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* (1) update the directory entry */ -+ remove_file(inode, &dir, dentry); -+ -+ clu_to_free.dir = fid->start_clu; -+ clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; -+ clu_to_free.flags = fid->flags; -+ -+ /* (2) free the clusters */ -+ p_fs->fs_func->free_cluster(sb, &clu_to_free, 0); -+ -+ fid->size = 0; -+ fid->start_clu = CLUSTER_32(~0); -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+#if 0 -+/* Not currently wired up */ -+static int ffsSetAttr(struct inode *inode, u32 attr) -+{ -+ u32 type; -+ int ret = FFS_SUCCESS; -+ sector_t sector = 0; -+ struct dentry_t *ep; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -+ struct entry_set_cache_t *es = NULL; -+ -+ if (fid->attr == attr) { -+ if (p_fs->dev_ejected) -+ return FFS_MEDIAERR; -+ return FFS_SUCCESS; -+ } -+ -+ if (is_dir) { -+ if ((fid->dir.dir == p_fs->root_dir) && -+ (fid->entry == -1)) { -+ if (p_fs->dev_ejected) -+ return FFS_MEDIAERR; -+ return FFS_SUCCESS; -+ } -+ } -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* get the directory entry of given file */ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (es == NULL) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } else { -+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } -+ -+ type = p_fs->fs_func->get_entry_type(ep); -+ -+ if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || -+ ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ else -+ ret = FFS_ERROR; -+ -+ if (p_fs->vol_type == EXFAT) -+ release_entry_set(es); -+ goto out; -+ } -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* set the file attribute */ -+ fid->attr = attr; -+ p_fs->fs_func->set_entry_attr(ep, attr); -+ -+ if (p_fs->vol_type != EXFAT) -+ buf_modify(sb, sector); -+ else { -+ update_dir_checksum_with_entry_set(sb, es); -+ release_entry_set(es); -+ } -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+#endif -+ -+static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) -+{ -+ sector_t sector = 0; -+ s32 count; -+ int ret = FFS_SUCCESS; -+ struct chain_t dir; -+ struct uni_name_t uni_name; -+ struct timestamp_t tm; -+ struct dentry_t *ep, *ep2; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ struct entry_set_cache_t *es = NULL; -+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -+ -+ pr_debug("%s entered\n", __func__); -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ if (is_dir) { -+ if ((fid->dir.dir == p_fs->root_dir) && -+ (fid->entry == -1)) { -+ info->Attr = ATTR_SUBDIR; -+ memset((char *)&info->CreateTimestamp, 0, -+ sizeof(struct date_time_t)); -+ memset((char *)&info->ModifyTimestamp, 0, -+ sizeof(struct date_time_t)); -+ memset((char *)&info->AccessTimestamp, 0, -+ sizeof(struct date_time_t)); -+ strcpy(info->ShortName, "."); -+ strcpy(info->Name, "."); -+ -+ dir.dir = p_fs->root_dir; -+ dir.flags = 0x01; -+ -+ if (p_fs->root_dir == CLUSTER_32(0)) { -+ /* FAT16 root_dir */ -+ info->Size = p_fs->dentries_in_root << -+ DENTRY_SIZE_BITS; -+ } else { -+ info->Size = count_num_clusters(sb, &dir) << -+ p_fs->cluster_size_bits; -+ } -+ -+ count = count_dos_name_entries(sb, &dir, TYPE_DIR); -+ if (count < 0) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ info->NumSubdirs = count; -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } -+ -+ /* get the directory entry of given file or directory */ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, -+ ES_2_ENTRIES, &ep); -+ if (es == NULL) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep+1; -+ } else { -+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep; -+ buf_lock(sb, sector); -+ } -+ -+ /* set FILE_INFO structure using the acquired struct dentry_t */ -+ info->Attr = p_fs->fs_func->get_entry_attr(ep); -+ -+ p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); -+ info->CreateTimestamp.Year = tm.year; -+ info->CreateTimestamp.Month = tm.mon; -+ info->CreateTimestamp.Day = tm.day; -+ info->CreateTimestamp.Hour = tm.hour; -+ info->CreateTimestamp.Minute = tm.min; -+ info->CreateTimestamp.Second = tm.sec; -+ info->CreateTimestamp.MilliSecond = 0; -+ -+ p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); -+ info->ModifyTimestamp.Year = tm.year; -+ info->ModifyTimestamp.Month = tm.mon; -+ info->ModifyTimestamp.Day = tm.day; -+ info->ModifyTimestamp.Hour = tm.hour; -+ info->ModifyTimestamp.Minute = tm.min; -+ info->ModifyTimestamp.Second = tm.sec; -+ info->ModifyTimestamp.MilliSecond = 0; -+ -+ memset((char *) &info->AccessTimestamp, 0, sizeof(struct date_time_t)); -+ -+ *(uni_name.name) = 0x0; -+ /* XXX this is very bad for exfat cuz name is already included in es. -+ * API should be revised -+ */ -+ p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, -+ uni_name.name); -+ if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT) -+ get_uni_name_from_dos_entry(sb, (struct dos_dentry_t *)ep, -+ &uni_name, 0x1); -+ nls_uniname_to_cstring(sb, info->Name, &uni_name); -+ -+ if (p_fs->vol_type == EXFAT) { -+ info->NumSubdirs = 2; -+ } else { -+ buf_unlock(sb, sector); -+ get_uni_name_from_dos_entry(sb, (struct dos_dentry_t *)ep, -+ &uni_name, 0x0); -+ nls_uniname_to_cstring(sb, info->ShortName, &uni_name); -+ info->NumSubdirs = 0; -+ } -+ -+ info->Size = p_fs->fs_func->get_entry_size(ep2); -+ -+ if (p_fs->vol_type == EXFAT) -+ release_entry_set(es); -+ -+ if (is_dir) { -+ dir.dir = fid->start_clu; -+ dir.flags = 0x01; -+ -+ if (info->Size == 0) -+ info->Size = (u64)count_num_clusters(sb, &dir) << -+ p_fs->cluster_size_bits; -+ -+ count = count_dos_name_entries(sb, &dir, TYPE_DIR); -+ if (count < 0) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ info->NumSubdirs += count; -+ } -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ pr_debug("%s exited successfully\n", __func__); -+ return ret; -+} -+ -+static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) -+{ -+ sector_t sector = 0; -+ int ret = FFS_SUCCESS; -+ struct timestamp_t tm; -+ struct dentry_t *ep, *ep2; -+ struct entry_set_cache_t *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; -+ -+ pr_debug("%s entered (inode %p info %p\n", __func__, inode, info); -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ if (is_dir) { -+ if ((fid->dir.dir == p_fs->root_dir) && -+ (fid->entry == -1)) { -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ ret = FFS_SUCCESS; -+ goto out; -+ } -+ } -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* get the directory entry of given file or directory */ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (es == NULL) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep+1; -+ } else { -+ /* for other than exfat */ -+ ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ ep2 = ep; -+ } -+ -+ p_fs->fs_func->set_entry_attr(ep, info->Attr); -+ -+ /* set FILE_INFO structure using the acquired struct dentry_t */ -+ tm.sec = info->CreateTimestamp.Second; -+ tm.min = info->CreateTimestamp.Minute; -+ tm.hour = info->CreateTimestamp.Hour; -+ tm.day = info->CreateTimestamp.Day; -+ tm.mon = info->CreateTimestamp.Month; -+ tm.year = info->CreateTimestamp.Year; -+ p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE); -+ -+ tm.sec = info->ModifyTimestamp.Second; -+ tm.min = info->ModifyTimestamp.Minute; -+ tm.hour = info->ModifyTimestamp.Hour; -+ tm.day = info->ModifyTimestamp.Day; -+ tm.mon = info->ModifyTimestamp.Month; -+ tm.year = info->ModifyTimestamp.Year; -+ p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY); -+ -+ p_fs->fs_func->set_entry_size(ep2, info->Size); -+ -+ if (p_fs->vol_type != EXFAT) { -+ buf_modify(sb, sector); -+ } else { -+ update_dir_checksum_with_entry_set(sb, es); -+ release_entry_set(es); -+ } -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ pr_debug("%s exited (%d)\n", __func__, ret); -+ -+ return ret; -+} -+ -+static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) -+{ -+ s32 num_clusters, num_alloced, modified = FALSE; -+ u32 last_clu; -+ int ret = FFS_SUCCESS; -+ sector_t sector = 0; -+ struct chain_t new_clu; -+ struct dentry_t *ep; -+ struct entry_set_cache_t *es = NULL; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ -+ /* check the validity of pointer parameters */ -+ if (clu == NULL) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; -+ -+ if (EXFAT_I(inode)->mmu_private == 0) -+ num_clusters = 0; -+ else -+ num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >> -+ p_fs->cluster_size_bits) + 1; -+ -+ *clu = last_clu = fid->start_clu; -+ -+ if (fid->flags == 0x03) { -+ if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -+ last_clu += clu_offset - 1; -+ -+ if (clu_offset == num_clusters) -+ *clu = CLUSTER_32(~0); -+ else -+ *clu += clu_offset; -+ } -+ } else { -+ /* hint information */ -+ if ((clu_offset > 0) && (fid->hint_last_off > 0) && -+ (clu_offset >= fid->hint_last_off)) { -+ clu_offset -= fid->hint_last_off; -+ *clu = fid->hint_last_clu; -+ } -+ -+ while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { -+ last_clu = *clu; -+ if (FAT_read(sb, *clu, clu) == -1) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ clu_offset--; -+ } -+ } -+ -+ if (*clu == CLUSTER_32(~0)) { -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : -+ last_clu + 1; -+ new_clu.size = 0; -+ new_clu.flags = fid->flags; -+ -+ /* (1) allocate a cluster */ -+ num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu); -+ if (num_alloced < 0) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } else if (num_alloced == 0) { -+ ret = FFS_FULL; -+ goto out; -+ } -+ -+ /* (2) append to the FAT chain */ -+ if (last_clu == CLUSTER_32(~0)) { -+ if (new_clu.flags == 0x01) -+ fid->flags = 0x01; -+ fid->start_clu = new_clu.dir; -+ modified = TRUE; -+ } else { -+ if (new_clu.flags != fid->flags) { -+ exfat_chain_cont_cluster(sb, fid->start_clu, -+ num_clusters); -+ fid->flags = 0x01; -+ modified = TRUE; -+ } -+ if (new_clu.flags == 0x01) -+ FAT_write(sb, last_clu, new_clu.dir); -+ } -+ -+ num_clusters += num_alloced; -+ *clu = new_clu.dir; -+ -+ if (p_fs->vol_type == EXFAT) { -+ es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, -+ ES_ALL_ENTRIES, &ep); -+ if (es == NULL) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ /* get stream entry */ -+ ep++; -+ } -+ -+ /* (3) update directory entry */ -+ if (modified) { -+ if (p_fs->vol_type != EXFAT) { -+ ep = get_entry_in_dir(sb, &(fid->dir), -+ fid->entry, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } -+ -+ if (p_fs->fs_func->get_entry_flag(ep) != fid->flags) -+ p_fs->fs_func->set_entry_flag(ep, fid->flags); -+ -+ if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu) -+ p_fs->fs_func->set_entry_clu0(ep, -+ fid->start_clu); -+ -+ if (p_fs->vol_type != EXFAT) -+ buf_modify(sb, sector); -+ } -+ -+ if (p_fs->vol_type == EXFAT) { -+ update_dir_checksum_with_entry_set(sb, es); -+ release_entry_set(es); -+ } -+ -+ /* add number of new blocks to inode */ -+ inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); -+ } -+ -+ /* hint information */ -+ fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); -+ fid->hint_last_clu = *clu; -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+/*----------------------------------------------------------------------*/ -+/* Directory Operation Functions */ -+/*----------------------------------------------------------------------*/ -+ -+static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) -+{ -+ int ret = FFS_SUCCESS; -+ struct chain_t dir; -+ struct uni_name_t uni_name; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ /* check the validity of pointer parameters */ -+ if ((fid == NULL) || (path == NULL) || (*path == '\0')) -+ return FFS_ERROR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ /* check the validity of directory name in the given old pathname */ -+ ret = resolve_path(inode, path, &dir, &uni_name); -+ if (ret) -+ goto out; -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ ret = create_dir(inode, &dir, &uni_name, fid); -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) -+{ -+ int i, dentry, clu_offset; -+ int ret = FFS_SUCCESS; -+ s32 dentries_per_clu, dentries_per_clu_bits = 0; -+ u32 type; -+ sector_t sector; -+ struct chain_t dir, clu; -+ struct uni_name_t uni_name; -+ struct timestamp_t tm; -+ struct dentry_t *ep; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct fs_func *fs_func = p_fs->fs_func; -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ -+ /* check the validity of pointer parameters */ -+ if (dir_entry == NULL) -+ return FFS_ERROR; -+ -+ /* check if the given file ID is opened */ -+ if (fid->type != TYPE_DIR) -+ return FFS_PERMISSIONERR; -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ if (fid->entry == -1) { -+ dir.dir = p_fs->root_dir; -+ dir.flags = 0x01; -+ } else { -+ dir.dir = fid->start_clu; -+ dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); -+ dir.flags = fid->flags; -+ } -+ -+ dentry = (s32)fid->rwoffset; -+ -+ if (dir.dir == CLUSTER_32(0)) { -+ /* FAT16 root_dir */ -+ dentries_per_clu = p_fs->dentries_in_root; -+ -+ if (dentry == dentries_per_clu) { -+ clu.dir = CLUSTER_32(~0); -+ } else { -+ clu.dir = dir.dir; -+ clu.size = dir.size; -+ clu.flags = dir.flags; -+ } -+ } else { -+ dentries_per_clu = p_fs->dentries_per_clu; -+ dentries_per_clu_bits = ilog2(dentries_per_clu); -+ -+ clu_offset = dentry >> dentries_per_clu_bits; -+ clu.dir = dir.dir; -+ clu.size = dir.size; -+ clu.flags = dir.flags; -+ -+ if (clu.flags == 0x03) { -+ clu.dir += clu_offset; -+ clu.size -= clu_offset; -+ } else { -+ /* hint_information */ -+ if ((clu_offset > 0) && (fid->hint_last_off > 0) && -+ (clu_offset >= fid->hint_last_off)) { -+ clu_offset -= fid->hint_last_off; -+ clu.dir = fid->hint_last_clu; -+ } -+ -+ while (clu_offset > 0) { -+ /* clu.dir = FAT_read(sb, clu.dir); */ -+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ clu_offset--; -+ } -+ } -+ } -+ -+ while (clu.dir != CLUSTER_32(~0)) { -+ if (p_fs->dev_ejected) -+ break; -+ -+ if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ -+ i = dentry % dentries_per_clu; -+ else -+ i = dentry & (dentries_per_clu-1); -+ -+ for ( ; i < dentries_per_clu; i++, dentry++) { -+ ep = get_entry_in_dir(sb, &clu, i, §or); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ type = fs_func->get_entry_type(ep); -+ -+ if (type == TYPE_UNUSED) -+ break; -+ -+ if ((type != TYPE_FILE) && (type != TYPE_DIR)) -+ continue; -+ -+ buf_lock(sb, sector); -+ dir_entry->Attr = fs_func->get_entry_attr(ep); -+ -+ fs_func->get_entry_time(ep, &tm, TM_CREATE); -+ dir_entry->CreateTimestamp.Year = tm.year; -+ dir_entry->CreateTimestamp.Month = tm.mon; -+ dir_entry->CreateTimestamp.Day = tm.day; -+ dir_entry->CreateTimestamp.Hour = tm.hour; -+ dir_entry->CreateTimestamp.Minute = tm.min; -+ dir_entry->CreateTimestamp.Second = tm.sec; -+ dir_entry->CreateTimestamp.MilliSecond = 0; -+ -+ fs_func->get_entry_time(ep, &tm, TM_MODIFY); -+ dir_entry->ModifyTimestamp.Year = tm.year; -+ dir_entry->ModifyTimestamp.Month = tm.mon; -+ dir_entry->ModifyTimestamp.Day = tm.day; -+ dir_entry->ModifyTimestamp.Hour = tm.hour; -+ dir_entry->ModifyTimestamp.Minute = tm.min; -+ dir_entry->ModifyTimestamp.Second = tm.sec; -+ dir_entry->ModifyTimestamp.MilliSecond = 0; -+ -+ memset((char *)&dir_entry->AccessTimestamp, 0, -+ sizeof(struct date_time_t)); -+ -+ *(uni_name.name) = 0x0; -+ fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, -+ uni_name.name); -+ if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT) -+ get_uni_name_from_dos_entry(sb, -+ (struct dos_dentry_t *)ep, -+ &uni_name, 0x1); -+ nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); -+ buf_unlock(sb, sector); -+ -+ if (p_fs->vol_type == EXFAT) { -+ ep = get_entry_in_dir(sb, &clu, i+1, NULL); -+ if (!ep) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } else { -+ get_uni_name_from_dos_entry(sb, -+ (struct dos_dentry_t *)ep, -+ &uni_name, 0x0); -+ nls_uniname_to_cstring(sb, dir_entry->ShortName, -+ &uni_name); -+ } -+ -+ dir_entry->Size = fs_func->get_entry_size(ep); -+ -+ /* hint information */ -+ if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ -+ } else { -+ fid->hint_last_off = dentry >> -+ dentries_per_clu_bits; -+ fid->hint_last_clu = clu.dir; -+ } -+ -+ fid->rwoffset = (s64) ++dentry; -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ -+ if (dir.dir == CLUSTER_32(0)) -+ break; /* FAT16 root_dir */ -+ -+ if (clu.flags == 0x03) { -+ if ((--clu.size) > 0) -+ clu.dir++; -+ else -+ clu.dir = CLUSTER_32(~0); -+ } else { -+ /* clu.dir = FAT_read(sb, clu.dir); */ -+ if (FAT_read(sb, clu.dir, &clu.dir) == -1) { -+ ret = FFS_MEDIAERR; -+ goto out; -+ } -+ } -+ } -+ -+ *(dir_entry->Name) = '\0'; -+ -+ fid->rwoffset = (s64) ++dentry; -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) -+{ -+ s32 dentry; -+ int ret = FFS_SUCCESS; -+ struct chain_t dir, clu_to_free; -+ struct super_block *sb = inode->i_sb; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ /* check the validity of the given file id */ -+ if (fid == NULL) -+ return FFS_INVALIDFID; -+ -+ dir.dir = fid->dir.dir; -+ dir.size = fid->dir.size; -+ dir.flags = fid->dir.flags; -+ -+ dentry = fid->entry; -+ -+ /* check if the file is "." or ".." */ -+ if (p_fs->vol_type != EXFAT) { -+ if ((dir.dir != p_fs->root_dir) && (dentry < 2)) -+ return FFS_PERMISSIONERR; -+ } -+ -+ /* acquire the lock for file system critical section */ -+ down(&p_fs->v_sem); -+ -+ clu_to_free.dir = fid->start_clu; -+ clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; -+ clu_to_free.flags = fid->flags; -+ -+ if (!is_dir_empty(sb, &clu_to_free)) { -+ ret = FFS_FILEEXIST; -+ goto out; -+ } -+ -+ fs_set_vol_flags(sb, VOL_DIRTY); -+ -+ /* (1) update the directory entry */ -+ remove_file(inode, &dir, dentry); -+ -+ /* (2) free the clusters */ -+ p_fs->fs_func->free_cluster(sb, &clu_to_free, 1); -+ -+ fid->size = 0; -+ fid->start_clu = CLUSTER_32(~0); -+ fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -+ -+#ifdef CONFIG_EXFAT_DELAYED_SYNC -+ fs_sync(sb, false); -+ fs_set_vol_flags(sb, VOL_CLEAN); -+#endif -+ -+ if (p_fs->dev_ejected) -+ ret = FFS_MEDIAERR; -+ -+out: -+ /* release the lock for file system critical section */ -+ up(&p_fs->v_sem); -+ -+ return ret; -+} -+ -+/*======================================================================*/ -+/* Directory Entry Operations */ -+/*======================================================================*/ -+ -+static int exfat_readdir(struct file *filp, struct dir_context *ctx) -+{ -+ struct inode *inode = file_inode(filp); -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -+ struct dir_entry_t de; -+ unsigned long inum; -+ loff_t cpos; -+ int err = 0; -+ -+ __lock_super(sb); -+ -+ cpos = ctx->pos; -+ /* Fake . and .. for the root directory. */ -+ if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { -+ while (cpos < 2) { -+ if (inode->i_ino == EXFAT_ROOT_INO) -+ inum = EXFAT_ROOT_INO; -+ else if (cpos == 0) -+ inum = inode->i_ino; -+ else /* (cpos == 1) */ -+ inum = parent_ino(filp->f_path.dentry); -+ -+ if (!dir_emit_dots(filp, ctx)) -+ goto out; -+ cpos++; -+ ctx->pos++; -+ } -+ if (cpos == 2) -+ cpos = 0; -+ } -+ if (cpos & (DENTRY_SIZE - 1)) { -+ err = -ENOENT; -+ goto out; -+ } -+ -+get_new: -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; -+ -+ err = ffsReadDir(inode, &de); -+ if (err) { -+ /* at least we tried to read a sector -+ * move cpos to next sector position (should be aligned) -+ */ -+ if (err == FFS_MEDIAERR) { -+ cpos += 1 << p_bd->sector_size_bits; -+ cpos &= ~((1 << p_bd->sector_size_bits)-1); -+ } -+ -+ err = -EIO; -+ goto end_of_dir; -+ } -+ -+ cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; -+ -+ if (!de.Name[0]) -+ goto end_of_dir; -+ -+ if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { -+ inum = inode->i_ino; -+ } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { -+ inum = parent_ino(filp->f_path.dentry); -+ } else { -+ loff_t i_pos = ((loff_t) EXFAT_I(inode)->fid.start_clu << 32) | -+ ((EXFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); -+ struct inode *tmp = exfat_iget(sb, i_pos); -+ -+ if (tmp) { -+ inum = tmp->i_ino; -+ iput(tmp); -+ } else { -+ inum = iunique(sb, EXFAT_ROOT_INO); -+ } -+ } -+ -+ if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, -+ (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) -+ goto out; -+ -+ ctx->pos = cpos; -+ goto get_new; -+ -+end_of_dir: -+ ctx->pos = cpos; -+out: -+ __unlock_super(sb); -+ return err; -+} -+ -+static int exfat_ioctl_volume_id(struct inode *dir) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ -+ return p_fs->vol_id; -+} -+ -+static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, -+ unsigned long arg) -+{ -+struct inode *inode = filp->f_path.dentry->d_inode; -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ unsigned int flags; -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+ switch (cmd) { -+ case EXFAT_IOCTL_GET_VOLUME_ID: -+ return exfat_ioctl_volume_id(inode); -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ case EXFAT_IOC_GET_DEBUGFLAGS: { -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ flags = sbi->debug_flags; -+ return put_user(flags, (int __user *)arg); -+ } -+ case EXFAT_IOC_SET_DEBUGFLAGS: { -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ if (get_user(flags, (int __user *) arg)) -+ return -EFAULT; -+ -+ __lock_super(sb); -+ sbi->debug_flags = flags; -+ __unlock_super(sb); -+ -+ return 0; -+ } -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ default: -+ return -ENOTTY; /* Inappropriate ioctl for device */ -+ } -+} -+ -+static const struct file_operations exfat_dir_operations = { -+ .llseek = generic_file_llseek, -+ .read = generic_read_dir, -+ .iterate = exfat_readdir, -+ .unlocked_ioctl = exfat_generic_ioctl, -+ .fsync = generic_file_fsync, -+}; -+ -+static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, -+ bool excl) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct file_id_t fid; -+ loff_t i_pos; -+ int err; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ err = ffsCreateFile(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); -+ if (err) { -+ if (err == FFS_INVALIDPATH) -+ err = -EINVAL; -+ else if (err == FFS_FILEEXIST) -+ err = -EEXIST; -+ else if (err == FFS_FULL) -+ err = -ENOSPC; -+ else if (err == FFS_NAMETOOLONG) -+ err = -ENAMETOOLONG; -+ else -+ err = -EIO; -+ goto out; -+ } -+ INC_IVERSION(dir); -+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ (void) exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); -+ -+ inode = exfat_build_inode(sb, &fid, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out; -+ } -+ INC_IVERSION(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); -+ /* -+ * timestamp is already written, so mark_inode_dirty() is unnecessary. -+ */ -+ -+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -+ d_instantiate(dentry, inode); -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_find(struct inode *dir, struct qstr *qname, -+ struct file_id_t *fid) -+{ -+ int err; -+ -+ if (qname->len == 0) -+ return -ENOENT; -+ -+ err = ffsLookupFile(dir, (u8 *) qname->name, fid); -+ if (err) -+ return -ENOENT; -+ -+ return 0; -+} -+ -+static int exfat_d_anon_disconn(struct dentry *dentry) -+{ -+ return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); -+} -+ -+static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, -+ unsigned int flags) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct dentry *alias; -+ int err; -+ struct file_id_t fid; -+ loff_t i_pos; -+ u64 ret; -+ mode_t i_mode; -+ -+ __lock_super(sb); -+ pr_debug("%s entered\n", __func__); -+ err = exfat_find(dir, &dentry->d_name, &fid); -+ if (err) { -+ if (err == -ENOENT) { -+ inode = NULL; -+ goto out; -+ } -+ goto error; -+ } -+ -+ i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); -+ inode = exfat_build_inode(sb, &fid, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto error; -+ } -+ -+ i_mode = inode->i_mode; -+ if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { -+ EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1, -+ GFP_KERNEL); -+ if (!EXFAT_I(inode)->target) { -+ err = -ENOMEM; -+ goto error; -+ } -+ ffsReadFile(dir, &fid, EXFAT_I(inode)->target, -+ i_size_read(inode), &ret); -+ *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; -+ } -+ -+ alias = d_find_alias(inode); -+ if (alias && !exfat_d_anon_disconn(alias)) { -+ BUG_ON(d_unhashed(alias)); -+ if (!S_ISDIR(i_mode)) -+ d_move(alias, dentry); -+ iput(inode); -+ __unlock_super(sb); -+ pr_debug("%s exited 1\n", __func__); -+ return alias; -+ } -+ dput(alias); -+out: -+ __unlock_super(sb); -+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -+ dentry = d_splice_alias(inode, dentry); -+ if (dentry) -+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -+ pr_debug("%s exited 2\n", __func__); -+ return dentry; -+ -+error: -+ __unlock_super(sb); -+ pr_debug("%s exited 3\n", __func__); -+ return ERR_PTR(err); -+} -+ -+static inline unsigned long exfat_hash(loff_t i_pos) -+{ -+ return hash_32(i_pos, EXFAT_HASH_BITS); -+} -+ -+static void exfat_attach(struct inode *inode, loff_t i_pos) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -+ -+ spin_lock(&sbi->inode_hash_lock); -+ EXFAT_I(inode)->i_pos = i_pos; -+ hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+static void exfat_detach(struct inode *inode) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ -+ spin_lock(&sbi->inode_hash_lock); -+ hlist_del_init(&EXFAT_I(inode)->i_hash_fat); -+ EXFAT_I(inode)->i_pos = 0; -+ spin_unlock(&sbi->inode_hash_lock); -+} -+ -+static int exfat_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ struct inode *inode = dentry->d_inode; -+ struct super_block *sb = dir->i_sb; -+ int err; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ -+ err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid)); -+ if (err) { -+ if (err == FFS_PERMISSIONERR) -+ err = -EPERM; -+ else -+ err = -EIO; -+ goto out; -+ } -+ INC_IVERSION(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ (void) exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_detach(inode); -+ remove_inode_hash(inode); -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_symlink(struct inode *dir, struct dentry *dentry, -+ const char *target) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct file_id_t fid; -+ loff_t i_pos; -+ int err; -+ u64 len = (u64) strlen(target); -+ u64 ret; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ err = ffsCreateFile(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); -+ if (err) { -+ if (err == FFS_INVALIDPATH) -+ err = -EINVAL; -+ else if (err == FFS_FILEEXIST) -+ err = -EEXIST; -+ else if (err == FFS_FULL) -+ err = -ENOSPC; -+ else -+ err = -EIO; -+ goto out; -+ } -+ -+ err = ffsWriteFile(dir, &fid, (char *) target, len, &ret); -+ -+ if (err) { -+ ffsRemoveFile(dir, &fid); -+ -+ if (err == FFS_FULL) -+ err = -ENOSPC; -+ else -+ err = -EIO; -+ goto out; -+ } -+ -+ INC_IVERSION(dir); -+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ (void) exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ -+ i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); -+ -+ inode = exfat_build_inode(sb, &fid, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out; -+ } -+ INC_IVERSION(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ EXFAT_I(inode)->target = kmalloc(len+1, GFP_KERNEL); -+ if (!EXFAT_I(inode)->target) { -+ err = -ENOMEM; -+ goto out; -+ } -+ memcpy(EXFAT_I(inode)->target, target, len+1); -+ -+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -+ d_instantiate(dentry, inode); -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -+{ -+ struct super_block *sb = dir->i_sb; -+ struct inode *inode; -+ struct file_id_t fid; -+ loff_t i_pos; -+ int err; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ err = ffsCreateDir(dir, (u8 *) dentry->d_name.name, &fid); -+ if (err) { -+ if (err == FFS_INVALIDPATH) -+ err = -EINVAL; -+ else if (err == FFS_FILEEXIST) -+ err = -EEXIST; -+ else if (err == FFS_FULL) -+ err = -ENOSPC; -+ else if (err == FFS_NAMETOOLONG) -+ err = -ENAMETOOLONG; -+ else -+ err = -EIO; -+ goto out; -+ } -+ INC_IVERSION(dir); -+ dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ (void) exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ inc_nlink(dir); -+ -+ i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); -+ -+ inode = exfat_build_inode(sb, &fid, i_pos); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out; -+ } -+ INC_IVERSION(inode); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); -+ /* timestamp is already written, so mark_inode_dirty() is unneeded. */ -+ -+ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); -+ d_instantiate(dentry, inode); -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ struct inode *inode = dentry->d_inode; -+ struct super_block *sb = dir->i_sb; -+ int err; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ -+ err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid)); -+ if (err) { -+ if (err == FFS_INVALIDPATH) -+ err = -EINVAL; -+ else if (err == FFS_FILEEXIST) -+ err = -ENOTEMPTY; -+ else if (err == FFS_NOTFOUND) -+ err = -ENOENT; -+ else if (err == FFS_DIRBUSY) -+ err = -EBUSY; -+ else -+ err = -EIO; -+ goto out; -+ } -+ INC_IVERSION(dir); -+ dir->i_mtime = dir->i_atime = current_time(dir); -+ if (IS_DIRSYNC(dir)) -+ (void) exfat_sync_inode(dir); -+ else -+ mark_inode_dirty(dir); -+ drop_nlink(dir); -+ -+ clear_nlink(inode); -+ inode->i_mtime = inode->i_atime = current_time(inode); -+ exfat_detach(inode); -+ remove_inode_hash(inode); -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, -+ struct inode *new_dir, struct dentry *new_dentry, -+ unsigned int flags) -+{ -+ struct inode *old_inode, *new_inode; -+ struct super_block *sb = old_dir->i_sb; -+ loff_t i_pos; -+ int err; -+ -+ if (flags) -+ return -EINVAL; -+ -+ __lock_super(sb); -+ -+ pr_debug("%s entered\n", __func__); -+ -+ old_inode = old_dentry->d_inode; -+ new_inode = new_dentry->d_inode; -+ -+ EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); -+ -+ err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, -+ new_dentry); -+ if (err) { -+ if (err == FFS_PERMISSIONERR) -+ err = -EPERM; -+ else if (err == FFS_INVALIDPATH) -+ err = -EINVAL; -+ else if (err == FFS_FILEEXIST) -+ err = -EEXIST; -+ else if (err == FFS_NOTFOUND) -+ err = -ENOENT; -+ else if (err == FFS_FULL) -+ err = -ENOSPC; -+ else -+ err = -EIO; -+ goto out; -+ } -+ INC_IVERSION(new_dir); -+ new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = -+ current_time(new_dir); -+ if (IS_DIRSYNC(new_dir)) -+ (void) exfat_sync_inode(new_dir); -+ else -+ mark_inode_dirty(new_dir); -+ -+ i_pos = ((loff_t) EXFAT_I(old_inode)->fid.dir.dir << 32) | -+ (EXFAT_I(old_inode)->fid.entry & 0xffffffff); -+ -+ exfat_detach(old_inode); -+ exfat_attach(old_inode, i_pos); -+ if (IS_DIRSYNC(new_dir)) -+ (void) exfat_sync_inode(old_inode); -+ else -+ mark_inode_dirty(old_inode); -+ -+ if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { -+ drop_nlink(old_dir); -+ if (!new_inode) -+ inc_nlink(new_dir); -+ } -+ INC_IVERSION(old_dir); -+ old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); -+ if (IS_DIRSYNC(old_dir)) -+ (void) exfat_sync_inode(old_dir); -+ else -+ mark_inode_dirty(old_dir); -+ -+ if (new_inode) { -+ exfat_detach(new_inode); -+ drop_nlink(new_inode); -+ if (S_ISDIR(new_inode->i_mode)) -+ drop_nlink(new_inode); -+ new_inode->i_ctime = current_time(new_inode); -+ } -+ -+out: -+ __unlock_super(sb); -+ pr_debug("%s exited\n", __func__); -+ return err; -+} -+ -+static int exfat_cont_expand(struct inode *inode, loff_t size) -+{ -+ struct address_space *mapping = inode->i_mapping; -+ loff_t start = i_size_read(inode), count = size - i_size_read(inode); -+ int err, err2; -+ -+ err = generic_cont_expand_simple(inode, size); -+ if (err != 0) -+ return err; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ mark_inode_dirty(inode); -+ -+ if (IS_SYNC(inode)) { -+ err = filemap_fdatawrite_range(mapping, start, -+ start + count - 1); -+ err2 = sync_mapping_buffers(mapping); -+ err = (err) ? (err) : (err2); -+ err2 = write_inode_now(inode, 1); -+ err = (err) ? (err) : (err2); -+ if (!err) -+ err = filemap_fdatawait_range(mapping, start, -+ start + count - 1); -+ } -+ return err; -+} -+ -+static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) -+{ -+ mode_t allow_utime = sbi->options.allow_utime; -+ -+ if (!uid_eq(current_fsuid(), inode->i_uid)) { -+ if (in_group_p(inode->i_gid)) -+ allow_utime >>= 3; -+ if (allow_utime & MAY_WRITE) -+ return 1; -+ } -+ -+ /* use a default check */ -+ return 0; -+} -+ -+static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, -+ struct inode *inode, umode_t *mode_ptr) -+{ -+ mode_t i_mode, mask, perm; -+ -+ i_mode = inode->i_mode; -+ -+ if (S_ISREG(i_mode) || S_ISLNK(i_mode)) -+ mask = sbi->options.fs_fmask; -+ else -+ mask = sbi->options.fs_dmask; -+ -+ perm = *mode_ptr & ~(S_IFMT | mask); -+ -+ /* Of the r and x bits, all (subject to umask) must be present.*/ -+ if ((perm & 0555) != (i_mode & 0555)) -+ return -EPERM; -+ -+ if (exfat_mode_can_hold_ro(inode)) { -+ /* -+ * Of the w bits, either all (subject to umask) or none must be -+ * present. -+ */ -+ if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask))) -+ return -EPERM; -+ } else { -+ /* -+ * If exfat_mode_can_hold_ro(inode) is false, can't change w -+ * bits. -+ */ -+ if ((perm & 0222) != (0222 & ~mask)) -+ return -EPERM; -+ } -+ -+ *mode_ptr &= S_IFMT | perm; -+ -+ return 0; -+} -+ -+static void exfat_truncate(struct inode *inode, loff_t old_size) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ int err; -+ -+ __lock_super(sb); -+ -+ /* -+ * This protects against truncating a file bigger than it was then -+ * trying to write into the hole. -+ */ -+ if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) -+ EXFAT_I(inode)->mmu_private = i_size_read(inode); -+ -+ if (EXFAT_I(inode)->fid.start_clu == 0) -+ goto out; -+ -+ err = ffsTruncateFile(inode, old_size, i_size_read(inode)); -+ if (err) -+ goto out; -+ -+ inode->i_ctime = inode->i_mtime = current_time(inode); -+ if (IS_DIRSYNC(inode)) -+ (void) exfat_sync_inode(inode); -+ else -+ mark_inode_dirty(inode); -+ -+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) & -+ ~((loff_t)p_fs->cluster_size - 1)) >> 9; -+out: -+ __unlock_super(sb); -+} -+ -+static int exfat_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ -+ struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); -+ struct inode *inode = dentry->d_inode; -+ unsigned int ia_valid; -+ int error; -+ loff_t old_size; -+ -+ pr_debug("%s entered\n", __func__); -+ -+ if ((attr->ia_valid & ATTR_SIZE) -+ && (attr->ia_size > i_size_read(inode))) { -+ error = exfat_cont_expand(inode, attr->ia_size); -+ if (error || attr->ia_valid == ATTR_SIZE) -+ return error; -+ attr->ia_valid &= ~ATTR_SIZE; -+ } -+ -+ ia_valid = attr->ia_valid; -+ -+ if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) -+ && exfat_allow_set_time(sbi, inode)) { -+ attr->ia_valid &= ~(ATTR_MTIME_SET | -+ ATTR_ATIME_SET | -+ ATTR_TIMES_SET); -+ } -+ -+ error = setattr_prepare(dentry, attr); -+ attr->ia_valid = ia_valid; -+ if (error) -+ return error; -+ -+ if (((attr->ia_valid & ATTR_UID) && -+ (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || -+ ((attr->ia_valid & ATTR_GID) && -+ (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || -+ ((attr->ia_valid & ATTR_MODE) && -+ (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) { -+ return -EPERM; -+ } -+ -+ /* -+ * We don't return -EPERM here. Yes, strange, but this is too -+ * old behavior. -+ */ -+ if (attr->ia_valid & ATTR_MODE) { -+ if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) -+ attr->ia_valid &= ~ATTR_MODE; -+ } -+ -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ -+ if (attr->ia_valid & ATTR_SIZE) { -+ old_size = i_size_read(inode); -+ down_write(&EXFAT_I(inode)->truncate_lock); -+ truncate_setsize(inode, attr->ia_size); -+ exfat_truncate(inode, old_size); -+ up_write(&EXFAT_I(inode)->truncate_lock); -+ } -+ setattr_copy(inode, attr); -+ mark_inode_dirty(inode); -+ -+ pr_debug("%s exited\n", __func__); -+ return error; -+} -+ -+static int exfat_getattr(const struct path *path, struct kstat *stat, -+ u32 request_mask, unsigned int flags) -+{ -+ struct inode *inode = path->dentry->d_inode; -+ -+ pr_debug("%s entered\n", __func__); -+ -+ generic_fillattr(inode, stat); -+ stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; -+ -+ pr_debug("%s exited\n", __func__); -+ return 0; -+} -+ -+static const struct inode_operations exfat_dir_inode_operations = { -+ .create = exfat_create, -+ .lookup = exfat_lookup, -+ .unlink = exfat_unlink, -+ .symlink = exfat_symlink, -+ .mkdir = exfat_mkdir, -+ .rmdir = exfat_rmdir, -+ .rename = exfat_rename, -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; -+ -+/*======================================================================*/ -+/* File Operations */ -+/*======================================================================*/ -+static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, -+ struct delayed_call *done) -+{ -+ struct exfat_inode_info *ei = EXFAT_I(inode); -+ -+ if (ei->target != NULL) { -+ char *cookie = ei->target; -+ -+ if (cookie != NULL) -+ return (char *)(ei->target); -+ } -+ return NULL; -+} -+ -+static const struct inode_operations exfat_symlink_inode_operations = { -+ .get_link = exfat_get_link, -+}; -+ -+static int exfat_file_release(struct inode *inode, struct file *filp) -+{ -+ struct super_block *sb = inode->i_sb; -+ -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ ffsSyncVol(sb, false); -+ return 0; -+} -+ -+static const struct file_operations exfat_file_operations = { -+ .llseek = generic_file_llseek, -+ .read_iter = generic_file_read_iter, -+ .write_iter = generic_file_write_iter, -+ .mmap = generic_file_mmap, -+ .release = exfat_file_release, -+ .unlocked_ioctl = exfat_generic_ioctl, -+ .fsync = generic_file_fsync, -+ .splice_read = generic_file_splice_read, -+}; -+ -+static const struct inode_operations exfat_file_inode_operations = { -+ .setattr = exfat_setattr, -+ .getattr = exfat_getattr, -+}; -+ -+/*======================================================================*/ -+/* Address Space Operations */ -+/*======================================================================*/ -+ -+static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, -+ unsigned long *mapped_blocks, int *create) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ struct bd_info_t *p_bd = &(sbi->bd_info); -+ const unsigned long blocksize = sb->s_blocksize; -+ const unsigned char blocksize_bits = sb->s_blocksize_bits; -+ sector_t last_block; -+ int err, clu_offset, sec_offset; -+ unsigned int cluster; -+ -+ *phys = 0; -+ *mapped_blocks = 0; -+ -+ if ((p_fs->vol_type == FAT12) || (p_fs->vol_type == FAT16)) { -+ if (inode->i_ino == EXFAT_ROOT_INO) { -+ if (sector < -+ (p_fs->dentries_in_root >> -+ (p_bd->sector_size_bits-DENTRY_SIZE_BITS))) { -+ *phys = sector + p_fs->root_start_sector; -+ *mapped_blocks = 1; -+ } -+ return 0; -+ } -+ } -+ -+ last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; -+ if (sector >= last_block) { -+ if (*create == 0) -+ return 0; -+ } else { -+ *create = 0; -+ } -+ -+ /* cluster offset */ -+ clu_offset = sector >> p_fs->sectors_per_clu_bits; -+ -+ /* sector offset in cluster */ -+ sec_offset = sector & (p_fs->sectors_per_clu - 1); -+ -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ -+ err = ffsMapCluster(inode, clu_offset, &cluster); -+ -+ if (err) { -+ if (err == FFS_FULL) -+ return -ENOSPC; -+ else -+ return -EIO; -+ } else if (cluster != CLUSTER_32(~0)) { -+ *phys = START_SECTOR(cluster) + sec_offset; -+ *mapped_blocks = p_fs->sectors_per_clu - sec_offset; -+ } -+ -+ return 0; -+} -+ -+static int exfat_get_block(struct inode *inode, sector_t iblock, -+ struct buffer_head *bh_result, int create) -+{ -+ struct super_block *sb = inode->i_sb; -+ unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; -+ int err; -+ unsigned long mapped_blocks; -+ sector_t phys; -+ -+ __lock_super(sb); -+ -+ err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); -+ if (err) { -+ __unlock_super(sb); -+ return err; -+ } -+ -+ if (phys) { -+ max_blocks = min(mapped_blocks, max_blocks); -+ if (create) { -+ EXFAT_I(inode)->mmu_private += max_blocks << -+ sb->s_blocksize_bits; -+ set_buffer_new(bh_result); -+ } -+ map_bh(bh_result, sb, phys); -+ } -+ -+ bh_result->b_size = max_blocks << sb->s_blocksize_bits; -+ __unlock_super(sb); -+ -+ return 0; -+} -+ -+static int exfat_readpage(struct file *file, struct page *page) -+{ -+ return mpage_readpage(page, exfat_get_block); -+} -+ -+static int exfat_readpages(struct file *file, struct address_space *mapping, -+ struct list_head *pages, unsigned int nr_pages) -+{ -+ return mpage_readpages(mapping, pages, nr_pages, exfat_get_block); -+} -+ -+static int exfat_writepage(struct page *page, struct writeback_control *wbc) -+{ -+ return block_write_full_page(page, exfat_get_block, wbc); -+} -+ -+static int exfat_writepages(struct address_space *mapping, -+ struct writeback_control *wbc) -+{ -+ return mpage_writepages(mapping, wbc, exfat_get_block); -+} -+ -+static void exfat_write_failed(struct address_space *mapping, loff_t to) -+{ -+ struct inode *inode = mapping->host; -+ -+ if (to > i_size_read(inode)) { -+ truncate_pagecache(inode, i_size_read(inode)); -+ EXFAT_I(inode)->fid.size = i_size_read(inode); -+ exfat_truncate(inode, i_size_read(inode)); -+ } -+} -+ -+static int exfat_write_begin(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int flags, -+ struct page **pagep, void **fsdata) -+{ -+ int ret; -+ -+ *pagep = NULL; -+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, -+ exfat_get_block, -+ &EXFAT_I(mapping->host)->mmu_private); -+ -+ if (ret < 0) -+ exfat_write_failed(mapping, pos+len); -+ return ret; -+} -+ -+static int exfat_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned int len, unsigned int copied, -+ struct page *pagep, void *fsdata) -+{ -+ struct inode *inode = mapping->host; -+ struct file_id_t *fid = &(EXFAT_I(inode)->fid); -+ int err; -+ -+ err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); -+ -+ if (err < len) -+ exfat_write_failed(mapping, pos+len); -+ -+ if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { -+ inode->i_mtime = inode->i_ctime = current_time(inode); -+ fid->attr |= ATTR_ARCHIVE; -+ mark_inode_dirty(inode); -+ } -+ return err; -+} -+ -+static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct inode *inode = iocb->ki_filp->f_mapping->host; -+ struct address_space *mapping = iocb->ki_filp->f_mapping; -+ ssize_t ret; -+ int rw; -+ -+ rw = iov_iter_rw(iter); -+ -+ if (rw == WRITE) { -+ if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) -+ return 0; -+ } -+ ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); -+ -+ if ((ret < 0) && (rw & WRITE)) -+ exfat_write_failed(mapping, iov_iter_count(iter)); -+ return ret; -+} -+ -+static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) -+{ -+ sector_t blocknr; -+ -+ /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ -+ down_read(&EXFAT_I(mapping->host)->truncate_lock); -+ blocknr = generic_block_bmap(mapping, block, exfat_get_block); -+ up_read(&EXFAT_I(mapping->host)->truncate_lock); -+ -+ return blocknr; -+} -+ -+static const struct address_space_operations exfat_aops = { -+ .readpage = exfat_readpage, -+ .readpages = exfat_readpages, -+ .writepage = exfat_writepage, -+ .writepages = exfat_writepages, -+ .write_begin = exfat_write_begin, -+ .write_end = exfat_write_end, -+ .direct_IO = exfat_direct_IO, -+ .bmap = _exfat_bmap -+}; -+ -+/*======================================================================*/ -+/* Super Operations */ -+/*======================================================================*/ -+ -+static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct exfat_inode_info *info; -+ struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); -+ struct inode *inode = NULL; -+ -+ spin_lock(&sbi->inode_hash_lock); -+ hlist_for_each_entry(info, head, i_hash_fat) { -+ BUG_ON(info->vfs_inode.i_sb != sb); -+ -+ if (i_pos != info->i_pos) -+ continue; -+ inode = igrab(&info->vfs_inode); -+ if (inode) -+ break; -+ } -+ spin_unlock(&sbi->inode_hash_lock); -+ return inode; -+} -+ -+/* doesn't deal with root inode */ -+static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ struct dir_entry_t info; -+ -+ memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t)); -+ -+ ffsReadStat(inode, &info); -+ -+ EXFAT_I(inode)->i_pos = 0; -+ EXFAT_I(inode)->target = NULL; -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ INC_IVERSION(inode); -+ inode->i_generation = get_seconds(); -+ -+ if (info.Attr & ATTR_SUBDIR) { /* directory */ -+ inode->i_generation &= ~1; -+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ -+ i_size_write(inode, info.Size); -+ EXFAT_I(inode)->mmu_private = i_size_read(inode); -+ set_nlink(inode, info.NumSubdirs); -+ } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ -+ inode->i_generation |= 1; -+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -+ inode->i_op = &exfat_symlink_inode_operations; -+ -+ i_size_write(inode, info.Size); -+ EXFAT_I(inode)->mmu_private = i_size_read(inode); -+ } else { /* regular file */ -+ inode->i_generation |= 1; -+ inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); -+ inode->i_op = &exfat_file_inode_operations; -+ inode->i_fop = &exfat_file_operations; -+ inode->i_mapping->a_ops = &exfat_aops; -+ inode->i_mapping->nrpages = 0; -+ -+ i_size_write(inode, info.Size); -+ EXFAT_I(inode)->mmu_private = i_size_read(inode); -+ } -+ exfat_save_attr(inode, info.Attr); -+ -+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -+ & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -+ -+ exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); -+ exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); -+ exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp); -+ -+ return 0; -+} -+ -+static struct inode *exfat_build_inode(struct super_block *sb, -+ struct file_id_t *fid, loff_t i_pos) -+{ -+ struct inode *inode; -+ int err; -+ -+ inode = exfat_iget(sb, i_pos); -+ if (inode) -+ goto out; -+ inode = new_inode(sb); -+ if (!inode) { -+ inode = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ inode->i_ino = iunique(sb, EXFAT_ROOT_INO); -+ SET_IVERSION(inode, 1); -+ err = exfat_fill_inode(inode, fid); -+ if (err) { -+ iput(inode); -+ inode = ERR_PTR(err); -+ goto out; -+ } -+ exfat_attach(inode, i_pos); -+ insert_inode_hash(inode); -+out: -+ return inode; -+} -+ -+static int exfat_sync_inode(struct inode *inode) -+{ -+ return exfat_write_inode(inode, NULL); -+} -+ -+static struct inode *exfat_alloc_inode(struct super_block *sb) -+{ -+ struct exfat_inode_info *ei; -+ -+ ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); -+ if (!ei) -+ return NULL; -+ -+ init_rwsem(&ei->truncate_lock); -+ -+ return &ei->vfs_inode; -+} -+ -+static void exfat_destroy_inode(struct inode *inode) -+{ -+ if (EXFAT_I(inode)->target) -+ kfree(EXFAT_I(inode)->target); -+ EXFAT_I(inode)->target = NULL; -+ -+ kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); -+} -+ -+static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct dir_entry_t info; -+ -+ if (inode->i_ino == EXFAT_ROOT_INO) -+ return 0; -+ -+ info.Attr = exfat_make_attr(inode); -+ info.Size = i_size_read(inode); -+ -+ exfat_time_unix2fat(sbi, &inode->i_mtime, &info.ModifyTimestamp); -+ exfat_time_unix2fat(sbi, &inode->i_ctime, &info.CreateTimestamp); -+ exfat_time_unix2fat(sbi, &inode->i_atime, &info.AccessTimestamp); -+ -+ ffsWriteStat(inode, &info); -+ -+ return 0; -+} -+ -+static void exfat_evict_inode(struct inode *inode) -+{ -+ truncate_inode_pages(&inode->i_data, 0); -+ -+ if (!inode->i_nlink) -+ i_size_write(inode, 0); -+ invalidate_inode_buffers(inode); -+ clear_inode(inode); -+ exfat_detach(inode); -+ -+ remove_inode_hash(inode); -+} -+ -+static void exfat_free_super(struct exfat_sb_info *sbi) -+{ -+ if (sbi->nls_disk) -+ unload_nls(sbi->nls_disk); -+ if (sbi->nls_io) -+ unload_nls(sbi->nls_io); -+ if (sbi->options.iocharset != exfat_default_iocharset) -+ kfree(sbi->options.iocharset); -+ /* mutex_init is in exfat_fill_super function. only for 3.7+ */ -+ mutex_destroy(&sbi->s_lock); -+ kfree(sbi); -+} -+ -+static void exfat_put_super(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ -+ if (__is_sb_dirty(sb)) -+ exfat_write_super(sb); -+ -+ ffsUmountVol(sb); -+ -+ sb->s_fs_info = NULL; -+ exfat_free_super(sbi); -+} -+ -+static void exfat_write_super(struct super_block *sb) -+{ -+ __lock_super(sb); -+ -+ __set_sb_clean(sb); -+ -+ if (!sb_rdonly(sb)) -+ ffsSyncVol(sb, true); -+ -+ __unlock_super(sb); -+} -+ -+static int exfat_sync_fs(struct super_block *sb, int wait) -+{ -+ int err = 0; -+ -+ if (__is_sb_dirty(sb)) { -+ __lock_super(sb); -+ __set_sb_clean(sb); -+ err = ffsSyncVol(sb, true); -+ __unlock_super(sb); -+ } -+ -+ return err; -+} -+ -+static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct super_block *sb = dentry->d_sb; -+ u64 id = huge_encode_dev(sb->s_bdev->bd_dev); -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ struct vol_info_t info; -+ -+ if (p_fs->used_clusters == (u32) ~0) { -+ if (ffsGetVolInfo(sb, &info) == FFS_MEDIAERR) -+ return -EIO; -+ -+ } else { -+ info.FatType = p_fs->vol_type; -+ info.ClusterSize = p_fs->cluster_size; -+ info.NumClusters = p_fs->num_clusters - 2; -+ info.UsedClusters = p_fs->used_clusters; -+ info.FreeClusters = info.NumClusters - info.UsedClusters; -+ -+ if (p_fs->dev_ejected) -+ pr_info("[EXFAT] statfs on device that is ejected\n"); -+ } -+ -+ buf->f_type = sb->s_magic; -+ buf->f_bsize = info.ClusterSize; -+ buf->f_blocks = info.NumClusters; -+ buf->f_bfree = info.FreeClusters; -+ buf->f_bavail = info.FreeClusters; -+ buf->f_fsid.val[0] = (u32)id; -+ buf->f_fsid.val[1] = (u32)(id >> 32); -+ buf->f_namelen = 260; -+ -+ return 0; -+} -+ -+static int exfat_remount(struct super_block *sb, int *flags, char *data) -+{ -+ *flags |= SB_NODIRATIME; -+ return 0; -+} -+ -+static int exfat_show_options(struct seq_file *m, struct dentry *root) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); -+ struct exfat_mount_options *opts = &sbi->options; -+ -+ if (__kuid_val(opts->fs_uid)) -+ seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); -+ if (__kgid_val(opts->fs_gid)) -+ seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); -+ seq_printf(m, ",fmask=%04o", opts->fs_fmask); -+ seq_printf(m, ",dmask=%04o", opts->fs_dmask); -+ if (opts->allow_utime) -+ seq_printf(m, ",allow_utime=%04o", opts->allow_utime); -+ if (sbi->nls_disk) -+ seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); -+ if (sbi->nls_io) -+ seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); -+ seq_printf(m, ",namecase=%u", opts->casesensitive); -+ if (opts->errors == EXFAT_ERRORS_CONT) -+ seq_puts(m, ",errors=continue"); -+ else if (opts->errors == EXFAT_ERRORS_PANIC) -+ seq_puts(m, ",errors=panic"); -+ else -+ seq_puts(m, ",errors=remount-ro"); -+#ifdef CONFIG_EXFAT_DISCARD -+ if (opts->discard) -+ seq_puts(m, ",discard"); -+#endif -+ return 0; -+} -+ -+static const struct super_operations exfat_sops = { -+ .alloc_inode = exfat_alloc_inode, -+ .destroy_inode = exfat_destroy_inode, -+ .write_inode = exfat_write_inode, -+ .evict_inode = exfat_evict_inode, -+ .put_super = exfat_put_super, -+ .sync_fs = exfat_sync_fs, -+ .statfs = exfat_statfs, -+ .remount_fs = exfat_remount, -+ .show_options = exfat_show_options, -+}; -+ -+/*======================================================================*/ -+/* Export Operations */ -+/*======================================================================*/ -+ -+static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino, -+ u32 generation) -+{ -+ struct inode *inode = NULL; -+ -+ if (ino < EXFAT_ROOT_INO) -+ return inode; -+ inode = ilookup(sb, ino); -+ -+ if (inode && generation && (inode->i_generation != generation)) { -+ iput(inode); -+ inode = NULL; -+ } -+ -+ return inode; -+} -+ -+static struct dentry *exfat_fh_to_dentry(struct super_block *sb, -+ struct fid *fid, int fh_len, -+ int fh_type) -+{ -+ return generic_fh_to_dentry(sb, fid, fh_len, fh_type, -+ exfat_nfs_get_inode); -+} -+ -+static struct dentry *exfat_fh_to_parent(struct super_block *sb, -+ struct fid *fid, int fh_len, -+ int fh_type) -+{ -+ return generic_fh_to_parent(sb, fid, fh_len, fh_type, -+ exfat_nfs_get_inode); -+} -+ -+static const struct export_operations exfat_export_ops = { -+ .fh_to_dentry = exfat_fh_to_dentry, -+ .fh_to_parent = exfat_fh_to_parent, -+}; -+ -+/*======================================================================*/ -+/* Super Block Read Operations */ -+/*======================================================================*/ -+ -+enum { -+ Opt_uid, -+ Opt_gid, -+ Opt_umask, -+ Opt_dmask, -+ Opt_fmask, -+ Opt_allow_utime, -+ Opt_codepage, -+ Opt_charset, -+ Opt_namecase, -+ Opt_debug, -+ Opt_err_cont, -+ Opt_err_panic, -+ Opt_err_ro, -+ Opt_utf8_hack, -+ Opt_err, -+#ifdef CONFIG_EXFAT_DISCARD -+ Opt_discard, -+#endif /* EXFAT_CONFIG_DISCARD */ -+}; -+ -+static const match_table_t exfat_tokens = { -+ {Opt_uid, "uid=%u"}, -+ {Opt_gid, "gid=%u"}, -+ {Opt_umask, "umask=%o"}, -+ {Opt_dmask, "dmask=%o"}, -+ {Opt_fmask, "fmask=%o"}, -+ {Opt_allow_utime, "allow_utime=%o"}, -+ {Opt_codepage, "codepage=%u"}, -+ {Opt_charset, "iocharset=%s"}, -+ {Opt_namecase, "namecase=%u"}, -+ {Opt_debug, "debug"}, -+ {Opt_err_cont, "errors=continue"}, -+ {Opt_err_panic, "errors=panic"}, -+ {Opt_err_ro, "errors=remount-ro"}, -+ {Opt_utf8_hack, "utf8"}, -+#ifdef CONFIG_EXFAT_DISCARD -+ {Opt_discard, "discard"}, -+#endif /* CONFIG_EXFAT_DISCARD */ -+ {Opt_err, NULL} -+}; -+ -+static int parse_options(char *options, int silent, int *debug, -+ struct exfat_mount_options *opts) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ int option; -+ char *iocharset; -+ -+ opts->fs_uid = current_uid(); -+ opts->fs_gid = current_gid(); -+ opts->fs_fmask = opts->fs_dmask = current->fs->umask; -+ opts->allow_utime = (unsigned short) -1; -+ opts->codepage = exfat_default_codepage; -+ opts->iocharset = exfat_default_iocharset; -+ opts->casesensitive = 0; -+ opts->errors = EXFAT_ERRORS_RO; -+#ifdef CONFIG_EXFAT_DISCARD -+ opts->discard = 0; -+#endif -+ *debug = 0; -+ -+ if (!options) -+ goto out; -+ -+ while ((p = strsep(&options, ",")) != NULL) { -+ int token; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, exfat_tokens, args); -+ switch (token) { -+ case Opt_uid: -+ if (match_int(&args[0], &option)) -+ return 0; -+ opts->fs_uid = KUIDT_INIT(option); -+ break; -+ case Opt_gid: -+ if (match_int(&args[0], &option)) -+ return 0; -+ opts->fs_gid = KGIDT_INIT(option); -+ break; -+ case Opt_umask: -+ case Opt_dmask: -+ case Opt_fmask: -+ if (match_octal(&args[0], &option)) -+ return 0; -+ if (token != Opt_dmask) -+ opts->fs_fmask = option; -+ if (token != Opt_fmask) -+ opts->fs_dmask = option; -+ break; -+ case Opt_allow_utime: -+ if (match_octal(&args[0], &option)) -+ return 0; -+ opts->allow_utime = option & 0022; -+ break; -+ case Opt_codepage: -+ if (match_int(&args[0], &option)) -+ return 0; -+ opts->codepage = option; -+ break; -+ case Opt_charset: -+ if (opts->iocharset != exfat_default_iocharset) -+ kfree(opts->iocharset); -+ iocharset = match_strdup(&args[0]); -+ if (!iocharset) -+ return -ENOMEM; -+ opts->iocharset = iocharset; -+ break; -+ case Opt_namecase: -+ if (match_int(&args[0], &option)) -+ return 0; -+ opts->casesensitive = option; -+ break; -+ case Opt_err_cont: -+ opts->errors = EXFAT_ERRORS_CONT; -+ break; -+ case Opt_err_panic: -+ opts->errors = EXFAT_ERRORS_PANIC; -+ break; -+ case Opt_err_ro: -+ opts->errors = EXFAT_ERRORS_RO; -+ break; -+ case Opt_debug: -+ *debug = 1; -+ break; -+#ifdef CONFIG_EXFAT_DISCARD -+ case Opt_discard: -+ opts->discard = 1; -+ break; -+#endif /* CONFIG_EXFAT_DISCARD */ -+ case Opt_utf8_hack: -+ break; -+ default: -+ if (!silent) -+ pr_err("[EXFAT] Unrecognized mount option %s or missing value\n", -+ p); -+ return -EINVAL; -+ } -+ } -+ -+out: -+ if (opts->allow_utime == (unsigned short) -1) -+ opts->allow_utime = ~opts->fs_dmask & 0022; -+ -+ return 0; -+} -+ -+static void exfat_hash_init(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ int i; -+ -+ spin_lock_init(&sbi->inode_hash_lock); -+ for (i = 0; i < EXFAT_HASH_SIZE; i++) -+ INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); -+} -+ -+static int exfat_read_root(struct inode *inode) -+{ -+ struct super_block *sb = inode->i_sb; -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct fs_info_t *p_fs = &(sbi->fs_info); -+ struct dir_entry_t info; -+ -+ EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; -+ EXFAT_I(inode)->fid.dir.flags = 0x01; -+ EXFAT_I(inode)->fid.entry = -1; -+ EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; -+ EXFAT_I(inode)->fid.flags = 0x01; -+ EXFAT_I(inode)->fid.type = TYPE_DIR; -+ EXFAT_I(inode)->fid.rwoffset = 0; -+ EXFAT_I(inode)->fid.hint_last_off = -1; -+ -+ EXFAT_I(inode)->target = NULL; -+ -+ ffsReadStat(inode, &info); -+ -+ inode->i_uid = sbi->options.fs_uid; -+ inode->i_gid = sbi->options.fs_gid; -+ INC_IVERSION(inode); -+ inode->i_generation = 0; -+ inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); -+ inode->i_op = &exfat_dir_inode_operations; -+ inode->i_fop = &exfat_dir_operations; -+ -+ i_size_write(inode, info.Size); -+ inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) -+ & ~((loff_t)p_fs->cluster_size - 1)) >> 9; -+ EXFAT_I(inode)->i_pos = ((loff_t) p_fs->root_dir << 32) | 0xffffffff; -+ EXFAT_I(inode)->mmu_private = i_size_read(inode); -+ -+ exfat_save_attr(inode, ATTR_SUBDIR); -+ inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); -+ set_nlink(inode, info.NumSubdirs + 2); -+ -+ return 0; -+} -+ -+static void setup_dops(struct super_block *sb) -+{ -+ if (EXFAT_SB(sb)->options.casesensitive == 0) -+ sb->s_d_op = &exfat_ci_dentry_ops; -+ else -+ sb->s_d_op = &exfat_dentry_ops; -+} -+ -+static int exfat_fill_super(struct super_block *sb, void *data, int silent) -+{ -+ struct inode *root_inode = NULL; -+ struct exfat_sb_info *sbi; -+ int debug, ret; -+ long error; -+ char buf[50]; -+ -+ /* -+ * GFP_KERNEL is ok here, because while we do hold the -+ * supeblock lock, memory pressure can't call back into -+ * the filesystem, since we're only just about to mount -+ * it and have no inodes etc active! -+ */ -+ sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); -+ if (!sbi) -+ return -ENOMEM; -+ mutex_init(&sbi->s_lock); -+ sb->s_fs_info = sbi; -+ sb->s_flags |= SB_NODIRATIME; -+ sb->s_magic = EXFAT_SUPER_MAGIC; -+ sb->s_op = &exfat_sops; -+ sb->s_export_op = &exfat_export_ops; -+ -+ error = parse_options(data, silent, &debug, &sbi->options); -+ if (error) -+ goto out_fail; -+ -+ setup_dops(sb); -+ -+ error = -EIO; -+ sb_min_blocksize(sb, 512); -+ sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ -+ -+ ret = ffsMountVol(sb); -+ if (ret) { -+ if (!silent) -+ pr_err("[EXFAT] ffsMountVol failed\n"); -+ -+ goto out_fail; -+ } -+ -+ /* set up enough so that it can read an inode */ -+ exfat_hash_init(sb); -+ -+ /* -+ * The low byte of FAT's first entry must have same value with -+ * media-field. But in real world, too many devices is -+ * writing wrong value. So, removed that validity check. -+ * -+ * if (FAT_FIRST_ENT(sb, media) != first) -+ */ -+ -+ /* codepage is not meaningful in exfat */ -+ if (sbi->fs_info.vol_type != EXFAT) { -+ error = -EINVAL; -+ sprintf(buf, "cp%d", sbi->options.codepage); -+ sbi->nls_disk = load_nls(buf); -+ if (!sbi->nls_disk) { -+ pr_err("[EXFAT] Codepage %s not found\n", buf); -+ goto out_fail2; -+ } -+ } -+ -+ sbi->nls_io = load_nls(sbi->options.iocharset); -+ -+ error = -ENOMEM; -+ root_inode = new_inode(sb); -+ if (!root_inode) -+ goto out_fail2; -+ root_inode->i_ino = EXFAT_ROOT_INO; -+ SET_IVERSION(root_inode, 1); -+ -+ error = exfat_read_root(root_inode); -+ if (error < 0) -+ goto out_fail2; -+ error = -ENOMEM; -+ exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); -+ insert_inode_hash(root_inode); -+ sb->s_root = d_make_root(root_inode); -+ if (!sb->s_root) { -+ pr_err("[EXFAT] Getting the root inode failed\n"); -+ goto out_fail2; -+ } -+ -+ return 0; -+ -+out_fail2: -+ ffsUmountVol(sb); -+out_fail: -+ if (root_inode) -+ iput(root_inode); -+ sb->s_fs_info = NULL; -+ exfat_free_super(sbi); -+ return error; -+} -+ -+static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, -+ int flags, const char *dev_name, -+ void *data) -+{ -+ return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); -+} -+ -+static void init_once(void *foo) -+{ -+ struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; -+ -+ INIT_HLIST_NODE(&ei->i_hash_fat); -+ inode_init_once(&ei->vfs_inode); -+} -+ -+static int __init exfat_init_inodecache(void) -+{ -+ exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", -+ sizeof(struct exfat_inode_info), -+ 0, -+ (SLAB_RECLAIM_ACCOUNT | -+ SLAB_MEM_SPREAD), -+ init_once); -+ if (exfat_inode_cachep == NULL) -+ return -ENOMEM; -+ return 0; -+} -+ -+static void __exit exfat_destroy_inodecache(void) -+{ -+ /* -+ * Make sure all delayed rcu free inodes are flushed before we -+ * destroy cache. -+ */ -+ rcu_barrier(); -+ kmem_cache_destroy(exfat_inode_cachep); -+} -+ -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+static void exfat_debug_kill_sb(struct super_block *sb) -+{ -+ struct exfat_sb_info *sbi = EXFAT_SB(sb); -+ struct block_device *bdev = sb->s_bdev; -+ struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -+ -+ long flags; -+ -+ if (sbi) { -+ flags = sbi->debug_flags; -+ -+ if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { -+ /* -+ * invalidate_bdev drops all device cache include -+ * dirty. We use this to simulate device removal. -+ */ -+ down(&p_fs->v_sem); -+ FAT_release_all(sb); -+ buf_release_all(sb); -+ up(&p_fs->v_sem); -+ -+ invalidate_bdev(bdev); -+ } -+ } -+ -+ kill_block_super(sb); -+} -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ -+static struct file_system_type exfat_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "exfat", -+ .mount = exfat_fs_mount, -+#ifdef CONFIG_EXFAT_KERNEL_DEBUG -+ .kill_sb = exfat_debug_kill_sb, -+#else -+ .kill_sb = kill_block_super, -+#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ -+ .fs_flags = FS_REQUIRES_DEV, -+}; -+ -+static int __init init_exfat(void) -+{ -+ int err; -+ -+ BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE); -+ BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE); -+ -+ pr_info("exFAT: Version %s\n", EXFAT_VERSION); -+ -+ err = exfat_init_inodecache(); -+ if (err) -+ return err; -+ -+ err = register_filesystem(&exfat_fs_type); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void __exit exit_exfat(void) -+{ -+ exfat_destroy_inodecache(); -+ unregister_filesystem(&exfat_fs_type); -+} -+ -+module_init(init_exfat); -+module_exit(exit_exfat); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("exFAT Filesystem Driver"); -+MODULE_ALIAS_FS("exfat"); -diff --git a/drivers/staging/exfat/exfat_upcase.c b/drivers/staging/exfat/exfat_upcase.c -new file mode 100644 -index 000000000000..366082fb3dab ---- /dev/null -+++ b/drivers/staging/exfat/exfat_upcase.c -@@ -0,0 +1,740 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. -+ */ -+ -+#include <linux/types.h> -+#include "exfat.h" -+ -+const u8 uni_upcase[NUM_UPCASE << 1] = { -+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, -+ 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, -+ 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, -+ 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, -+ 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, -+ 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, -+ 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, -+ 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, -+ 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, -+ 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, -+ 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, -+ 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, -+ 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, -+ 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, -+ 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, -+ 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, -+ 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -+ 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -+ 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -+ 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -+ 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, -+ 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, -+ 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, -+ 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, -+ 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, -+ 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, -+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, -+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, -+ 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, -+ 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, -+ 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, -+ 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, -+ 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, -+ 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, -+ 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, -+ 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, -+ 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, -+ 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, -+ 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, -+ 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, -+ 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, -+ 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, -+ 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, -+ 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, -+ 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, -+ 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, -+ 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -+ 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -+ 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -+ 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -+ 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -+ 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, -+ 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -+ 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, -+ 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, -+ 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, -+ 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, -+ 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, -+ 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, -+ 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, -+ 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, -+ 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, -+ 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, -+ 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, -+ 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, -+ 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, -+ 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, -+ 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, -+ 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, -+ 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, -+ 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, -+ 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, -+ 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, -+ 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, -+ 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, -+ 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, -+ 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, -+ 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, -+ 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, -+ 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, -+ 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, -+ 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, -+ 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, -+ 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, -+ 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, -+ 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, -+ 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, -+ 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, -+ 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, -+ 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, -+ 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, -+ 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, -+ 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, -+ 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, -+ 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, -+ 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, -+ 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, -+ 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, -+ 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, -+ 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, -+ 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, -+ 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, -+ 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, -+ 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, -+ 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, -+ 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, -+ 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, -+ 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, -+ 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, -+ 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, -+ 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, -+ 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, -+ 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, -+ 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, -+ 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, -+ 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, -+ 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, -+ 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, -+ 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, -+ 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, -+ 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, -+ 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, -+ 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, -+ 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, -+ 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, -+ 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, -+ 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, -+ 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, -+ 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, -+ 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, -+ 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, -+ 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, -+ 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, -+ 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, -+ 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, -+ 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, -+ 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, -+ 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, -+ 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, -+ 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, -+ 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, -+ 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, -+ 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, -+ 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, -+ 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, -+ 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, -+ 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, -+ 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, -+ 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, -+ 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, -+ 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, -+ 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, -+ 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, -+ 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, -+ 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, -+ 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, -+ 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, -+ 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, -+ 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, -+ 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, -+ 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, -+ 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, -+ 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, -+ 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, -+ 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, -+ 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, -+ 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, -+ 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, -+ 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, -+ 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, -+ 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, -+ 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, -+ 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, -+ 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, -+ 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, -+ 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, -+ 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, -+ 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, -+ 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, -+ 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, -+ 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, -+ 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, -+ 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, -+ 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, -+ 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, -+ 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, -+ 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, -+ 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, -+ 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, -+ 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, -+ 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, -+ 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, -+ 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, -+ 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, -+ 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, -+ 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, -+ 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, -+ 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, -+ 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, -+ 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, -+ 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, -+ 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, -+ 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, -+ 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, -+ 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, -+ 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, -+ 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, -+ 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, -+ 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, -+ 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, -+ 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, -+ 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, -+ 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, -+ 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, -+ 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, -+ 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, -+ 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, -+ 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, -+ 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, -+ 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, -+ 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, -+ 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, -+ 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, -+ 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, -+ 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, -+ 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, -+ 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -+ 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -+ 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -+ 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -+ 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, -+ 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -+ 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -+ 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, -+ 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, -+ 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, -+ 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, -+ 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, -+ 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, -+ 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, -+ 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, -+ 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, -+ 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, -+ 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, -+ 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, -+ 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, -+ 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, -+ 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, -+ 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, -+ 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, -+ 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, -+ 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, -+ 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, -+ 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, -+ 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -+ 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -+ 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -+ 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -+ 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -+ 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -+ 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -+ 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -+ 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -+ 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -+ 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -+ 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -+ 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, -+ 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, -+ 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, -+ 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, -+ 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, -+ 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, -+ 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, -+ 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, -+ 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, -+ 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, -+ 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, -+ 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, -+ 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, -+ 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, -+ 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, -+ 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, -+ 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, -+ 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, -+ 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, -+ 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, -+ 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, -+ 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, -+ 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, -+ 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, -+ 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, -+ 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, -+ 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, -+ 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, -+ 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, -+ 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, -+ 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, -+ 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, -+ 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, -+ 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, -+ 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, -+ 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, -+ 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, -+ 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, -+ 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, -+ 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, -+ 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, -+ 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, -+ 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, -+ 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, -+ 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, -+ 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, -+ 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, -+ 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, -+ 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, -+ 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, -+ 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, -+ 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, -+ 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, -+ 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, -+ 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, -+ 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, -+ 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, -+ 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, -+ 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, -+ 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, -+ 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, -+ 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, -+ 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, -+ 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, -+ 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -+ 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -+ 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -+ 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -+ 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -+ 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -+ 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -+ 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -+ 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -+ 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, -+ 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, -+ 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, -+ 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, -+ 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, -+ 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, -+ 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, -+ 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, -+ 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, -+ 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, -+ 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, -+ 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, -+ 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, -+ 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, -+ 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, -+ 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, -+ 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, -+ 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, -+ 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, -+ 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, -+ 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, -+ 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, -+ 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, -+ 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, -+ 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, -+ 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, -+ 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, -+ 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, -+ 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, -+ 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, -+ 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, -+ 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, -+ 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, -+ 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, -+ 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, -+ 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, -+ 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, -+ 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, -+ 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, -+ 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, -+ 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, -+ 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, -+ 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, -+ 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, -+ 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, -+ 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, -+ 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, -+ 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, -+ 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, -+ 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, -+ 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, -+ 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, -+ 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, -+ 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, -+ 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, -+ 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, -+ 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, -+ 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, -+ 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, -+ 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, -+ 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, -+ 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, -+ 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, -+ 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, -+ 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, -+ 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, -+ 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, -+ 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, -+ 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, -+ 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, -+ 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, -+ 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, -+ 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, -+ 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, -+ 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, -+ 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, -+ 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, -+ 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, -+ 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, -+ 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, -+ 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, -+ 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, -+ 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, -+ 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, -+ 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, -+ 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, -+ 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, -+ 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, -+ 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, -+ 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, -+ 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, -+ 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, -+ 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, -+ 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, -+ 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, -+ 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, -+ 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, -+ 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, -+ 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, -+ 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, -+ 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, -+ 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, -+ 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, -+ 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, -+ 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, -+ 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, -+ 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, -+ 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, -+ 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, -+ 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, -+ 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -+ 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -+ 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, -+ 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, -+ 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -+ 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, -+ 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, -+ 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, -+ 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -+ 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -+ 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, -+ 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, -+ 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -+ 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -+ 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, -+ 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, -+ 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -+ 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, -+ 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, -+ 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, -+ 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, -+ 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, -+ 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, -+ 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, -+ 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -+ 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -+ 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, -+ 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, -+ 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, -+ 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -+ 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -+ 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, -+ 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -+ 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -+ 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, -+ 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, -+ 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -+ 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -+ 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, -+ 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, -+ 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -+ 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -+ 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, -+ 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, -+ 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, -+ 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, -+ 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, -+ 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, -+ 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, -+ 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, -+ 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, -+ 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, -+ 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, -+ 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, -+ 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, -+ 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, -+ 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, -+ 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, -+ 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, -+ 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, -+ 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, -+ 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, -+ 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, -+ 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, -+ 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, -+ 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, -+ 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, -+ 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, -+ 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, -+ 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, -+ 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, -+ 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, -+ 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, -+ 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, -+ 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, -+ 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, -+ 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, -+ 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, -+ 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, -+ 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, -+ 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, -+ 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, -+ 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, -+ 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, -+ 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, -+ 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, -+ 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, -+ 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, -+ 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, -+ 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, -+ 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, -+ 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, -+ 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, -+ 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, -+ 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, -+ 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, -+ 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, -+ 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, -+ 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, -+ 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, -+ 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, -+ 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, -+ 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, -+ 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, -+ 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, -+ 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, -+ 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, -+ 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, -+ 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, -+ 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, -+ 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, -+ 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, -+ 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, -+ 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, -+ 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, -+ 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, -+ 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, -+ 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, -+ 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, -+ 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, -+ 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, -+ 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, -+ 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, -+ 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, -+ 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, -+ 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, -+ 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, -+ 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, -+ 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, -+ 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, -+ 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, -+ 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, -+ 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, -+ 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, -+ 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, -+ 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, -+ 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, -+ 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, -+ 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, -+ 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, -+ 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, -+ 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, -+ 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, -+ 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, -+ 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, -+ 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, -+ 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, -+ 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, -+ 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, -+ 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, -+ 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, -+ 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, -+ 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -+ 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -+ 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -+ 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -+ 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, -+ 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, -+ 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, -+ 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, -+ 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, -+ 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, -+ 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, -+ 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, -+ 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, -+ 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, -+ 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, -+ 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, -+ 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, -+ 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, -+ 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, -+ 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, -+ 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, -+ 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, -+ 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, -+ 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, -+ 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, -+ 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, -+ 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, -+ 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, -+ 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, -+ 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, -+ 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, -+ 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, -+ 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, -+ 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, -+ 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, -+ 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, -+ 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, -+ 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, -+ 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, -+ 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, -+ 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, -+ 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, -+ 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, -+ 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, -+ 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, -+ 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, -+ 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, -+ 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, -+ 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, -+ 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, -+ 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, -+ 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, -+ 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, -+ 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, -+ 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, -+ 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, -+ 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, -+ 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, -+ 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, -+ 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, -+ 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, -+ 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, -+ 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, -+ 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, -+ 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, -+ 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, -+ 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, -+ 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, -+ 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, -+ 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, -+ 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, -+ 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, -+ 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, -+ 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, -+ 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, -+ 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, -+ 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, -+ 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, -+ 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, -+ 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, -+ 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, -+ 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, -+ 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, -+ 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, -+ 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, -+ 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, -+ 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, -+ 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, -+ 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, -+ 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, -+ 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, -+ 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, -+ 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, -+ 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, -+ 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, -+ 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, -+ 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, -+ 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, -+ 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, -+ 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, -+ 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, -+ 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, -+ 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, -+ 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, -+ 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, -+ 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, -+ 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, -+ 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, -+ 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, -+ 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, -+ 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, -+ 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, -+ 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, -+ 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, -+ 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, -+ 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, -+ 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, -+ 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, -+ 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, -+ 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, -+ 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, -+ 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, -+ 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, -+ 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, -+ 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, -+ 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, -+ 0xFE, 0xFF, 0xFF, 0xFF -+}; --- -cgit 1.2-0.3.lf.el7 - diff --git a/patches/drivers/ti/gpio/0002-hack-gpiolib-yes-we-have-drivers-stomping-on-each-ot.patch b/patches/drivers/ti/gpio/0002-hack-gpiolib-yes-we-have-drivers-stomping-on-each-ot.patch index 983027d0695d8cd0c46d3f75c14eb379535c3f0c..7cf8ca1ebff4e8f2c7e7fa930bfd27ff52646256 100644 --- a/patches/drivers/ti/gpio/0002-hack-gpiolib-yes-we-have-drivers-stomping-on-each-ot.patch +++ b/patches/drivers/ti/gpio/0002-hack-gpiolib-yes-we-have-drivers-stomping-on-each-ot.patch @@ -10,24 +10,24 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index bca3e7740ef6..71a8af876b4f 100644 +index bdbc1649eafa..4bf866d74e37 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c -@@ -2332,10 +2332,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) +@@ -2650,10 +2650,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { desc_set_label(desc, label ? : "?"); - status = 0; + ret = 0; - } else { - kfree_const(label); -- status = -EBUSY; +- ret = -EBUSY; - goto done; +// } else { +// kfree_const(label); -+// status = -EBUSY; ++// ret = -EBUSY; +// goto done; } if (chip->request) { -- -2.20.1 +2.23.0 diff --git a/patches/fixes/0001-ARM-don-t-export-unused-return_address.patch b/patches/fixes/0001-ARM-don-t-export-unused-return_address.patch new file mode 100644 index 0000000000000000000000000000000000000000..3db46d0d31bdbea070bda954a182bab692abeb20 --- /dev/null +++ b/patches/fixes/0001-ARM-don-t-export-unused-return_address.patch @@ -0,0 +1,33 @@ +From 8129c011ecdb5287325dfc97a81087134e83dcbe Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann <arnd@arndb.de> +Date: Fri, 6 Sep 2019 17:46:55 +0200 +Subject: [PATCH] ARM: don't export unused return_address() + +Without the frame pointer enabled, return_address() is an inline +function and does not need to be exported, as shown by this warning: + +WARNING: "return_address" [vmlinux] is a static EXPORT_SYMBOL_GPL + +Move the EXPORT_SYMBOL_GPL() into the #ifdef as well. + +Signed-off-by: Arnd Bergmann <arnd@arndb.de> +--- + arch/arm/kernel/return_address.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c +index b0d2f1fe891d..fb0fc1910102 100644 +--- a/arch/arm/kernel/return_address.c ++++ b/arch/arm/kernel/return_address.c +@@ -53,6 +53,7 @@ void *return_address(unsigned int level) + return NULL; + } + ++EXPORT_SYMBOL_GPL(return_address); ++ + #endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */ + +-EXPORT_SYMBOL_GPL(return_address); +-- +2.23.0 + diff --git a/patches/ref_omap2plus_defconfig b/patches/ref_omap2plus_defconfig index 9aaf84a0f82d9e1fdb70665ee10509222f6be6c1..d8580dbb610de413851670e36e1d075528effed5 100644 --- a/patches/ref_omap2plus_defconfig +++ b/patches/ref_omap2plus_defconfig @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.3.2 Kernel Configuration +# Linux/arm 5.4.0-rc1 Kernel Configuration # # @@ -11,6 +11,7 @@ CONFIG_GCC_VERSION=80300 CONFIG_CLANG_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_EXTABLE_SORT=y @@ -256,19 +257,13 @@ CONFIG_ARCH_MULTIPLATFORM=y # CONFIG_ARCH_EBSA110 is not set # CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_IOP13XX is not set # CONFIG_ARCH_IOP32X is not set -# CONFIG_ARCH_IOP33X is not set # CONFIG_ARCH_IXP4XX is not set # CONFIG_ARCH_DOVE is not set -# CONFIG_ARCH_KS8695 is not set -# CONFIG_ARCH_W90X900 is not set -# CONFIG_ARCH_LPC32XX is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C24XX is not set -# CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP1 is not set # @@ -642,8 +637,6 @@ CONFIG_ARCH_HIBERNATION_POSSIBLE=y # # Firmware Drivers # -# CONFIG_ARM_SCMI_PROTOCOL is not set -# CONFIG_ARM_SCPI_PROTOCOL is not set # CONFIG_FIRMWARE_MEMMAP is not set # CONFIG_FW_CFG_SYSFS is not set # CONFIG_TRUSTED_FOUNDATIONS is not set @@ -723,6 +716,7 @@ CONFIG_ARCH_HAS_ELF_RANDOMIZE=y CONFIG_HAVE_ARCH_MMAP_RND_BITS=y CONFIG_HAVE_EXIT_THREAD=y CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y CONFIG_CLONE_BACKWARDS=y CONFIG_OLD_SIGSUSPEND3=y CONFIG_OLD_SIGACTION=y @@ -769,6 +763,8 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_MODULE_SIG is not set # CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_UNUSED_SYMBOLS is not set # CONFIG_TRIM_UNUSED_KSYMS is not set CONFIG_MODULES_TREE_LOOKUP=y CONFIG_BLOCK=y @@ -781,6 +777,7 @@ CONFIG_BLK_SCSI_REQUEST=y # CONFIG_BLK_CMDLINE_PARSER is not set # CONFIG_BLK_WBT is not set # CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CGROUP_IOCOST is not set CONFIG_BLK_DEBUG_FS=y # CONFIG_BLK_SED_OPAL is not set @@ -810,7 +807,6 @@ CONFIG_EFI_PARTITION=y # end of Partition Types CONFIG_BLK_MQ_PCI=y -CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_PM=y # @@ -1051,6 +1047,7 @@ CONFIG_CAN=m CONFIG_CAN_RAW=m CONFIG_CAN_BCM=m CONFIG_CAN_GW=m +# CONFIG_CAN_J1939 is not set CONFIG_CAN_ISOTP=m # @@ -1063,6 +1060,7 @@ CONFIG_CAN_DEV=m CONFIG_CAN_CALC_BITTIMING=y # CONFIG_CAN_FLEXCAN is not set # CONFIG_CAN_GRCAN is not set +# CONFIG_CAN_KVASER_PCIEFD is not set # CONFIG_CAN_TI_HECC is not set CONFIG_CAN_C_CAN=m CONFIG_CAN_C_CAN_PLATFORM=m @@ -1246,6 +1244,7 @@ CONFIG_PCI_DRA7XX_EP=y # CONFIG_PCIE_DW_PLAT_HOST is not set # CONFIG_PCIE_DW_PLAT_EP is not set # CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_LAYERSCAPE_EP is not set # CONFIG_PCI_MESON is not set # end of DesignWare PCI Core Support # end of PCI controller drivers @@ -1308,6 +1307,7 @@ CONFIG_GENERIC_ARCH_TOPOLOGY=y # Bus devices # # CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_MOXTET is not set CONFIG_OMAP_INTERCONNECT=y CONFIG_OMAP_OCP2SCP=y # CONFIG_SIMPLE_PM_BUS is not set @@ -1319,13 +1319,13 @@ CONFIG_CONNECTOR=m # CONFIG_GNSS is not set CONFIG_MTD=y # CONFIG_MTD_TESTS is not set -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_OF_PARTS=y -# CONFIG_MTD_AR7_PARTS is not set # # Partition parsers # +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_OF_PARTS=y # CONFIG_MTD_AFS_PARTS is not set # CONFIG_MTD_REDBOOT_PARTS is not set # end of Partition parsers @@ -1384,7 +1384,6 @@ CONFIG_MTD_PHYSMAP_OF=y # # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_DATAFLASH is not set -CONFIG_MTD_M25P80=m # CONFIG_MTD_MCHP23K256 is not set # CONFIG_MTD_SST25L is not set # CONFIG_MTD_SLRAM is not set @@ -1420,6 +1419,7 @@ CONFIG_MTD_NAND_OMAP_BCH=y CONFIG_MTD_NAND_OMAP_BCH_BUILD=y # CONFIG_MTD_NAND_CAFE is not set # CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_MXIC is not set # CONFIG_MTD_NAND_GPIO is not set # CONFIG_MTD_NAND_PLATFORM is not set @@ -1478,7 +1478,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=16384 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set -# CONFIG_VIRTIO_BLK is not set # CONFIG_BLK_DEV_RBD is not set # CONFIG_BLK_DEV_RSXX is not set @@ -1496,7 +1495,6 @@ CONFIG_BLK_DEV_RAM_SIZE=16384 # CONFIG_AD525X_DPOT is not set # CONFIG_DUMMY_IRQ is not set # CONFIG_PHANTOM is not set -# CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -1673,7 +1671,6 @@ CONFIG_SCSI_LOWLEVEL=y # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_PMCRAID is not set # CONFIG_SCSI_PM8001 is not set -# CONFIG_SCSI_VIRTIO is not set # CONFIG_SCSI_DH is not set # end of SCSI device support @@ -1798,7 +1795,6 @@ CONFIG_NET_CORE=y # CONFIG_TUN is not set # CONFIG_TUN_VNET_CROSS_LE is not set # CONFIG_VETH is not set -# CONFIG_VIRTIO_NET is not set # CONFIG_NLMON is not set # CONFIG_ARCNET is not set @@ -1907,10 +1903,10 @@ CONFIG_NET_VENDOR_OKI=y CONFIG_NET_VENDOR_PACKET_ENGINES=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set +CONFIG_NET_VENDOR_PENSANDO=y CONFIG_NET_VENDOR_QLOGIC=y # CONFIG_QLA3XXX is not set # CONFIG_QLCNIC is not set -# CONFIG_QLGE is not set # CONFIG_NETXEN_NIC is not set # CONFIG_QED is not set # CONFIG_NET_VENDOR_QUALCOMM is not set @@ -1979,6 +1975,7 @@ CONFIG_SWPHY=y # # MII PHY device drivers # +# CONFIG_ADIN_PHY is not set # CONFIG_AMD_PHY is not set # CONFIG_AQUANTIA_PHY is not set # CONFIG_AX88796B_PHY is not set @@ -2338,7 +2335,6 @@ CONFIG_INPUT_PWM_VIBRA=m # CONFIG_INPUT_ADXL34X is not set # CONFIG_INPUT_IMS_PCU is not set # CONFIG_INPUT_CMA3000 is not set -# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set # CONFIG_INPUT_DRV260X_HAPTICS is not set # CONFIG_INPUT_DRV2665_HAPTICS is not set # CONFIG_INPUT_DRV2667_HAPTICS is not set @@ -2408,7 +2404,6 @@ CONFIG_SERIAL_8250_FSL=y # CONFIG_SERIAL_8250_RT288X is not set CONFIG_SERIAL_8250_OMAP=y CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP=y -# CONFIG_SERIAL_8250_MOXA is not set CONFIG_SERIAL_OF_PLATFORM=y # @@ -2434,6 +2429,7 @@ CONFIG_SERIAL_OMAP_CONSOLE=y # CONFIG_SERIAL_ARC is not set # CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set # CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set # CONFIG_SERIAL_ST_ASC is not set # end of Serial drivers @@ -2443,13 +2439,11 @@ CONFIG_SERIAL_DEV_BUS=y CONFIG_SERIAL_DEV_CTRL_TTYPORT=y # CONFIG_TTY_PRINTK is not set # CONFIG_HVC_DCC is not set -# CONFIG_VIRTIO_CONSOLE is not set # CONFIG_IPMI_HANDLER is not set CONFIG_HW_RANDOM=m # CONFIG_HW_RANDOM_TIMERIOMEM is not set CONFIG_HW_RANDOM_OMAP=m CONFIG_HW_RANDOM_OMAP3_ROM=m -# CONFIG_HW_RANDOM_VIRTIO is not set # CONFIG_APPLICOM is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set @@ -2457,6 +2451,8 @@ CONFIG_DEVPORT=y # CONFIG_XILLYBUS is not set # end of Character devices +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set + # # I2C support # @@ -2712,6 +2708,7 @@ CONFIG_W1_CON=y # CONFIG_W1_MASTER_DS1WM is not set # CONFIG_W1_MASTER_GPIO is not set CONFIG_HDQ_MASTER_OMAP=m +# CONFIG_W1_MASTER_SGI is not set # end of 1-wire Bus Masters # @@ -2728,6 +2725,7 @@ CONFIG_HDQ_MASTER_OMAP=m # CONFIG_W1_SLAVE_DS2431 is not set # CONFIG_W1_SLAVE_DS2433 is not set # CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS250X is not set # CONFIG_W1_SLAVE_DS2780 is not set # CONFIG_W1_SLAVE_DS2781 is not set # CONFIG_W1_SLAVE_DS28E04 is not set @@ -2808,6 +2806,7 @@ CONFIG_HWMON=m # CONFIG_SENSORS_ADT7462 is not set # CONFIG_SENSORS_ADT7470 is not set # CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AS370 is not set # CONFIG_SENSORS_ASC7621 is not set # CONFIG_SENSORS_ASPEED is not set # CONFIG_SENSORS_ATXP1 is not set @@ -2897,7 +2896,6 @@ CONFIG_SENSORS_LM75=m # CONFIG_SENSORS_STTS751 is not set # CONFIG_SENSORS_SMM665 is not set # CONFIG_SENSORS_ADC128D818 is not set -# CONFIG_SENSORS_ADS1015 is not set # CONFIG_SENSORS_ADS7828 is not set # CONFIG_SENSORS_ADS7871 is not set # CONFIG_SENSORS_AMC6821 is not set @@ -3014,7 +3012,6 @@ CONFIG_MFD_CORE=y # CONFIG_MFD_BCM590XX is not set # CONFIG_MFD_BD9571MWV is not set # CONFIG_MFD_AXP20X_I2C is not set -# CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_MADERA is not set # CONFIG_MFD_ASIC3 is not set # CONFIG_PMIC_DA903X is not set @@ -3158,6 +3155,7 @@ CONFIG_REGULATOR_PBIAS=y # CONFIG_REGULATOR_SLG51000 is not set CONFIG_REGULATOR_TI_ABB=y # CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set # CONFIG_REGULATOR_TPS51632 is not set CONFIG_REGULATOR_TPS62360=m CONFIG_REGULATOR_TPS65023=y @@ -3210,6 +3208,7 @@ CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_DEV=m CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_V4L2=m +CONFIG_VIDEO_V4L2_I2C=y # CONFIG_VIDEO_ADV_DEBUG is not set # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set CONFIG_V4L2_FWNODE=m @@ -3339,6 +3338,7 @@ CONFIG_VIDEO_TVP5150=m # CONFIG_VIDEO_OV5647 is not set # CONFIG_VIDEO_OV6650 is not set # CONFIG_VIDEO_OV5670 is not set +# CONFIG_VIDEO_OV5675 is not set # CONFIG_VIDEO_OV5695 is not set # CONFIG_VIDEO_OV7251 is not set # CONFIG_VIDEO_OV772X is not set @@ -3510,18 +3510,11 @@ CONFIG_DRM_OMAP_ENCODER_TPD12S015=m CONFIG_DRM_OMAP_CONNECTOR_HDMI=m CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV=m CONFIG_DRM_OMAP_PANEL_DSI_CM=m -CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM=m -CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02=m -CONFIG_DRM_OMAP_PANEL_SHARP_LS037V7DW01=m -CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1=m -CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1=m -CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11=m # end of OMAPDRM External Display Device Drivers CONFIG_DRM_TILCDC=m # CONFIG_DRM_QXL is not set # CONFIG_DRM_BOCHS is not set -# CONFIG_DRM_VIRTIO_GPU is not set # CONFIG_DRM_FSL_DCU is not set # CONFIG_DRM_STM is not set CONFIG_DRM_PANEL=y @@ -3531,15 +3524,22 @@ CONFIG_DRM_PANEL=y # # CONFIG_DRM_PANEL_ARM_VERSATILE is not set # CONFIG_DRM_PANEL_LVDS is not set -# CONFIG_DRM_PANEL_SIMPLE is not set +CONFIG_DRM_PANEL_SIMPLE=m # CONFIG_DRM_PANEL_ILITEK_IL9322 is not set # CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set # CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set # CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set # CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set # CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set # CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set # CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set # CONFIG_DRM_PANEL_TPO_TPG110 is not set # end of Display Panels @@ -3570,9 +3570,15 @@ CONFIG_DRM_PANEL_BRIDGE=y # CONFIG_DRM_STI is not set # CONFIG_DRM_ETNAVIV is not set # CONFIG_DRM_ARCPGU is not set -# CONFIG_DRM_HISI_HIBMC is not set # CONFIG_DRM_MXSFB is not set -# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_MI0283QT is not set +# CONFIG_TINYDRM_REPAPER is not set +# CONFIG_TINYDRM_ST7586 is not set +# CONFIG_TINYDRM_ST7735R is not set # CONFIG_DRM_PL111 is not set # CONFIG_DRM_TVE200 is not set # CONFIG_DRM_LIMA is not set @@ -3970,6 +3976,7 @@ CONFIG_SND_SOC_TLV320AIC3X=m # CONFIG_SND_SOC_TSCS454 is not set CONFIG_SND_SOC_TWL4030=m CONFIG_SND_SOC_TWL6040=m +# CONFIG_SND_SOC_UDA1334 is not set # CONFIG_SND_SOC_WM8510 is not set # CONFIG_SND_SOC_WM8523 is not set # CONFIG_SND_SOC_WM8524 is not set @@ -4037,6 +4044,7 @@ CONFIG_HID_GENERIC=m # CONFIG_HID_MACALLY is not set # CONFIG_HID_PRODIKEYS is not set # CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set # CONFIG_HID_CYPRESS is not set # CONFIG_HID_DRAGONRISE is not set # CONFIG_HID_EMS_FF is not set @@ -4131,6 +4139,9 @@ CONFIG_USB_MOUSE=m CONFIG_USB_OHCI_LITTLE_ENDIAN=y CONFIG_USB_SUPPORT=y CONFIG_USB_COMMON=m +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_CONN_GPIO is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB=m CONFIG_USB_PCI=y @@ -4147,7 +4158,6 @@ CONFIG_USB_DEFAULT_PERSIST=y # CONFIG_USB_LEDS_TRIGGER_USBPORT is not set CONFIG_USB_AUTOSUSPEND_DELAY=2 CONFIG_USB_MON=m -# CONFIG_USB_WUSB_CBAF is not set # # USB Host Controller Drivers @@ -4215,6 +4225,7 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set # CONFIG_USBIP_CORE is not set +# CONFIG_USB_CDNS3 is not set CONFIG_USB_MUSB_HDRC=m # CONFIG_USB_MUSB_HOST is not set # CONFIG_USB_MUSB_GADGET is not set @@ -4441,9 +4452,6 @@ CONFIG_USB_G_NOKIA=m # CONFIG_USB_G_WEBCAM is not set # CONFIG_TYPEC is not set # CONFIG_USB_ROLE_SWITCH is not set -# CONFIG_USB_LED_TRIG is not set -# CONFIG_USB_ULPI_BUS is not set -# CONFIG_UWB is not set CONFIG_MMC=y CONFIG_PWRSEQ_EMMC=y # CONFIG_PWRSEQ_SD8787 is not set @@ -4461,6 +4469,7 @@ CONFIG_MMC_SDHCI=y # CONFIG_MMC_SDHCI_PCI is not set CONFIG_MMC_SDHCI_PLTFM=y # CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ASPEED is not set # CONFIG_MMC_SDHCI_OF_AT91 is not set # CONFIG_MMC_SDHCI_OF_DWCMSHC is not set # CONFIG_MMC_SDHCI_CADENCE is not set @@ -4600,7 +4609,6 @@ CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_PCF8583 is not set CONFIG_RTC_DRV_M41T80=m # CONFIG_RTC_DRV_M41T80_WDT is not set -# CONFIG_RTC_DRV_BD70528 is not set # CONFIG_RTC_DRV_BQ32K is not set CONFIG_RTC_DRV_TWL92330=y CONFIG_RTC_DRV_TWL4030=m @@ -4714,17 +4722,15 @@ CONFIG_TI_DMA_CROSSBAR=y CONFIG_SYNC_FILE=y # CONFIG_SW_SYNC is not set # CONFIG_UDMABUF is not set +# CONFIG_DMABUF_SELFTESTS is not set # end of DMABUF options # CONFIG_AUXDISPLAY is not set # CONFIG_UIO is not set # CONFIG_VFIO is not set # CONFIG_VIRT_DRIVERS is not set -CONFIG_VIRTIO=m CONFIG_VIRTIO_MENU=y # CONFIG_VIRTIO_PCI is not set -# CONFIG_VIRTIO_BALLOON is not set -# CONFIG_VIRTIO_INPUT is not set # CONFIG_VIRTIO_MMIO is not set # @@ -4732,8 +4738,10 @@ CONFIG_VIRTIO_MENU=y # # end of Microsoft Hyper-V guest support +# CONFIG_GREYBUS is not set # CONFIG_STAGING is not set # CONFIG_GOLDFISH is not set +# CONFIG_MFD_CROS_EC is not set # CONFIG_CHROME_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set CONFIG_CLKDEV_LOOKUP=y @@ -4776,12 +4784,7 @@ CONFIG_ARM_ARCH_TIMER=y CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y # end of Clock Source drivers -CONFIG_MAILBOX=y -# CONFIG_PLATFORM_MHU is not set -CONFIG_OMAP2PLUS_MBOX=m -CONFIG_OMAP_MBOX_KFIFO_SIZE=256 -# CONFIG_ALTERA_MBOX is not set -# CONFIG_MAILBOX_TEST is not set +# CONFIG_MAILBOX is not set CONFIG_IOMMU_API=y CONFIG_IOMMU_SUPPORT=y @@ -4802,15 +4805,12 @@ CONFIG_OMAP_IOMMU=y # # Remoteproc drivers # -CONFIG_REMOTEPROC=m -CONFIG_OMAP_REMOTEPROC=m -CONFIG_WKUP_M3_RPROC=m +# CONFIG_REMOTEPROC is not set # end of Remoteproc drivers # # Rpmsg drivers # -# CONFIG_RPMSG_QCOM_GLINK_RPM is not set # CONFIG_RPMSG_VIRTIO is not set # end of Rpmsg drivers @@ -4852,8 +4852,6 @@ CONFIG_WKUP_M3_RPROC=m # end of Qualcomm SoC drivers CONFIG_SOC_TI=y -CONFIG_AMX3_PM=m -CONFIG_WKUP_M3_IPC=m # # Xilinx SoC drivers @@ -4912,7 +4910,6 @@ CONFIG_IIO_SW_TRIGGER=m # CONFIG_DMARD06 is not set # CONFIG_DMARD09 is not set # CONFIG_DMARD10 is not set -# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set CONFIG_IIO_ST_ACCEL_3AXIS=m CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m @@ -5138,6 +5135,7 @@ CONFIG_IIO_ST_SENSORS_CORE=m # Inertial measurement units # # CONFIG_ADIS16400 is not set +# CONFIG_ADIS16460 is not set # CONFIG_ADIS16480 is not set # CONFIG_BMI160_I2C is not set # CONFIG_BMI160_SPI is not set @@ -5170,6 +5168,7 @@ CONFIG_IIO_ST_SENSORS_CORE=m # CONFIG_LV0104CS is not set # CONFIG_MAX44000 is not set # CONFIG_MAX44009 is not set +# CONFIG_NOA1305 is not set # CONFIG_OPT3001 is not set # CONFIG_PA12203001 is not set # CONFIG_SI1133 is not set @@ -5232,6 +5231,7 @@ CONFIG_IIO_ST_SENSORS_CORE=m # # CONFIG_AD5272 is not set # CONFIG_DS1803 is not set +# CONFIG_MAX5432 is not set # CONFIG_MAX5481 is not set # CONFIG_MAX5487 is not set # CONFIG_MCP4018 is not set @@ -5427,6 +5427,7 @@ CONFIG_EXPORTFS=y CONFIG_FILE_LOCKING=y CONFIG_MANDATORY_FILE_LOCKING=y # CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set CONFIG_FSNOTIFY=y CONFIG_DNOTIFY=y CONFIG_INOTIFY_USER=y @@ -5536,7 +5537,7 @@ CONFIG_CRAMFS_BLOCKDEV=y # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_AUFS_FS is not set +# CONFIG_EROFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y @@ -5640,13 +5641,14 @@ CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y # CONFIG_SECURITY_LOADPIN is not set # CONFIG_SECURITY_YAMA is not set # CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set CONFIG_INTEGRITY=y # CONFIG_INTEGRITY_SIGNATURE is not set CONFIG_INTEGRITY_AUDIT=y # CONFIG_IMA is not set # CONFIG_EVM is not set CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_LSM="yama,loadpin,safesetid,integrity" +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" # # Kernel hardening options @@ -5699,7 +5701,6 @@ CONFIG_CRYPTO_CRYPTD=m # CONFIG_CRYPTO_AUTHENC is not set # CONFIG_CRYPTO_TEST is not set CONFIG_CRYPTO_SIMD=m -CONFIG_CRYPTO_ENGINE=m # # Public-key cryptography @@ -5717,10 +5718,6 @@ CONFIG_CRYPTO_CCM=m CONFIG_CRYPTO_GCM=m # CONFIG_CRYPTO_CHACHA20POLY1305 is not set # CONFIG_CRYPTO_AEGIS128 is not set -# CONFIG_CRYPTO_AEGIS128L is not set -# CONFIG_CRYPTO_AEGIS256 is not set -# CONFIG_CRYPTO_MORUS640 is not set -# CONFIG_CRYPTO_MORUS1280 is not set CONFIG_CRYPTO_SEQIV=m # CONFIG_CRYPTO_ECHAINIV is not set @@ -5738,6 +5735,7 @@ CONFIG_CRYPTO_PCBC=m # CONFIG_CRYPTO_XTS is not set # CONFIG_CRYPTO_KEYWRAP is not set # CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_ESSIV is not set # # Hash modes @@ -5764,6 +5762,7 @@ CONFIG_CRYPTO_MICHAEL_MIC=y # CONFIG_CRYPTO_RMD256 is not set # CONFIG_CRYPTO_RMD320 is not set CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_LIB_SHA256=m CONFIG_CRYPTO_SHA256=m # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_SHA3 is not set @@ -5775,6 +5774,7 @@ CONFIG_CRYPTO_SHA256=m # # Ciphers # +CONFIG_CRYPTO_LIB_AES=m CONFIG_CRYPTO_AES=m # CONFIG_CRYPTO_AES_TI is not set # CONFIG_CRYPTO_ANUBIS is not set @@ -5825,7 +5825,7 @@ CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_OMAP is not set # CONFIG_CRYPTO_DEV_ATMEL_ECC is not set # CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set -CONFIG_CRYPTO_DEV_VIRTIO=m +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set # CONFIG_CRYPTO_DEV_CCREE is not set CONFIG_ASYMMETRIC_KEY_TYPE=y CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y @@ -5933,7 +5933,6 @@ CONFIG_GENERIC_ATOMIC64=y CONFIG_CLZ_TAB=y # CONFIG_IRQ_POLL is not set CONFIG_MPILIB=y -CONFIG_DIMLIB=y CONFIG_LIBFDT=y CONFIG_OID_REGISTRY=y CONFIG_FONT_SUPPORT=y @@ -5985,10 +5984,9 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_FRAME_WARN=1024 # CONFIG_STRIP_ASM_SYMS is not set # CONFIG_READABLE_ASM is not set -# CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_FS=y # CONFIG_HEADERS_INSTALL is not set -# CONFIG_OPTIMIZE_INLINING is not set +CONFIG_OPTIMIZE_INLINING=y # CONFIG_DEBUG_SECTION_MISMATCH is not set CONFIG_SECTION_MISMATCH_WARN_ONLY=y # CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set diff --git a/patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.3.x.patch b/patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.4.x.patch similarity index 99% rename from patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.3.x.patch rename to patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.4.x.patch index 1ddb8dee9ef95c3178b01d5b2f60009e354e3f9b..44a5b22c8e8093ab7bd25dffeee642ff77121dd8 100644 --- a/patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.3.x.patch +++ b/patches/soc/ti/beagleboard_dtbs/0001-Add-BeagleBoard.org-DTBS-v5.4.x.patch @@ -1,9 +1,9 @@ -From c6423b69f11cc28a5d5f37b8bd548d91a983d738 Mon Sep 17 00:00:00 2001 +From 1012eb42edd62e3c26bb04228b09430c59dfec29 Mon Sep 17 00:00:00 2001 From: Robert Nelson <robertcnelson@gmail.com> -Date: Tue, 1 Oct 2019 10:29:42 -0500 -Subject: [PATCH] Add BeagleBoard.org DTBS: v5.3.x +Date: Tue, 1 Oct 2019 13:27:28 -0500 +Subject: [PATCH] Add BeagleBoard.org DTBS: v5.4.x -https://github.com/beagleboard/BeagleBoard-DeviceTrees/tree/v5.3.x +https://github.com/beagleboard/BeagleBoard-DeviceTrees/tree/v5.4.x Signed-off-by: Robert Nelson <robertcnelson@gmail.com> --- arch/arm/boot/dts/Makefile | 6 + @@ -16,11 +16,11 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> arch/arm/boot/dts/am335x-bone.dts | 6 + .../arm/boot/dts/am335x-boneblack-common.dtsi | 10 +- .../boot/dts/am335x-boneblack-uboot-univ.dts | 40 + - arch/arm/boot/dts/am335x-boneblack-uboot.dts | 41 + + arch/arm/boot/dts/am335x-boneblack-uboot.dts | 40 + .../boot/dts/am335x-boneblack-wireless.dts | 6 + arch/arm/boot/dts/am335x-boneblack.dts | 6 + - arch/arm/boot/dts/am335x-boneblue.dts | 491 ++- - ...am335x-bonegreen-wireless-common-univ.dtsi | 2794 ++++++++++++++++ + arch/arm/boot/dts/am335x-boneblue.dts | 469 ++- + ...am335x-bonegreen-wireless-common-univ.dtsi | 2823 ++++++++++++++++ .../am335x-bonegreen-wireless-uboot-univ.dts | 55 + .../boot/dts/am335x-bonegreen-wireless.dts | 6 + arch/arm/boot/dts/am335x-bonegreen.dts | 6 + @@ -45,7 +45,7 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> arch/arm/boot/dts/omap4.dtsi | 2 + arch/arm/boot/dts/twl6030.dtsi | 5 + .../dt-bindings/board/am335x-bbw-bbb-base.h | 103 + - 39 files changed, 9465 insertions(+), 118 deletions(-) + 39 files changed, 9473 insertions(+), 116 deletions(-) create mode 100644 arch/arm/boot/dts/am335x-abbbi.dts create mode 100644 arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi create mode 100644 arch/arm/boot/dts/am335x-bone-common-univ.dtsi @@ -59,10 +59,10 @@ Signed-off-by: Robert Nelson <robertcnelson@gmail.com> create mode 100644 include/dt-bindings/board/am335x-bbw-bbb-base.h diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 9159fa2cea90..fe03bb9ef7e5 100644 +index b21b3a64641a..a979e20ee430 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -732,6 +732,11 @@ dtb-$(CONFIG_SOC_AM33XX) += \ +@@ -739,6 +739,11 @@ dtb-$(CONFIG_SOC_AM33XX) += \ am335x-base0033.dtb \ am335x-bone.dtb \ am335x-boneblack.dtb \ @@ -74,7 +74,7 @@ index 9159fa2cea90..fe03bb9ef7e5 100644 am335x-boneblack-wireless.dtb \ am335x-boneblue.dtb \ am335x-bonegreen.dtb \ -@@ -762,6 +767,7 @@ dtb-$(CONFIG_ARCH_OMAP4) += \ +@@ -769,6 +774,7 @@ dtb-$(CONFIG_ARCH_OMAP4) += \ omap4-duovero-parlor.dtb \ omap4-kc1.dtb \ omap4-panda.dtb \ @@ -3797,10 +3797,10 @@ index 000000000000..4e5633e38694 +}; diff --git a/arch/arm/boot/dts/am335x-boneblack-uboot.dts b/arch/arm/boot/dts/am335x-boneblack-uboot.dts new file mode 100644 -index 000000000000..09e8c27a4b29 +index 000000000000..285a92126854 --- /dev/null +++ b/arch/arm/boot/dts/am335x-boneblack-uboot.dts -@@ -0,0 +1,41 @@ +@@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ @@ -3809,7 +3809,6 @@ index 000000000000..09e8c27a4b29 + +#include "am33xx.dtsi" +#include "am335x-bone-common.dtsi" -+ +/* #include "am335x-bone-jtag.dtsi" */ + +/ { @@ -3886,22 +3885,19 @@ index d3928662aed4..40b17b956109 100644 &cpu0_opp_table { diff --git a/arch/arm/boot/dts/am335x-boneblue.dts b/arch/arm/boot/dts/am335x-boneblue.dts -index 0257576d5d16..6df70194b15d 100644 +index 2f6652ef9a15..78a360558d9e 100644 --- a/arch/arm/boot/dts/am335x-boneblue.dts +++ b/arch/arm/boot/dts/am335x-boneblue.dts -@@ -11,6 +11,11 @@ - model = "TI AM335x BeagleBone Blue"; - compatible = "ti,am335x-bone-blue", "ti,am33xx"; +@@ -14,6 +14,8 @@ -+ chosen { + chosen { + stdout-path = &uart0; + base_dtb = "am335x-boneblue.dts"; + base_dtb_timestamp = __TIMESTAMP__; -+ }; -+ - cpus { - cpu@0 { - cpu0-supply = <&dcdc2_reg>; -@@ -122,9 +127,183 @@ + }; + + leds { +@@ -112,9 +114,168 @@ gpio = <&gpio3 9 0>; enable-active-high; }; @@ -3916,21 +3912,6 @@ index 0257576d5d16..6df70194b15d 100644 + gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; -+ }; -+}; -+ -+&cpu0_opp_table { -+ /* -+ * Octavo Systems: -+ * The EFUSE_SMA register is not programmed for any of the AM335x wafers -+ * we get and we are not programming them during our production test. -+ * Therefore, from a DEVICE_ID revision point of view, the silicon looks -+ * like it is Revision 2.1. However, from an EFUSE_SMA point of view for -+ * the HW OPP table, the silicon looks like it is Revision 1.0 (ie the -+ * EFUSE_SMA register reads as all zeros). -+ */ -+ oppnitro-1000000000 { -+ opp-supported-hw = <0x06 0x0100>; + }; }; @@ -4085,7 +4066,7 @@ index 0257576d5d16..6df70194b15d 100644 user_leds_s0: user_leds_s0 { pinctrl-single,pins = < AM33XX_PADCONF(AM335X_PIN_GPMC_A5, PIN_OUTPUT, MUX_MODE7) /* (V15) gpmc_a5.gpio1[21] - USR_LED_0 */ -@@ -181,11 +360,11 @@ +@@ -164,11 +325,11 @@ }; /* DSM2 */ @@ -4102,7 +4083,7 @@ index 0257576d5d16..6df70194b15d 100644 /* UT5 */ uart5_pins: pinmux_uart5_pins { -@@ -258,6 +437,51 @@ +@@ -241,6 +402,51 @@ AM33XX_PADCONF(AM335X_PIN_MII1_RXD0, PIN_OUTPUT, MUX_MODE7) /* (M16) gmii1_rxd0.gpio2[21] */ >; }; @@ -4154,7 +4135,7 @@ index 0257576d5d16..6df70194b15d 100644 }; &uart0 { -@@ -281,12 +505,12 @@ +@@ -264,12 +470,12 @@ status = "okay"; }; @@ -4173,16 +4154,7 @@ index 0257576d5d16..6df70194b15d 100644 &uart5 { pinctrl-names = "default"; -@@ -384,6 +608,8 @@ - interrupts = <7>; /* NMI */ - interrupt-parent = <&intc>; - -+ ti,pmic-shutdown-controller; -+ - charger { - interrupts = <0>, <1>; - interrupt-names = "USB", "AC"; -@@ -484,22 +710,23 @@ +@@ -404,22 +610,23 @@ }; }; @@ -4216,21 +4188,19 @@ index 0257576d5d16..6df70194b15d 100644 +// }; }; - &aes { -@@ -512,8 +739,10 @@ - &rtc { - system-power-controller; -- clocks = <&clk_32768_ck>, <&clk_24mhz_clkctrl AM3_CLK_24MHZ_CLKDIV32K_CLKCTRL 0>; -- clock-names = "ext-clk", "int-clk"; -+}; -+ -+&wkup_m3_ipc { -+ ti,scale-data-fw = "am335x-bone-scale-data.bin"; +@@ -428,6 +635,10 @@ + clock-names = "ext-clk", "int-clk"; }; ++&wkup_m3_ipc { ++ ti,scale-data-fw = "am335x-bone-scale-data.bin"; ++}; ++ &dcan1 { -@@ -530,3 +759,217 @@ + pinctrl-names = "default"; + pinctrl-0 = <&dcan1_pins>; +@@ -442,3 +653,217 @@ line-name = "LS_BUF_EN"; }; }; @@ -4450,10 +4420,10 @@ index 0257576d5d16..6df70194b15d 100644 +}; diff --git a/arch/arm/boot/dts/am335x-bonegreen-wireless-common-univ.dtsi b/arch/arm/boot/dts/am335x-bonegreen-wireless-common-univ.dtsi new file mode 100644 -index 000000000000..e6f28c969b75 +index 000000000000..4662f304f3ee --- /dev/null +++ b/arch/arm/boot/dts/am335x-bonegreen-wireless-common-univ.dtsi -@@ -0,0 +1,2794 @@ +@@ -0,0 +1,2823 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ @@ -5584,6 +5554,18 @@ index 000000000000..e6f28c969b75 + /* P9_45 GND */ + + /* P9_46 GND */ ++ ++ /* (ZCZ ball A15) */ ++ A15_default_pin: pinmux_A15_default_pin { ++ pinctrl-single,pins = <0x1b0 0x0b>; }; /* Mode 3 */ ++ A15_clkout_pin: pinmux_A15_clkout_pin { ++ pinctrl-single,pins = <0x1b0 0x0b>; }; /* Mode 3 */ ++ A15_gpio_pin: pinmux_A15_gpio_pin { ++ pinctrl-single,pins = <0x1b0 0x2f>; }; /* Mode 7, RxActive */ ++ A15_gpio_pu_pin: pinmux_A15_gpio_pu_pin { ++ pinctrl-single,pins = <0x1b0 0x37>; }; /* Mode 7, Pull-Up, RxActive */ ++ A15_gpio_pd_pin: pinmux_A15_gpio_pd_pin { ++ pinctrl-single,pins = <0x1b0 0x27>; }; /* Mode 7, Pull-Down, RxActive */ +}; + +&i2c1 { @@ -6784,6 +6766,17 @@ index 000000000000..e6f28c969b75 + + /* P9_46 GND */ + ++ /* (ZCZ ball A15) */ ++ A15_pinmux { ++ compatible = "bone-pinmux-helper"; ++ status = "okay"; ++ pinctrl-names = "default", "clkout", "gpio", "gpio_pu", "gpio_pd"; ++ pinctrl-0 = <&A15_default_pin>; ++ pinctrl-1 = <&A15_clkout_pin>; ++ pinctrl-2 = <&A15_gpio_pin>; ++ pinctrl-3 = <&A15_gpio_pu_pin>; ++ pinctrl-4 = <&A15_gpio_pd_pin>; ++ }; + + cape-universal { + compatible = "gpio-of-helper"; @@ -7246,6 +7239,12 @@ index 000000000000..e6f28c969b75 + dir-changeable; + }; + ++ A15 { ++ gpio-name = "A15"; ++ gpio = <&gpio0 19 0>; ++ input; ++ dir-changeable; ++ }; + }; +}; diff --git a/arch/arm/boot/dts/am335x-bonegreen-wireless-uboot-univ.dts b/arch/arm/boot/dts/am335x-bonegreen-wireless-uboot-univ.dts @@ -9563,7 +9562,7 @@ index 8678e6e35493..2381a5c5110c 100644 &am33xx_pinmux { diff --git a/arch/arm/boot/dts/am33xx-l4.dtsi b/arch/arm/boot/dts/am33xx-l4.dtsi -index 46849d6ecb3e..7ba792f7213c 100644 +index 9915c891e05f..f391e88ea14f 100644 --- a/arch/arm/boot/dts/am33xx-l4.dtsi +++ b/arch/arm/boot/dts/am33xx-l4.dtsi @@ -158,6 +158,39 @@ @@ -10202,7 +10201,7 @@ index 3c274965ff40..97001fefe875 100644 &keypad { diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi -index c43e52fd5f65..ec51eaabb463 100644 +index 7cc95bc1598b..b4ebf768d0f9 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -252,6 +252,7 @@ diff --git a/version.sh b/version.sh index 9643d1693ffa79f236e7f209d6b5547a81f7d8ce..831b4f94deb05091cde1a75eb755cb5b0b584108 100644 --- a/version.sh +++ b/version.sh @@ -31,11 +31,11 @@ toolchain="gcc_arm_gnueabihf_8" #toolchain="gcc_arm_aarch64_gnu_8" #Kernel -KERNEL_REL=5.3 -KERNEL_TAG=${KERNEL_REL}.2 +KERNEL_REL=5.4 +KERNEL_TAG=${KERNEL_REL}-rc1 kernel_rt=".X-rtY" #Kernel Build -BUILD=${build_prefix}9.2 +BUILD=${build_prefix}0 #v5.X-rcX + upto SHA #prev_KERNEL_SHA=""