diff --git a/source/arm11/i2c.c b/source/arm11/i2c.c new file mode 100644 index 0000000..365c3f6 --- /dev/null +++ b/source/arm11/i2c.c @@ -0,0 +1,344 @@ +#include "types.h" +#include "IO.h" +#include "mem_map.h" +#include "util.h" + + + +struct i2c_dev_table_entry { + u32 bus_id; + u8 devaddr; +}; + +static const struct i2c_dev_table_entry i2c_dev_table[] = +{ + {0, 0x4A}, + {0, 0x7A}, + {0, 0x78}, + {1, 0x4A}, + {1, 0x78}, + {1, 0x2C}, + {1, 0x2E}, + {1, 0x40}, + {1, 0x44} +}; + + +// i2c mcu defines +bool i2cmcu_reg0_upper_read; +u8 i2cmcu_reg0_upper_data; +bool i2cmcu_readreg0x0_bus0_read_flag; +u8 i2cmcu_readreg0x0_bus0_first; +u8 i2cmcu_readreg0x0_bus0_second; + + +void i2c_wait(u32 bus_id); +void i2c_put_byte(u32 bus_id, u8 data_byte); +void i2c_start(u32 bus_id); +void i2c_set_rw(u32 bus_id, u32 read_enable); +bool i2c_test_ack(u32 bus_id); +u8 i2c_receive_byte(u32 bus_id); +void i2c_stop(u32 bus_id, u32 read_enable); +void i2c_stop_err(u32 dev_id); +bool i2c_start_put_devaddr(u32 dev_id); +bool i2c_put_devaddr_set_read(u32 dev_id); +bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr); +u8 i2c_get_byte(u32 dev_id); +u8 i2c_get_byte_stop(u32 dev_id); +u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size); +u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size); + + +void i2c_wait(u32 bus_id) +{ + u8 result; + do { + if(bus_id == 0) + result = REG_I2C_BUS0_CNT; + else + result = REG_I2C_BUS1_CNT; + } while((result>>7) & 1); +} + +void i2c_put_byte(u32 bus_id, u8 data_byte) +{ + if(bus_id == 0) + REG_I2C_BUS0_DATA = data_byte; + else + REG_I2C_BUS1_DATA = data_byte; +} + +void i2c_start(u32 bus_id) +{ + wait(0x100); + if(bus_id == 0) + REG_I2C_BUS0_CNT = 0xC2; + else + REG_I2C_BUS1_CNT = 0xC2; +} + +void i2c_set_rw(u32 bus_id, u32 read_enable) +{ + u8 cnt = 0xC0; + cnt |= read_enable << 5; + cnt |= read_enable << 4; + if(bus_id == 0) + REG_I2C_BUS0_CNT = cnt; + else + REG_I2C_BUS1_CNT = cnt; +} + +bool i2c_test_ack(u32 bus_id) +{ + i2c_wait(bus_id); + wait(0x80); + u8 result; + if(bus_id == 0) + result = REG_I2C_BUS0_CNT; + else + result = REG_I2C_BUS1_CNT; + return ((result << 0x1B) >> 0x1F); // return Ack Flag +} + +u8 i2c_receive_byte(u32 bus_id) +{ + i2c_wait(bus_id); + wait(0x100); + if(bus_id == 0) + return REG_I2C_BUS0_DATA; + else + return REG_I2C_BUS1_DATA; +} + +void i2c_stop(u32 bus_id, u32 read_enable) +{ + u8 cnt = 0xC1; + cnt |= read_enable << 5; + if(bus_id == 0) + REG_I2C_BUS0_CNT = cnt; + else + REG_I2C_BUS1_CNT = cnt; +} + +void i2c_stop_err(u32 dev_id) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + if(bus_id == 0) + REG_I2C_BUS0_CNT = 0xC5; + else + REG_I2C_BUS1_CNT = 0xC5; + i2c_wait(bus_id); + wait(0x200); +} + +bool i2c_start_put_devaddr(u32 dev_id) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + u8 dev_addr = i2c_dev_table[dev_id].devaddr; + i2c_wait(bus_id); + i2c_put_byte(bus_id, dev_addr); + i2c_start(bus_id); + return i2c_test_ack(bus_id); +} + +bool i2c_put_devaddr_set_read(u32 dev_id) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + u8 dev_addr = i2c_dev_table[dev_id].devaddr; + i2c_wait(bus_id); + dev_addr |= 1; // i2c direction: read bit set + i2c_put_byte(bus_id, dev_addr); + i2c_start(bus_id); + return i2c_test_ack(bus_id); +} + +bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + i2c_wait(bus_id); + i2c_put_byte(bus_id, regaddr); + i2c_set_rw(bus_id, 0); // write + return i2c_test_ack(bus_id); +} + +u8 i2c_get_byte(u32 dev_id) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + i2c_wait(bus_id); + i2c_set_rw(bus_id, 1); // read + return i2c_receive_byte(bus_id); +} + +u8 i2c_get_byte_stop(u32 dev_id) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + i2c_wait(bus_id); + i2c_stop(bus_id, 1); // 1=read + return i2c_receive_byte(bus_id); +} + +bool i2c_put_data_stop(u32 dev_id, u8 data) +{ + u32 bus_id = i2c_dev_table[dev_id].bus_id; + i2c_wait(bus_id); + i2c_put_byte(bus_id, data); + i2c_stop(bus_id, 0); // 0=write + return i2c_receive_byte(bus_id); +} + +u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size) +{ + int i; + for(i=0; i<8; i++) // try max. 8 times + { + if(!i2c_start_put_devaddr(dev_id) || + !i2c_put_regaddr_set_write(dev_id, regaddr) || + !i2c_put_devaddr_set_read(dev_id)) + i2c_stop_err(dev_id); + else break; + } + if(i == 8) + return 0; + + while(size != 1) + { + *out = i2c_get_byte(dev_id); + out++; + size--; + } + + // receive the last byte + *out = i2c_get_byte_stop(dev_id); + + return 1; +} + +u32 i2c_writeregdata(u32 dev_id, u32 regaddr, u8 data) +{ + int i; + for(i=0; i<8; i++) // try max. 8 times + { + if(!i2c_start_put_devaddr(dev_id) || + !i2c_put_regaddr_set_write(dev_id, regaddr) || + !i2c_put_data_stop(dev_id, data)) + i2c_stop_err(dev_id); + else break; + } + if(i == 8) + return 0; + return 1; +} + +u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size) +{ + return i2c_readregdata(3, regaddr, outbuf, size); +} + +u32 i2cmcu_readreg0x0_upper(u8 *result) +{ + /*if(i2cmcu_reg0_upper_read) + { + result = i2cmcu_reg0_upper_data; + return 1; + } + else*/ + { + u8 data; + u32 retval = i2cmcu_readregdata(0, &data, 1); + if(retval != 0) + { + data >>= 4; + i2cmcu_reg0_upper_data = data; + *result = data; + } + return retval; + } +} + +u32 i2cmcu_readreg0x0_2bytes(u8 *byte1, u8 *byte2) +{ + u8 data[2]; + if(!i2cmcu_readregdata(0, data, 2)) + return 0; + *byte1 = data[0] & 0xF; + *byte2 = data[1]; + return 1; +} + +u32 i2cmcu_readreg0x0_bus0() +{ + if(!i2cmcu_readreg0x0_bus0_read_flag) + { + i2cmcu_readreg0x0_bus0_read_flag = true; + i2cmcu_readreg0x0_2bytes(&i2cmcu_readreg0x0_bus0_first, &i2cmcu_readreg0x0_bus0_second); + if(i2cmcu_readreg0x0_bus0_first << 0x1C) return 1; + if(i2cmcu_readreg0x0_bus0_second >= 9) return 1; + i2cmcu_readreg0x0_bus0_second = 0; + return 0; + } + return i2cmcu_readreg0x0_bus0_second ? 1 : 0; +} + +u8 i2cmcu_readreg_hid() +{ + u8 data; + if(!i2cmcu_readregdata(0x10, &data, 1)) + return 0; + return data; +} + +// aka i2cmcu_write_reg0x20_0x22 +void i2cmcu_lcd_poweron() +{ + if(i2cmcu_readreg0x0_bus0()) + i2c_writeregdata(3, 0x22, 2); // bit1 = lcd power enable for both screens + else + i2c_writeregdata(3, 0x20, 0x80); +} + +// aka i2cmcu_write_reg0x20_0x22_2 +void i2cmcu_lcd_backlight_poweron() +{ + if(i2cmcu_readreg0x0_bus0()) + i2c_writeregdata(3, 0x22, 0x28); // bit3 = lower screen, bit5 = upper + else + i2c_writeregdata(3, 0x20, 0x20); +} + +void i2cmcu_lcd_poweroff() +{ + i2c_writeregdata(3, 0x22, 1); // bit0 = lcd power disable for both screens (also disabled backlight) +} + +void i2cmcu_lcd_backlight_poweroff() +{ + i2c_writeregdata(3, 0x22, 0x14); // bit2 = backlight disable lower, bit4 = upper +} + +u32 i2c_write_regdata_dev5_dev6(bool dev5, bool dev6, u32 regaddr, u8 data) +{ + u32 result = 1; + if(dev5) + result &= i2c_writeregdata(5, regaddr, data); + if(dev6) + result &= i2c_writeregdata(6, regaddr, data); + return result; +} + +u8 i2c_write_echo_read(u32 dev_id, u32 regaddr, u8 data) +{ + int i; + for(i=0; i<8; i++) // try max. 8 times + { + if(!i2c_start_put_devaddr(dev_id) || + !i2c_put_regaddr_set_write(dev_id, regaddr) || + !i2c_put_data_stop(dev_id, data) || + !i2c_put_devaddr_set_read(dev_id) || + (i2c_get_byte(dev_id) != data)) + i2c_stop_err(dev_id); + else break; + } + if(i == 8) + return 0xFF; + return i2c_get_byte_stop(dev_id);; +} diff --git a/source/arm11/i2c.thumb.c b/source/arm11/i2c.thumb.c deleted file mode 100644 index 365c3f6..0000000 --- a/source/arm11/i2c.thumb.c +++ /dev/null @@ -1,344 +0,0 @@ -#include "types.h" -#include "IO.h" -#include "mem_map.h" -#include "util.h" - - - -struct i2c_dev_table_entry { - u32 bus_id; - u8 devaddr; -}; - -static const struct i2c_dev_table_entry i2c_dev_table[] = -{ - {0, 0x4A}, - {0, 0x7A}, - {0, 0x78}, - {1, 0x4A}, - {1, 0x78}, - {1, 0x2C}, - {1, 0x2E}, - {1, 0x40}, - {1, 0x44} -}; - - -// i2c mcu defines -bool i2cmcu_reg0_upper_read; -u8 i2cmcu_reg0_upper_data; -bool i2cmcu_readreg0x0_bus0_read_flag; -u8 i2cmcu_readreg0x0_bus0_first; -u8 i2cmcu_readreg0x0_bus0_second; - - -void i2c_wait(u32 bus_id); -void i2c_put_byte(u32 bus_id, u8 data_byte); -void i2c_start(u32 bus_id); -void i2c_set_rw(u32 bus_id, u32 read_enable); -bool i2c_test_ack(u32 bus_id); -u8 i2c_receive_byte(u32 bus_id); -void i2c_stop(u32 bus_id, u32 read_enable); -void i2c_stop_err(u32 dev_id); -bool i2c_start_put_devaddr(u32 dev_id); -bool i2c_put_devaddr_set_read(u32 dev_id); -bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr); -u8 i2c_get_byte(u32 dev_id); -u8 i2c_get_byte_stop(u32 dev_id); -u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size); -u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size); - - -void i2c_wait(u32 bus_id) -{ - u8 result; - do { - if(bus_id == 0) - result = REG_I2C_BUS0_CNT; - else - result = REG_I2C_BUS1_CNT; - } while((result>>7) & 1); -} - -void i2c_put_byte(u32 bus_id, u8 data_byte) -{ - if(bus_id == 0) - REG_I2C_BUS0_DATA = data_byte; - else - REG_I2C_BUS1_DATA = data_byte; -} - -void i2c_start(u32 bus_id) -{ - wait(0x100); - if(bus_id == 0) - REG_I2C_BUS0_CNT = 0xC2; - else - REG_I2C_BUS1_CNT = 0xC2; -} - -void i2c_set_rw(u32 bus_id, u32 read_enable) -{ - u8 cnt = 0xC0; - cnt |= read_enable << 5; - cnt |= read_enable << 4; - if(bus_id == 0) - REG_I2C_BUS0_CNT = cnt; - else - REG_I2C_BUS1_CNT = cnt; -} - -bool i2c_test_ack(u32 bus_id) -{ - i2c_wait(bus_id); - wait(0x80); - u8 result; - if(bus_id == 0) - result = REG_I2C_BUS0_CNT; - else - result = REG_I2C_BUS1_CNT; - return ((result << 0x1B) >> 0x1F); // return Ack Flag -} - -u8 i2c_receive_byte(u32 bus_id) -{ - i2c_wait(bus_id); - wait(0x100); - if(bus_id == 0) - return REG_I2C_BUS0_DATA; - else - return REG_I2C_BUS1_DATA; -} - -void i2c_stop(u32 bus_id, u32 read_enable) -{ - u8 cnt = 0xC1; - cnt |= read_enable << 5; - if(bus_id == 0) - REG_I2C_BUS0_CNT = cnt; - else - REG_I2C_BUS1_CNT = cnt; -} - -void i2c_stop_err(u32 dev_id) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - if(bus_id == 0) - REG_I2C_BUS0_CNT = 0xC5; - else - REG_I2C_BUS1_CNT = 0xC5; - i2c_wait(bus_id); - wait(0x200); -} - -bool i2c_start_put_devaddr(u32 dev_id) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - u8 dev_addr = i2c_dev_table[dev_id].devaddr; - i2c_wait(bus_id); - i2c_put_byte(bus_id, dev_addr); - i2c_start(bus_id); - return i2c_test_ack(bus_id); -} - -bool i2c_put_devaddr_set_read(u32 dev_id) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - u8 dev_addr = i2c_dev_table[dev_id].devaddr; - i2c_wait(bus_id); - dev_addr |= 1; // i2c direction: read bit set - i2c_put_byte(bus_id, dev_addr); - i2c_start(bus_id); - return i2c_test_ack(bus_id); -} - -bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - i2c_wait(bus_id); - i2c_put_byte(bus_id, regaddr); - i2c_set_rw(bus_id, 0); // write - return i2c_test_ack(bus_id); -} - -u8 i2c_get_byte(u32 dev_id) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - i2c_wait(bus_id); - i2c_set_rw(bus_id, 1); // read - return i2c_receive_byte(bus_id); -} - -u8 i2c_get_byte_stop(u32 dev_id) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - i2c_wait(bus_id); - i2c_stop(bus_id, 1); // 1=read - return i2c_receive_byte(bus_id); -} - -bool i2c_put_data_stop(u32 dev_id, u8 data) -{ - u32 bus_id = i2c_dev_table[dev_id].bus_id; - i2c_wait(bus_id); - i2c_put_byte(bus_id, data); - i2c_stop(bus_id, 0); // 0=write - return i2c_receive_byte(bus_id); -} - -u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size) -{ - int i; - for(i=0; i<8; i++) // try max. 8 times - { - if(!i2c_start_put_devaddr(dev_id) || - !i2c_put_regaddr_set_write(dev_id, regaddr) || - !i2c_put_devaddr_set_read(dev_id)) - i2c_stop_err(dev_id); - else break; - } - if(i == 8) - return 0; - - while(size != 1) - { - *out = i2c_get_byte(dev_id); - out++; - size--; - } - - // receive the last byte - *out = i2c_get_byte_stop(dev_id); - - return 1; -} - -u32 i2c_writeregdata(u32 dev_id, u32 regaddr, u8 data) -{ - int i; - for(i=0; i<8; i++) // try max. 8 times - { - if(!i2c_start_put_devaddr(dev_id) || - !i2c_put_regaddr_set_write(dev_id, regaddr) || - !i2c_put_data_stop(dev_id, data)) - i2c_stop_err(dev_id); - else break; - } - if(i == 8) - return 0; - return 1; -} - -u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size) -{ - return i2c_readregdata(3, regaddr, outbuf, size); -} - -u32 i2cmcu_readreg0x0_upper(u8 *result) -{ - /*if(i2cmcu_reg0_upper_read) - { - result = i2cmcu_reg0_upper_data; - return 1; - } - else*/ - { - u8 data; - u32 retval = i2cmcu_readregdata(0, &data, 1); - if(retval != 0) - { - data >>= 4; - i2cmcu_reg0_upper_data = data; - *result = data; - } - return retval; - } -} - -u32 i2cmcu_readreg0x0_2bytes(u8 *byte1, u8 *byte2) -{ - u8 data[2]; - if(!i2cmcu_readregdata(0, data, 2)) - return 0; - *byte1 = data[0] & 0xF; - *byte2 = data[1]; - return 1; -} - -u32 i2cmcu_readreg0x0_bus0() -{ - if(!i2cmcu_readreg0x0_bus0_read_flag) - { - i2cmcu_readreg0x0_bus0_read_flag = true; - i2cmcu_readreg0x0_2bytes(&i2cmcu_readreg0x0_bus0_first, &i2cmcu_readreg0x0_bus0_second); - if(i2cmcu_readreg0x0_bus0_first << 0x1C) return 1; - if(i2cmcu_readreg0x0_bus0_second >= 9) return 1; - i2cmcu_readreg0x0_bus0_second = 0; - return 0; - } - return i2cmcu_readreg0x0_bus0_second ? 1 : 0; -} - -u8 i2cmcu_readreg_hid() -{ - u8 data; - if(!i2cmcu_readregdata(0x10, &data, 1)) - return 0; - return data; -} - -// aka i2cmcu_write_reg0x20_0x22 -void i2cmcu_lcd_poweron() -{ - if(i2cmcu_readreg0x0_bus0()) - i2c_writeregdata(3, 0x22, 2); // bit1 = lcd power enable for both screens - else - i2c_writeregdata(3, 0x20, 0x80); -} - -// aka i2cmcu_write_reg0x20_0x22_2 -void i2cmcu_lcd_backlight_poweron() -{ - if(i2cmcu_readreg0x0_bus0()) - i2c_writeregdata(3, 0x22, 0x28); // bit3 = lower screen, bit5 = upper - else - i2c_writeregdata(3, 0x20, 0x20); -} - -void i2cmcu_lcd_poweroff() -{ - i2c_writeregdata(3, 0x22, 1); // bit0 = lcd power disable for both screens (also disabled backlight) -} - -void i2cmcu_lcd_backlight_poweroff() -{ - i2c_writeregdata(3, 0x22, 0x14); // bit2 = backlight disable lower, bit4 = upper -} - -u32 i2c_write_regdata_dev5_dev6(bool dev5, bool dev6, u32 regaddr, u8 data) -{ - u32 result = 1; - if(dev5) - result &= i2c_writeregdata(5, regaddr, data); - if(dev6) - result &= i2c_writeregdata(6, regaddr, data); - return result; -} - -u8 i2c_write_echo_read(u32 dev_id, u32 regaddr, u8 data) -{ - int i; - for(i=0; i<8; i++) // try max. 8 times - { - if(!i2c_start_put_devaddr(dev_id) || - !i2c_put_regaddr_set_write(dev_id, regaddr) || - !i2c_put_data_stop(dev_id, data) || - !i2c_put_devaddr_set_read(dev_id) || - (i2c_get_byte(dev_id) != data)) - i2c_stop_err(dev_id); - else break; - } - if(i == 8) - return 0xFF; - return i2c_get_byte_stop(dev_id);; -} diff --git a/source/arm11/pxi.c b/source/arm11/pxi.c new file mode 100644 index 0000000..2b4c2cd --- /dev/null +++ b/source/arm11/pxi.c @@ -0,0 +1,48 @@ +#include "types.h" +#include "pxi.h" +//#include "interrupt.h" + + + +void PXI_init(void) +{ + REG_PXI_SYNC11 = 0; + REG_PXI_CNT11 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; + + while((REG_PXI_SYNC11 & 0xFFu) != 9u); + REG_PXI_SYNC11 |= 11u<<8; +} + +void PXI_sendWord(u32 val) +{ + while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); + REG_PXI_SEND11 = val; + REG_PXI_SYNC11 |= PXI_NOTIFY_9; +} + +bool PXI_trySendWord(u32 val) +{ + if(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL) + return false; + REG_PXI_SEND11 = val; + REG_PXI_SYNC11 |= PXI_NOTIFY_9; + return true; +} + +u32 PXI_recvWord(void) +{ + while(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY); + return REG_PXI_RECV11; +} + +u32 PXI_tryRecvWord(bool *success) +{ + if(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY) + { + *success = false; + return 0; + } + + *success = true; + return REG_PXI_RECV11; +} diff --git a/source/arm11/pxi.thumb.c b/source/arm11/pxi.thumb.c deleted file mode 100644 index 2b4c2cd..0000000 --- a/source/arm11/pxi.thumb.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "types.h" -#include "pxi.h" -//#include "interrupt.h" - - - -void PXI_init(void) -{ - REG_PXI_SYNC11 = 0; - REG_PXI_CNT11 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; - - while((REG_PXI_SYNC11 & 0xFFu) != 9u); - REG_PXI_SYNC11 |= 11u<<8; -} - -void PXI_sendWord(u32 val) -{ - while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); - REG_PXI_SEND11 = val; - REG_PXI_SYNC11 |= PXI_NOTIFY_9; -} - -bool PXI_trySendWord(u32 val) -{ - if(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL) - return false; - REG_PXI_SEND11 = val; - REG_PXI_SYNC11 |= PXI_NOTIFY_9; - return true; -} - -u32 PXI_recvWord(void) -{ - while(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY); - return REG_PXI_RECV11; -} - -u32 PXI_tryRecvWord(bool *success) -{ - if(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY) - { - *success = false; - return 0; - } - - *success = true; - return REG_PXI_RECV11; -} diff --git a/source/arm9/filebrowse.c b/source/arm9/filebrowse.c new file mode 100644 index 0000000..74f9e11 --- /dev/null +++ b/source/arm9/filebrowse.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include "types.h" +#include "mem_map.h" +#include "arm9/fatfs/ff.h" +#include "arm9/console.h" +#include "arm9/main.h" +#include "arm9/menu.h" +#include "arm9/interrupt.h" +#include "util.h" +#include "hid.h" + +#define MAX_CACHED_ENTRIES 0x400 +#define MAX_ENTRY_SIZE _MAX_LFN + 2 +#define MAX_NEW_ENTRIES 0x20 +#define MAX_PATH_LENGTH 0x400 +#define MAX_PATH_DEPTH 0x20 + +typedef struct { + char name[MAX_ENTRY_SIZE]; + bool isDir; +} EntryType; + +static EntryType *dirEntries; // [MAX_ENTRY_SIZE][MAX_CACHED_ENTRIES]; +static DIR curDirectory; +static char curPath[MAX_PATH_LENGTH]; +static u32 curEntriesCount; + +// This stack is used to recover the original cursor position +// in the dir entries list when returning from a subdir. +static u32 indexStack[MAX_PATH_DEPTH]; +static u32 *indexStackPtr = indexStack; + +/* This scans the current directory for entries. + Only MAX_NEW_ENTRIES will be added at maximum. + This also updates the curEntriesCount. + Returns true if new entries were added. */ +static bool scanDirectory() +{ + FRESULT res; + static FILINFO fno; + unsigned i = 0; + + for(i=0; i bufSize - 1) + { + end = in + entryLen; + strcpy(&out[3], end - bufSize + 3); + memcpy(out, "...", 3); + } + else strcpy(out, in); + } + else + { + if(entryLen > bufSize - 1) + { + memcpy(out, in, bufSize - 4); + memcpy(&out[bufSize - 5], "...", 4); + } + else strcpy(out, in); + } +} + +static void updateCursor(int cursor_pos, int old_cursor_pos, int maxEntries) +{ + // clear old '*' char + consoleSetCursor(&con_bottom, 0, (old_cursor_pos % (maxEntries)) + 1); + printf(" "); + + consoleSetCursor(&con_bottom, 0, (cursor_pos % (maxEntries)) + 1); + printf("*"); +} + +static void updateScreen(int cursor_pos, bool dirChange) +{ + // we don't want ugly line breaks in our list + const int maxLen = con_bottom.windowWidth - 1; + const int maxEntries = con_bottom.windowHeight - 1; + + static int old_cursor_pos; + + consoleSelect(&con_bottom); + + if(!dirChange && (cursor_pos < maxEntries) && (old_cursor_pos < maxEntries)) + { + updateCursor(cursor_pos, old_cursor_pos, maxEntries); + old_cursor_pos = cursor_pos; + return; + } + + old_cursor_pos = cursor_pos; + + char entry [maxLen]; // should be safe + unsigned start, end; + + consoleClear(); + + // print the current path in the first line + formatEntry(entry, curPath, (u32) maxLen - 3, false); + printf("%s :", entry); + + if(cursor_pos < (u32) maxEntries) + { + start = 0; + end = min(maxEntries, curEntriesCount); + } + else + { + start = cursor_pos - maxEntries + 1; + end = min(cursor_pos + 1, curEntriesCount); + } + + for(unsigned i = start; i < end; i++) + { + formatEntry(entry, dirEntries[i].name, (u32) maxLen - 2, true); + printf("\n%s %s", i == (unsigned) cursor_pos ? "*" : " ", entry); + } +} + +const char *browseForFile(const char *basePath) +{ + FRESULT res; + u32 keys; + u32 cursor_pos = 0; + bool fileSelected = false; + + curEntriesCount = 0; + indexStackPtr = indexStack; + + dirEntries = (EntryType *) malloc(MAX_CACHED_ENTRIES); + if(!dirEntries) + { + menuSetReturnToState(STATE_PREVIOUS); + menuUpdateGlobalState(); + menuActState(); + return NULL; + } + + if(basePath) + strncpy_s(curPath, basePath, sizeof(curPath) - 1, sizeof(curPath)); + else + strncpy_s(curPath, "sdmc:", sizeof(curPath) - 1, sizeof(curPath)); + + res = f_opendir(&curDirectory, curPath); + if (res != FR_OK) + { + free(dirEntries); + menuSetReturnToState(STATE_PREVIOUS); + menuUpdateGlobalState(); + menuActState(); + return NULL; + } + + // do an initial scan + scanDirectory(); + + updateScreen((int)cursor_pos, true); + + for(;;) + { + hidScanInput(); + keys = hidKeysDown()/* | hidKeysHeld()*/; + + if(curEntriesCount != 0) + { + if(keys & KEY_DUP || keys & KEY_DLEFT) + { + if(cursor_pos != 0) + { + cursor_pos -= keys & KEY_DLEFT ? min(cursor_pos, 8) : 1; + updateScreen((int)cursor_pos, false); + } + } + + else if(keys & KEY_DDOWN || keys & KEY_DRIGHT) + { + // we reached the end of our entries list? + u32 old_pos = cursor_pos; + cursor_pos += keys & KEY_DRIGHT ? 8 : 1; + if(cursor_pos >= curEntriesCount) + { + scanDirectory(); + // we got more entries? + if(curEntriesCount > cursor_pos) + cursor_pos = min(cursor_pos, curEntriesCount - 1); + else + cursor_pos = curEntriesCount - 1; + if(cursor_pos != old_pos) + updateScreen((int)cursor_pos, false); + } + else + { + updateScreen((int)cursor_pos, false); + } + } + + else if(keys & KEY_A) // select entry + { + if(dirEntries[cursor_pos].isDir) // it's a dir + { + if(descendPath(cursor_pos, dirEntries[cursor_pos].name)) + { + f_closedir(&curDirectory); + res = f_opendir(&curDirectory, curPath); + if (res != FR_OK) + ascendPath(); + else + { + // fetch new entries + curEntriesCount = 0; + scanDirectory(); + cursor_pos = 0; + updateScreen((int)cursor_pos, true); + } + } + } + else // we got our file! + { + if(strlen(dirEntries[cursor_pos].name) + strlen(curPath) + 2 > sizeof(curPath)) + goto fail; // TODO? Path too long. + strcat(curPath, "\\"); + strcat(curPath, dirEntries[cursor_pos].name); + fileSelected = true; + menuSetReturnToState(STATE_PREVIOUS); + } + } + } + if(keys & KEY_B) // go back + { + if(indexStackPtr != indexStack) + { + cursor_pos = ascendPath(); + f_closedir(&curDirectory); + + res = f_opendir(&curDirectory, curPath); + if (res != FR_OK) + goto fail; + curEntriesCount = 0; + + do { + if(!scanDirectory()) + goto fail; + } while(curEntriesCount <= cursor_pos); + + updateScreen((int)cursor_pos, true); + } + else + menuSetReturnToState(STATE_PREVIOUS); + } + + switch(menuUpdateGlobalState()) + { + case MENU_EVENT_HOME_PRESSED: + case MENU_EVENT_POWER_PRESSED: + case MENU_EVENT_SD_CARD_REMOVED: + goto fail; + case MENU_EVENT_STATE_CHANGE: + if(!fileSelected) goto fail; + else goto done; + default: + break; + } + + menuActState(); + + } + +done: + + f_closedir(&curDirectory); + free(dirEntries); + + menuActState(); + + return curPath; + +fail: + + f_closedir(&curDirectory); + free(dirEntries); + + menuActState(); + + return NULL; +} diff --git a/source/arm9/filebrowse.thumb.c b/source/arm9/filebrowse.thumb.c deleted file mode 100644 index 74f9e11..0000000 --- a/source/arm9/filebrowse.thumb.c +++ /dev/null @@ -1,337 +0,0 @@ -#include -#include -#include -#include "types.h" -#include "mem_map.h" -#include "arm9/fatfs/ff.h" -#include "arm9/console.h" -#include "arm9/main.h" -#include "arm9/menu.h" -#include "arm9/interrupt.h" -#include "util.h" -#include "hid.h" - -#define MAX_CACHED_ENTRIES 0x400 -#define MAX_ENTRY_SIZE _MAX_LFN + 2 -#define MAX_NEW_ENTRIES 0x20 -#define MAX_PATH_LENGTH 0x400 -#define MAX_PATH_DEPTH 0x20 - -typedef struct { - char name[MAX_ENTRY_SIZE]; - bool isDir; -} EntryType; - -static EntryType *dirEntries; // [MAX_ENTRY_SIZE][MAX_CACHED_ENTRIES]; -static DIR curDirectory; -static char curPath[MAX_PATH_LENGTH]; -static u32 curEntriesCount; - -// This stack is used to recover the original cursor position -// in the dir entries list when returning from a subdir. -static u32 indexStack[MAX_PATH_DEPTH]; -static u32 *indexStackPtr = indexStack; - -/* This scans the current directory for entries. - Only MAX_NEW_ENTRIES will be added at maximum. - This also updates the curEntriesCount. - Returns true if new entries were added. */ -static bool scanDirectory() -{ - FRESULT res; - static FILINFO fno; - unsigned i = 0; - - for(i=0; i bufSize - 1) - { - end = in + entryLen; - strcpy(&out[3], end - bufSize + 3); - memcpy(out, "...", 3); - } - else strcpy(out, in); - } - else - { - if(entryLen > bufSize - 1) - { - memcpy(out, in, bufSize - 4); - memcpy(&out[bufSize - 5], "...", 4); - } - else strcpy(out, in); - } -} - -static void updateCursor(int cursor_pos, int old_cursor_pos, int maxEntries) -{ - // clear old '*' char - consoleSetCursor(&con_bottom, 0, (old_cursor_pos % (maxEntries)) + 1); - printf(" "); - - consoleSetCursor(&con_bottom, 0, (cursor_pos % (maxEntries)) + 1); - printf("*"); -} - -static void updateScreen(int cursor_pos, bool dirChange) -{ - // we don't want ugly line breaks in our list - const int maxLen = con_bottom.windowWidth - 1; - const int maxEntries = con_bottom.windowHeight - 1; - - static int old_cursor_pos; - - consoleSelect(&con_bottom); - - if(!dirChange && (cursor_pos < maxEntries) && (old_cursor_pos < maxEntries)) - { - updateCursor(cursor_pos, old_cursor_pos, maxEntries); - old_cursor_pos = cursor_pos; - return; - } - - old_cursor_pos = cursor_pos; - - char entry [maxLen]; // should be safe - unsigned start, end; - - consoleClear(); - - // print the current path in the first line - formatEntry(entry, curPath, (u32) maxLen - 3, false); - printf("%s :", entry); - - if(cursor_pos < (u32) maxEntries) - { - start = 0; - end = min(maxEntries, curEntriesCount); - } - else - { - start = cursor_pos - maxEntries + 1; - end = min(cursor_pos + 1, curEntriesCount); - } - - for(unsigned i = start; i < end; i++) - { - formatEntry(entry, dirEntries[i].name, (u32) maxLen - 2, true); - printf("\n%s %s", i == (unsigned) cursor_pos ? "*" : " ", entry); - } -} - -const char *browseForFile(const char *basePath) -{ - FRESULT res; - u32 keys; - u32 cursor_pos = 0; - bool fileSelected = false; - - curEntriesCount = 0; - indexStackPtr = indexStack; - - dirEntries = (EntryType *) malloc(MAX_CACHED_ENTRIES); - if(!dirEntries) - { - menuSetReturnToState(STATE_PREVIOUS); - menuUpdateGlobalState(); - menuActState(); - return NULL; - } - - if(basePath) - strncpy_s(curPath, basePath, sizeof(curPath) - 1, sizeof(curPath)); - else - strncpy_s(curPath, "sdmc:", sizeof(curPath) - 1, sizeof(curPath)); - - res = f_opendir(&curDirectory, curPath); - if (res != FR_OK) - { - free(dirEntries); - menuSetReturnToState(STATE_PREVIOUS); - menuUpdateGlobalState(); - menuActState(); - return NULL; - } - - // do an initial scan - scanDirectory(); - - updateScreen((int)cursor_pos, true); - - for(;;) - { - hidScanInput(); - keys = hidKeysDown()/* | hidKeysHeld()*/; - - if(curEntriesCount != 0) - { - if(keys & KEY_DUP || keys & KEY_DLEFT) - { - if(cursor_pos != 0) - { - cursor_pos -= keys & KEY_DLEFT ? min(cursor_pos, 8) : 1; - updateScreen((int)cursor_pos, false); - } - } - - else if(keys & KEY_DDOWN || keys & KEY_DRIGHT) - { - // we reached the end of our entries list? - u32 old_pos = cursor_pos; - cursor_pos += keys & KEY_DRIGHT ? 8 : 1; - if(cursor_pos >= curEntriesCount) - { - scanDirectory(); - // we got more entries? - if(curEntriesCount > cursor_pos) - cursor_pos = min(cursor_pos, curEntriesCount - 1); - else - cursor_pos = curEntriesCount - 1; - if(cursor_pos != old_pos) - updateScreen((int)cursor_pos, false); - } - else - { - updateScreen((int)cursor_pos, false); - } - } - - else if(keys & KEY_A) // select entry - { - if(dirEntries[cursor_pos].isDir) // it's a dir - { - if(descendPath(cursor_pos, dirEntries[cursor_pos].name)) - { - f_closedir(&curDirectory); - res = f_opendir(&curDirectory, curPath); - if (res != FR_OK) - ascendPath(); - else - { - // fetch new entries - curEntriesCount = 0; - scanDirectory(); - cursor_pos = 0; - updateScreen((int)cursor_pos, true); - } - } - } - else // we got our file! - { - if(strlen(dirEntries[cursor_pos].name) + strlen(curPath) + 2 > sizeof(curPath)) - goto fail; // TODO? Path too long. - strcat(curPath, "\\"); - strcat(curPath, dirEntries[cursor_pos].name); - fileSelected = true; - menuSetReturnToState(STATE_PREVIOUS); - } - } - } - if(keys & KEY_B) // go back - { - if(indexStackPtr != indexStack) - { - cursor_pos = ascendPath(); - f_closedir(&curDirectory); - - res = f_opendir(&curDirectory, curPath); - if (res != FR_OK) - goto fail; - curEntriesCount = 0; - - do { - if(!scanDirectory()) - goto fail; - } while(curEntriesCount <= cursor_pos); - - updateScreen((int)cursor_pos, true); - } - else - menuSetReturnToState(STATE_PREVIOUS); - } - - switch(menuUpdateGlobalState()) - { - case MENU_EVENT_HOME_PRESSED: - case MENU_EVENT_POWER_PRESSED: - case MENU_EVENT_SD_CARD_REMOVED: - goto fail; - case MENU_EVENT_STATE_CHANGE: - if(!fileSelected) goto fail; - else goto done; - default: - break; - } - - menuActState(); - - } - -done: - - f_closedir(&curDirectory); - free(dirEntries); - - menuActState(); - - return curPath; - -fail: - - f_closedir(&curDirectory); - free(dirEntries); - - menuActState(); - - return NULL; -} diff --git a/source/arm9/loader_init.c b/source/arm9/loader_init.c new file mode 100644 index 0000000..058b34f --- /dev/null +++ b/source/arm9/loader_init.c @@ -0,0 +1,16 @@ +#include "types.h" +#include "arm9/interrupt.h" +#include "arm9/ndma.h" +#include "arm9/timer.h" +#include "pxi.h" + + + +void hardwareInit(void) +{ + // Atomic IRQ disable and aknowledge + __asm__("stmia %0, {%1, %2}" : : "r" (®_IRQ_IE), "r" (0u), "r" (0xFFFFFFFFu) : "memory"); + NDMA_init(); + TIMER_init(); + PXI_init(); +} diff --git a/source/arm9/loader_init.thumb.c b/source/arm9/loader_init.thumb.c deleted file mode 100644 index 058b34f..0000000 --- a/source/arm9/loader_init.thumb.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "types.h" -#include "arm9/interrupt.h" -#include "arm9/ndma.h" -#include "arm9/timer.h" -#include "pxi.h" - - - -void hardwareInit(void) -{ - // Atomic IRQ disable and aknowledge - __asm__("stmia %0, {%1, %2}" : : "r" (®_IRQ_IE), "r" (0u), "r" (0xFFFFFFFFu) : "memory"); - NDMA_init(); - TIMER_init(); - PXI_init(); -} diff --git a/source/arm9/pxi.c b/source/arm9/pxi.c new file mode 100644 index 0000000..b47c087 --- /dev/null +++ b/source/arm9/pxi.c @@ -0,0 +1,48 @@ +#include "types.h" +#include "pxi.h" +#include "arm9/interrupt.h" + + + +void PXI_init(void) +{ + REG_PXI_SYNC9 = PXI_IRQ_ENABLE; + REG_PXI_CNT9 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; + + REG_PXI_SYNC9 |= 9u<<8; + while((REG_PXI_SYNC9 & 0xFFu) != 11u); +} + +void PXI_sendWord(u32 val) +{ + while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); + REG_PXI_SEND9 = val; + REG_PXI_SYNC9 |= PXI_NOTIFY_11; +} + +bool PXI_trySendWord(u32 val) +{ + if(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL) + return false; + REG_PXI_SEND9 = val; + REG_PXI_SYNC9 |= PXI_NOTIFY_11; + return true; +} + +u32 PXI_recvWord(void) +{ + while(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY); + return REG_PXI_RECV9; +} + +u32 PXI_tryRecvWord(bool *success) +{ + if(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY) + { + *success = false; + return 0; + } + + *success = true; + return REG_PXI_RECV9; +} diff --git a/source/arm9/pxi.thumb.c b/source/arm9/pxi.thumb.c deleted file mode 100644 index b47c087..0000000 --- a/source/arm9/pxi.thumb.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "types.h" -#include "pxi.h" -#include "arm9/interrupt.h" - - - -void PXI_init(void) -{ - REG_PXI_SYNC9 = PXI_IRQ_ENABLE; - REG_PXI_CNT9 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; - - REG_PXI_SYNC9 |= 9u<<8; - while((REG_PXI_SYNC9 & 0xFFu) != 11u); -} - -void PXI_sendWord(u32 val) -{ - while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); - REG_PXI_SEND9 = val; - REG_PXI_SYNC9 |= PXI_NOTIFY_11; -} - -bool PXI_trySendWord(u32 val) -{ - if(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL) - return false; - REG_PXI_SEND9 = val; - REG_PXI_SYNC9 |= PXI_NOTIFY_11; - return true; -} - -u32 PXI_recvWord(void) -{ - while(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY); - return REG_PXI_RECV9; -} - -u32 PXI_tryRecvWord(bool *success) -{ - if(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY) - { - *success = false; - return 0; - } - - *success = true; - return REG_PXI_RECV9; -} diff --git a/source/arm9/spiflash.c b/source/arm9/spiflash.c new file mode 100644 index 0000000..44af94c --- /dev/null +++ b/source/arm9/spiflash.c @@ -0,0 +1,67 @@ +#include "types.h" +#include "io.h" +#include "arm9/spiflash.h" + + + +void spi_busy_wait() +{ + while(REG_SPI_BUS2_CNT & 0x80); +} + +void spi_put_byte(u8 data) +{ + REG_SPI_BUS2_DATA = data; + spi_busy_wait(); +} + +u8 spi_receive_byte() +{ + // clock out a dummy byte + REG_SPI_BUS2_DATA = 0x00; + spi_busy_wait(); + return REG_SPI_BUS2_DATA; +} + +// select spiflash if select=true, deselect otherwise +void spiflash_select(bool select) +{ + // select device 1, enable SPI bus + REG_SPI_BUS2_CNT = 0x8100 | (select << 11); +} + +bool spiflash_get_status() +{ + u8 resp; + + spi_busy_wait(); + spiflash_select(1); + spi_put_byte(SPIFLASH_CMD_RDSR); + spiflash_select(0); + resp = spi_receive_byte(); + + if(resp & 1) return false; + return true; +} + +void spiflash_read(u32 offset, u32 size, u8 *buf) +{ + spi_busy_wait(); + spiflash_select(1); + spi_put_byte(SPIFLASH_CMD_READ); + + // write addr (24-bit, msb first) + for(int i=0; i<3; i++) + { + offset <<= 8; + spi_put_byte((offset >> 24) & 0xFF); + } + + // read bytes + for(u32 i=0; i> 24) & 0xFF); - } - - // read bytes - for(u32 i=0; i