/****************************************/ /* MES/Copyleft Yukio Mituiwa,2005 */ /* */ /* 2006/6/16 first release */ /* */ /****************************************/ #include #include #include #ifdef _KERNEL_ #include "mes.h" #include "conf.h" #define device_main(arg1,arg2) init_mmc(void) extern PIOConf mmc_config[]; #endif #if defined(__H8300H__) #define SCIREGINC 8 #endif #if defined(__sh__) #define SCIREGINC 16 #endif #if defined(__sh3__) asm( " .text" "\n\t" "_mmc_sci0_read:" "\n\t" " mov.l SCR0_k,r3" "\n\t" "_mmc_sci_read:" "\n\t" " mov r5,r0" "\n\t" " mov.b r0,@(2,r3)" "\n\t" " mov #0x10,r0" "\n\t" " mov.b r0,@(4,r3)" "\n\t" " mov.l SECSIZ,r2" "\n\t" "_mmc_sci_read_L0:" "\n\t" " mov.b @(8,r3),r0" "\n\t" " tst #0x40,r0" "\n\t" " bt _mmc_sci_read_L0" "\n\t" " mov.b @(10,r3),r0" "\n\t" " mov.b r0,@r4" "\n\t" " add #1,r4" "\n\t" " mov.b @(8,r3),r0" "\n\t" " mov #0,r0" "\n\t" " mov.b r0,@(8,r3)" "\n\t" " dt r2" "\n\t" " bf _mmc_sci_read_L0" "\n\t" " rts" "\n\t" " nop" "\n\t" "_mmc_sci0_write:" "\n\t" " mov.l SCR0_k,r3" "\n\t" "_mmc_sci_write:" "\n\t" " mov r5,r0" "\n\t" " mov.b r0,@(2,r3)" "\n\t" " mov #0x20,r0" "\n\t" " mov.b r0,@(4,r3)" "\n\t" " mov.l SECSIZ,r2" "\n\t" "_mmc_sci_write_L0:" "\n\t" " mov.b @(8,r3),r0" "\n\t" " tst #0x80,r0" "\n\t" " bt _mmc_sci_write_L0" "\n\t" " mov.b @r4,r0" "\n\t" " mov.b r0,@(6,r3)" "\n\t" " add #1,r4" "\n\t" " mov.b @(8,r3),r0" "\n\t" " mov #0,r0" "\n\t" " mov.b r0,@(8,r3)" "\n\t" " dt r2" "\n\t" " bf _mmc_sci_write_L0" "\n\t" " rts" "\n\t" " nop" "\n\t" " .align 4" "\n\t" "SCR0_k:" "\n\t" " .long 0xfffffe80" "\n\t" "SECSIZ:" "\n\t" " .long 512" "\n\t" ); #endif #if defined(__sh2__) asm( " .text" "\n\t" "_mmc_sci0_read:" "\n\t" " mov.l SCR0_k,r3" "\n\t" " bra _mmc_sci_read" "\n\t" " nop" "\n\t" "_mmc_sci1_read:" "\n\t" " mov.l SCR1_k,r3" "\n\t" " bra _mmc_sci_read" "\n\t" " nop" "\n\t" "_mmc_sci2_read:" "\n\t" " mov.l SCR2_k,r3" "\n\t" " bra _mmc_sci_read" "\n\t" " nop" "\n\t" "_mmc_sci3_read:" "\n\t" " mov.l SCR3_k,r3" "\n\t" " bra _mmc_sci_read" "\n\t" " nop" "\n\t" "_mmc_sci_read:" "\n\t" " mov r5,r0" "\n\t" " mov.b r0,@(1,r3)" "\n\t" " mov #0x10,r0" "\n\t" " mov.b r0,@(2,r3)" "\n\t" " mov.l SECSIZ,r2" "\n\t" "_mmc_sci_read_L0:" "\n\t" " mov.b @(4,r3),r0" "\n\t" " tst #0x40,r0" "\n\t" " bt _mmc_sci_read_L0" "\n\t" " mov.b @(5,r3),r0" "\n\t" " mov.b r0,@r4" "\n\t" " add #1,r4" "\n\t" " mov.b @(4,r3),r0" "\n\t" " mov #0,r0" "\n\t" " mov.b r0,@(4,r3)" "\n\t" " dt r2" "\n\t" " bf _mmc_sci_read_L0" "\n\t" " rts" "\n\t" " nop" "\n\t" "_mmc_sci0_write:" "\n\t" " mov.l SCR0_k,r3" "\n\t" " bra _mmc_sci_write" "\n\t" " nop" "\n\t" "_mmc_sci1_write:" "\n\t" " mov.l SCR1_k,r3" "\n\t" " bra _mmc_sci_write" "\n\t" " nop" "\n\t" "_mmc_sci2_write:" "\n\t" " mov.l SCR2_k,r3" "\n\t" " bra _mmc_sci_write" "\n\t" " nop" "\n\t" "_mmc_sci3_write:" "\n\t" " mov.l SCR3_k,r3" "\n\t" " bra _mmc_sci_write" "\n\t" " nop" "\n\t" "_mmc_sci_write:" "\n\t" " mov r5,r0" "\n\t" " mov.b r0,@(1,r3)" "\n\t" " mov #0x20,r0" "\n\t" " mov.b r0,@(2,r3)" "\n\t" " mov.l SECSIZ,r2" "\n\t" "_mmc_sci_write_L0:" "\n\t" " mov.b @(4,r3),r0" "\n\t" " tst #0x80,r0" "\n\t" " bt _mmc_sci_write_L0" "\n\t" " mov.b @r4,r0" "\n\t" " mov.b r0,@(3,r3)" "\n\t" " add #1,r4" "\n\t" " mov.b @(4,r3),r0" "\n\t" " mov #0,r0" "\n\t" " mov.b r0,@(4,r3)" "\n\t" " dt r2" "\n\t" " bf _mmc_sci_write_L0" "\n\t" " rts" "\n\t" " nop" "\n\t" " .align 4" "\n\t" "SCR0_k:" "\n\t" " .long 0xffff81a0" "\n\t" "SCR1_k:" "\n\t" " .long 0xffff81b0" "\n\t" "SCR2_k:" "\n\t" " .long 0xffff81c0" "\n\t" "SCR3_k:" "\n\t" " .long 0xffff81d0" "\n\t" "SECSIZ:" "\n\t" " .long 512" "\n\t" ); #endif #if defined(__H8300H__) asm( "_mmc_sci0_read:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xb1:8" "\n\t" " mov.b #0x10,r1l" "\n\t" " mov.b r1l,@0xb2:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" "_mmc_sci0_read_L0:" "\n\t" " btst #6,@0xb4:8" "\n\t" " beq _mmc_sci0_read_L0" "\n\t" " mov.b @0xb5:8,r1l" "\n\t" " mov.b r1l,@er0" "\n\t" " mov.b r1h,@0xb4:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci0_read_L0" "\n\t" " rts" "\n\t" "_mmc_sci1_read:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xb9:8" "\n\t" " mov.b #0x10,r1l" "\n\t" " mov.b r1l,@0xba:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" " nop" "\n\t" "_mmc_sci1_read_L0:" "\n\t" " btst #6,@0xbc:8" "\n\t" " beq _mmc_sci1_read_L0" "\n\t" " mov.b @0xbd:8,r1l" "\n\t" " mov.b r1l,@er0" "\n\t" " mov.b r1h,@0xbc:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci1_read_L0" "\n\t" " rts" "\n\t" "_mmc_sci2_read:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xc1:8" "\n\t" " mov.b #0x10,r1l" "\n\t" " mov.b r1l,@0xc2:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" " nop" "\n\t" "_mmc_sci2_read_L0:" "\n\t" " btst #6,@0xc4:8" "\n\t" " beq _mmc_sci2_read_L0" "\n\t" " mov.b @0xc5:8,r1l" "\n\t" " mov.b r1l,@er0" "\n\t" " mov.b r1h,@0xc4:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci2_read_L0" "\n\t" " rts" "\n\t" "_mmc_sci0_write:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xb1:8" "\n\t" " mov.b #0x20,r1l" "\n\t" " mov.b r1l,@0xb2:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" "_mmc_sci0_write_L0:" "\n\t" " btst #7,@0xb4:8" "\n\t" " beq _mmc_sci0_write_L0" "\n\t" " mov.b @er0,r1l" "\n\t" " mov.b r1l,@0xb3:8" "\n\t" " mov.b r1h,@0xb4:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci0_write_L0" "\n\t" " rts" "\n\t" "_mmc_sci1_write:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xb9:8" "\n\t" " mov.b #0x20,r1l" "\n\t" " mov.b r1l,@0xba:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" "_mmc_sci1_write_L0:" "\n\t" " btst #7,@0xbc:8" "\n\t" " beq _mmc_sci1_write_L0" "\n\t" " mov.b @er0,r1l" "\n\t" " mov.b r1l,@0xbb:8" "\n\t" " mov.b r1h,@0xbc:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci1_write_L0" "\n\t" " rts" "\n\t" "_mmc_sci2_write:" "\n\t" " mov.b #0,r1h" "\n\t" " mov.b r1l,@0xc1:8" "\n\t" " mov.b #0x20,r1l" "\n\t" " mov.b r1l,@0xc2:8" "\n\t" " mov.l er0,er2" "\n\t" " add.l #512,er2" "\n\t" "_mmc_sci2_write_L0:" "\n\t" " btst #7,@0xc4:8" "\n\t" " beq _mmc_sci2_write_L0" "\n\t" " mov.b @er0,r1l" "\n\t" " mov.b r1l,@0xc3:8" "\n\t" " mov.b r1h,@0xc4:8" "\n\t" " inc.l #1,er0" "\n\t" " cmp.l er0,er2" "\n\t" " bne _mmc_sci2_write_L0" "\n\t" " rts" "\n\t" ); #endif #define MMC_NUM 2 #define RETRY_NUM 12 #define MMC_CMD_INIT 0x40 #define SECSIZ 512 #define CMD_INITIALIZE 0 #define CMD_ENABLE 1 #define CMD_CSD 9 #define CMD_CID 10 #define CMD_WRITE 24 #define CMD_READ 17 #if defined(__H8300H__) || defined(__sh2__) #define LOW_SPD 96 #define MID_SPD 48 #define MMC_TIME_OVER 1000 #endif #if defined(__sh3__) #define LOW_SPD 144 #define MID_SPD 32 #define MMC_TIME_OVER 1500 #endif // SMR #define CA 0x80 #define CHR 0x40 #define PE 0x20 #define OE 0x10 #define STOP 0x08 #define MP 0x04 // SCR #define TIE 0x80 #define RIE 0x40 #define TE 0x20 #define RE 0x10 #define MPIE 0x08 #define TEIE 0x04 #define SCK_OUT 0 #define SCK_IN 2 // SSR #define TDRE 0x80 #define RDRF 0x40 #define ORER 0x20 #define FER 0x10 #define PER 0x08 #define TEND 0x04 #define MPB 0x02 #define MPBT 0x01 typedef struct { unsigned int cs; unsigned int clk; unsigned int cmd; unsigned int data; unsigned int outbits; unsigned int clkcmd; unsigned int offset; unsigned int cache_start; unsigned int cache_size; IOREG *dr; #if defined(__H8300H__) || defined(__sh__) int port; int sci_port; int sci_speed; volatile char *smr; volatile char *brr; volatile char *scr; volatile char *tdr; volatile char *ssr; volatile char *rdr; volatile char *scmr; #endif volatile char *cache; int (*mmc_config_read)(int, unsigned char*, int, int); int (*mmc_reset)(int); int (*mmc_write)(int, char*, int); int (*mmc_read)(int, char*, int); unsigned char sci; unsigned char cs_positive; unsigned char eject_port; unsigned char eject_bit; } mmcinfo; static mmcinfo *mmc; #define CS mmc[minor].cs #define CLK mmc[minor].clk #define CMD mmc[minor].cmd #define DATA mmc[minor].data #define CS_CLK_CMD mmc[minor].outbits #define CLK_CMD mmc[minor].clkcmd #if defined(__H8300H__) || defined(__sh__) #define MMC_DR mmc[minor].dr #endif #if defined(__arm__) static void outport(int minor, int data) { PIO_SODR = data & CS_CLK_CMD; PIO_CODR = ~data & CS_CLK_CMD; } static int inport(int minor) { return PIO_PDSR & DATA; } #endif #if defined(__H8300H__) || defined(__sh__) #define outport(minor, data) *MMC_DR = ~(data & CS_CLK_CMD) #define inport(minor) (*MMC_DR & DATA) #endif static int spi_putchar(int minor, char data) { int i, ser; task_sw_ctl(1); outport(minor, CMD); for(i = 0;i < 8;i++){ ser = ((data << i) & 0x80) ? CMD : 0; outport(minor, ser); outport(minor, ser | CLK); } outport(minor, CMD); task_sw_ctl(0); return 1; } static unsigned char spi_getchar(int minor) { int i; char data; task_sw_ctl(1); outport(minor, CMD); data = 0; for(i = 0;i < 8;i++) { outport(minor, CLK_CMD); data |= (inport(minor) & DATA) ? 1 << (7 - i) : 0; outport(minor, CMD); } task_sw_ctl(0); return data; } static char spi_getblock(int minor, char *buffer, int size) { int i, n; outport(minor, CMD); for(n = 0;n < size;n++) { buffer[n] = 0; for(i = 0;i < 8;i++) { outport(minor, CLK_CMD); buffer[n] |= (inport(minor) & DATA) ? 1 << (7 - i) : 0; outport(minor, CMD); } } return size; } static char spi_mmc_command(int minor, char command, char *arg, int arglen) { int datalen, over; unsigned char data; spi_putchar(minor, 0xff); spi_putchar(minor, MMC_CMD_INIT | (command & 0x3f)); datalen = arglen; while(datalen) { spi_putchar(minor, arg[arglen - datalen]); datalen--; } datalen = 4 - arglen; while(datalen){ spi_putchar(minor, 0x00); datalen--; } spi_putchar(minor, (command == 0) ? 0x95 : 0); spi_putchar(minor, 0xff); over = MMC_TIME_OVER; while((data = spi_getchar(minor)) & 0x80){ if(--over == 0) return 0xff; } spi_putchar(minor, 0xff); return data; } static int spi_mmc_config_read(int minor, unsigned char *data, int command, int len) { int i, ret; ret = spi_mmc_command(minor, command, 0, 0); for(i = 0;i < len;i++) { data[i] = spi_getchar(minor); if(i == 0 && data[0] == 0xfe) i--; } spi_getchar(minor); spi_getchar(minor); spi_putchar(minor, 0xff); return 0; } static int spi_mmc_reset(int minor) { int i, ret; *MMC_DR = CS + CLK + CMD; if(mmc[minor].cs_positive == 0) { outport(minor, CS | CMD); } else { outport(minor, CMD); } for(i = 0;i < 100;i++) { outport(minor, CS_CLK_CMD); if(mmc[minor].cs_positive == 0) { outport(minor, CS | CMD); } else { outport(minor, CMD); } } outport(minor, CMD); ret = spi_mmc_command(minor, 0, 0, 0); if(ret != 1) return -1; for(;;) { ret = spi_mmc_command(minor, 1, 0, 0); if(ret == 0x00) break; if(ret != 0x01) return -1; } return 0; } static int spi_writemmc(int minor, char *buffer, int size) { int i, ret, address, over; address = be32toh(mmc[minor].offset * SECSIZ); ret = spi_mmc_command(minor, 24, (char*)&address, 4); if(ret != 0) return -1; spi_putchar(minor, 0xfe); for(i = 0;i < SECSIZ;i++) spi_putchar(minor, buffer[i]); spi_putchar(minor, 0); spi_putchar(minor, 0); over = MMC_TIME_OVER; while(spi_getchar(minor) != 0xff) { if(--over == 0) return -1; } return 0; } static int spi_readmmc(int minor, char *buffer, int size) { int i, ret, address, over; int c; address = be32toh(mmc[minor].offset * SECSIZ); ret = spi_mmc_command(minor, 17, (char*)&address, 4); if(ret != 0) return -1; over = MMC_TIME_OVER; for(;;) { c = spi_getchar(minor); if(c == 0xfe) break; if(--over == 0) return -1; } spi_getblock(minor, buffer, SECSIZ); spi_getchar(minor); spi_getchar(minor); spi_putchar(minor, 0xff); return 0; } static void sci_putch(int minor, int c) { int w; #if defined(__sh__) ddr_set(mmc[minor].sci_port, CLK); #endif *mmc[minor].scr = TE + SCK_OUT; while((*mmc[minor].ssr & TDRE) == 0); pe_reset(mmc[minor].sci_port, CLK); *mmc[minor].tdr = c; w = *mmc[minor].ssr; *mmc[minor].ssr = 0; } static void sci_putch_block(int minor, char *data, int size) { switch(mmc[minor].sci) { #if defined(__H8300H__) case 0: mmc_sci0_write(data, 3 * mmc[minor].sci_speed, 0); break; case 1: mmc_sci1_write(data, 3 * mmc[minor].sci_speed, 0); break; case 2: mmc_sci2_write(data, 3 * mmc[minor].sci_speed, 0); break; #endif #if defined(__sh2__) case 0: mmc_sci0_write(data, 3 * mmc[minor].sci_speed, 0); break; case 1: mmc_sci1_write(data, 3 * mmc[minor].sci_speed, 0); break; case 2: mmc_sci2_write(data, 3 * mmc[minor].sci_speed, 0); break; case 3: mmc_sci3_write(data, 3 * mmc[minor].sci_speed, 0); break; #endif #if defined(__sh3__) case 0: mmc_sci0_write(data, 4 * mmc[minor].sci_speed, 0); break; #endif } } static void sci_putch_sw(int minor) { volatile char *scr, *ssr, *smr; scr = mmc[minor].scr; ssr = mmc[minor].ssr; smr = mmc[minor].smr; while(!(*ssr & TEND)); #if defined(__sh__) ddr_reset(mmc[minor].sci_port, CLK); #endif *scr |= SCK_IN; pe_reset(mmc[minor].sci_port, CLK); *smr = 0; *scr = SCK_OUT; *ssr = 0; *smr = CA; } static int sci_getch(int minor) { int w, c; #if defined(__sh2__) ddr_set(mmc[minor].sci_port, CLK); #endif *mmc[minor].scr = RE + SCK_OUT; if(*mmc[minor].ssr & 0x20) { *mmc[minor].ssr &= ~0x20; return -1; } pe_reset(mmc[minor].sci_port, CLK); while((*mmc[minor].ssr & RDRF) == 0); c = *mmc[minor].rdr; w = *mmc[minor].ssr; *mmc[minor].ssr = 0; return c & 0xff; } static int sci_getch_block(int minor, char *data, int size) { switch(mmc[minor].sci) { #if defined(__H8300H__) case 0: mmc_sci0_read(data, 3 * mmc[minor].sci_speed, 0); break; case 1: mmc_sci1_read(data, 3 * mmc[minor].sci_speed, 0); break; case 2: mmc_sci2_read(data, 3 * mmc[minor].sci_speed, 0); break; #endif #if defined(__sh2__) case 0: mmc_sci0_read(data, 3 * mmc[minor].sci_speed, 0); break; case 1: mmc_sci1_read(data, 3 * mmc[minor].sci_speed, 0); break; case 2: mmc_sci2_read(data, 3 * mmc[minor].sci_speed, 0); break; case 3: mmc_sci3_read(data, 3 * mmc[minor].sci_speed, 0); break; #endif #if defined(__sh3__) case 0: mmc_sci0_read(data, 4 * mmc[minor].sci_speed, 0); break; #endif } return 0; } static void sci_getch_sw(int minor) { int c; volatile char *scr, *ssr, *smr, *brr, *rdr; scr = mmc[minor].scr; ssr = mmc[minor].ssr; smr = mmc[minor].smr; brr = mmc[minor].brr; rdr = mmc[minor].rdr; *brr = LOW_SPD; while(!(*ssr & RDRF)); c = *rdr; #if defined(__sh__) ddr_reset(mmc[minor].sci_port, CLK); #endif *scr |= SCK_IN; pe_reset(mmc[minor].sci_port, CLK); *smr = 0; *scr = SCK_OUT; *ssr = 0; *smr = CA; } static int sci_mmc_command(int minor, char command, char *arg, int arglen) { int datalen, over; unsigned char data; volatile int w; *mmc[minor].brr = (command == 0) ? LOW_SPD : MID_SPD; sci_putch(minor, 0xff); sci_putch(minor, MMC_CMD_INIT | (command & 0x3f)); datalen = arglen; while(datalen) { sci_putch(minor, arg[arglen - datalen]); datalen--; } datalen = 4 - arglen; while(datalen){ sci_putch(minor, 0x00); datalen--; } sci_putch(minor, (command == 0) ? 0x95 : 0); sci_putch(minor, 0xff); sci_putch_sw(minor); over = MMC_TIME_OVER; while((data = sci_getch(minor)) & 0x80){ if(--over == 0) return -1; } sci_getch_sw(minor); return data; } static int sci_mmc_reset(minor) { int ret; volatile int i; IOREG *csdr; ddr_set(mmc[minor].sci_port, CLK + CMD); pe_reset(mmc[minor].sci_port, CMD); *MMC_DR |= CLK + CMD; ddr_set(mmc[minor].port, CS); *mmc[minor].scr = 0x00; *mmc[minor].ssr = 0; *mmc[minor].scmr = 0xfa; *mmc[minor].smr = 0x80; *mmc[minor].brr = LOW_SPD; for(i = 0;i < 1000;i++); csdr = get_dr(mmc[minor].port); if(mmc[minor].cs_positive == 0) { *csdr &= ~CS; } else { *csdr |= CS; } INT_DISABLE(); for(i = 0;i < 20;i++) sci_putch(minor, 0xff); sci_putch_sw(minor); if(mmc[minor].cs_positive == 0) { *csdr |= CS; } else { *csdr &= ~CS; } ret = sci_mmc_command(minor, CMD_INITIALIZE, 0, 0); if(ret != 1) { INT_ENABLE(); return -1; } for(;;) { ret = sci_mmc_command(minor, CMD_ENABLE, 0, 0); if(ret == 0x00) break; if(ret != 0x01) { INT_ENABLE(); return -1; } } INT_ENABLE(); return 0; } static int sci_mmc_config_read(int minor, unsigned char *data, int command, int len) { int i, ret, over; unsigned char c; volatile char *brr; brr = mmc[minor].brr; INT_DISABLE(); ret = sci_mmc_command(minor, command, 0, 0); if(ret != 0) { INT_ENABLE(); return -1; } for(i = 0;i < len;i++) { data[i] = sci_getch(minor); if(i == 0 && data[0] == 0xfe) i--; } *mmc[minor].brr = LOW_SPD; sci_getch(minor); sci_getch(minor); sci_getch(minor); sci_getch_sw(minor); INT_ENABLE(); return 0; } static int sci_readmmc(int minor, char *buffer, int size) { int i, ret, address, over; unsigned char c; volatile char *brr; brr = mmc[minor].brr; INT_DISABLE(); address = be32toh(mmc[minor].offset * SECSIZ); ret = sci_mmc_command(minor, CMD_READ, (char*)&address, 4); if(ret != 0) { INT_ENABLE(); return -1; } over = MMC_TIME_OVER; for(;;) { c = sci_getch(minor); if(c == 0xfe) break; if(--over == 0) { INT_ENABLE(); return -1; } } sci_getch_block(minor, buffer, SECSIZ); *brr = LOW_SPD; sci_getch(minor); sci_getch(minor); sci_getch(minor); sci_getch_sw(minor); INT_ENABLE(); return 0; } static int sci_writemmc(int minor, char *buffer, int size) { int i, ret, address, over; char c; volatile char *brr; brr = mmc[minor].brr; INT_DISABLE(); address = be32toh(mmc[minor].offset * SECSIZ); ret = sci_mmc_command(minor, CMD_WRITE, (char*)&address, 4); if(ret != 0) { INT_ENABLE(); return -1; } sci_putch(minor, 0xfe); sci_putch_block(minor, buffer, SECSIZ); *brr = LOW_SPD; sci_putch(minor, 0); sci_putch(minor, 0); sci_putch(minor, 0); sci_putch_sw(minor); over = MMC_TIME_OVER; while(sci_getch(minor) != 0xff) { if(--over == 0) { INT_ENABLE(); return -1; } } sci_getch_sw(minor); INT_ENABLE(); return 0; } static int open_mmc(int minor, int option) { unsigned int i, m, ret, addr; char data_bit; IOREG *data_reg; if(minor >= MMC_NUM) return -1; if(option == -1) return 0; #if defined(__arm__) PIO_PER = CS + CLK + CMD + DATA; PIO_OER = CS + CLK + CMD; PIO_ODR = DATA; PIO_SODR = 0; #endif #if defined(__H8300H__) || defined(__sh__) if(mmc[minor].sci != 0xff) { addr = (int)(&SMR0) + mmc[minor].sci * SCIREGINC; #if defined(__H8300H__) || defined(__sh2__) mmc[minor].smr = (volatile char *)(addr + 0); mmc[minor].brr = (volatile char *)(addr + 1); mmc[minor].scr = (volatile char *)(addr + 2); mmc[minor].tdr = (volatile char *)(addr + 3); mmc[minor].ssr = (volatile char *)(addr + 4); mmc[minor].rdr = (volatile char *)(addr + 5); mmc[minor].scmr = (volatile char *)(addr + 6); #endif #if defined(__sh3__) mmc[minor].smr = (volatile char *)(addr + 0); mmc[minor].brr = (volatile char *)(addr + 2); mmc[minor].scr = (volatile char *)(addr + 4); mmc[minor].tdr = (volatile char *)(addr + 6); mmc[minor].ssr = (volatile char *)(addr + 8); mmc[minor].rdr = (volatile char *)(addr + 10); mmc[minor].scmr = (volatile char *)(addr + 12); #endif mmc[minor].mmc_config_read = sci_mmc_config_read; mmc[minor].mmc_reset = sci_mmc_reset; mmc[minor].mmc_write = sci_writemmc; mmc[minor].mmc_read = sci_readmmc; switch(mmc[minor].sci) { #if defined(__H8300H__) case 0: mmc[minor].sci_port = 9; CLK = 1 << 4; CMD = 1 << 0; MMC_DR = get_dr(9); break; case 1: mmc[minor].sci_port = 9; CLK = 1 << 5; CMD = 1 << 1; MMC_DR = get_dr(9); break; case 2: mmc[minor].sci_port = 11; CLK = 1 << 5; CMD = 1 << 6; MMC_DR = get_dr(11); break; #endif #if defined(__sh2__) case 0: mmc[minor].sci_port = 1; CLK = 1 << 2; CMD = 1 << 1; MMC_DR = get_dr(1); break; case 1: mmc[minor].sci_port = 1; CLK = 1 << 5; CMD = 1 << 4; MMC_DR = get_dr(1); break; case 2: mmc[minor].sci_port = 6; CLK = 1 << 8; CMD = 1 << 7; MMC_DR = get_dr(6); break; case 3: mmc[minor].sci_port = 6; CLK = 1 << 6; CMD = 1 << 4; MMC_DR = get_dr(6); break; #endif #if defined(__sh3__) case 0: mmc[minor].sci_port = 8; CLK = 1 << 1; CMD = 1 << 0; MMC_DR = get_dr(8); break; #endif } } else { MMC_DR = get_dr(mmc[minor].port); mmc[minor].mmc_config_read = spi_mmc_config_read; mmc[minor].mmc_reset = spi_mmc_reset; mmc[minor].mmc_write = spi_writemmc; mmc[minor].mmc_read = spi_readmmc; ddr_set(mmc[minor].port, CS + CLK + CMD); ddr_reset(mmc[minor].port, DATA); } #endif if(mmc[minor].cs_positive == 0) { CS_CLK_CMD = CS + CLK + CMD; } else { CS_CLK_CMD = CLK + CMD; } CLK_CMD = CLK + CMD; if(mmc[minor].eject_port != 0xff) { data_reg = get_dr(mmc[minor].eject_port); data_bit = 1 << mmc[minor].eject_bit; if(*data_reg & data_bit) return -1; } for(i = 0;i < RETRY_NUM * 8;i++) { mmc[minor].offset = 0; ret = (*(mmc[minor].mmc_reset))(minor); if(ret == 0) { mmc[minor].cache_start = 0; mmc[minor].cache_size = 0; mmc[minor].cache = 0; break; } } return ret; } static int close_mmc(int minor) { if(minor >= MMC_NUM) return -1; if(mmc[minor].cache != 0) device_free(SuperTask, (char*)mmc[minor].cache); mmc[minor].cache = 0; return 0; } static int write_mmc(int minor, char *buffer, int size) { int i, ret, address, over, try; int start, tail; char *ptr; start = mmc[minor].cache_start; tail = start + mmc[minor].cache_size; if(mmc[minor].offset >= start && mmc[minor].offset < tail) { ptr = (char*)mmc[minor].cache; memcpy(&ptr[(mmc[minor].offset - start) * SECSIZ], buffer, SECSIZ); } for(try = 0;try < RETRY_NUM;try++) { ret = (*(mmc[minor].mmc_write))(minor, buffer, size); if(ret == 0) break; } if(try == RETRY_NUM) return -1; mmc[minor].offset++; return SECSIZ; } static int read_mmc(int minor, char *buffer, int size) { int i, ret, address, over, try; int start, tail; char c, dummy, *ptr; if(minor >= MMC_NUM) return -1; if(size != SECSIZ) return -1; start = mmc[minor].cache_start; tail = start + mmc[minor].cache_size; if(mmc[minor].offset >= start && mmc[minor].offset < tail) { ptr = (char*)mmc[minor].cache; memcpy(buffer, &ptr[(mmc[minor].offset - start) * SECSIZ], SECSIZ); } else { for(try = 0;try < RETRY_NUM;try++) { ret = (*(mmc[minor].mmc_read))(minor, buffer, size); if(ret == 0) { break; } (*(mmc[minor].mmc_reset))(minor); } if(try == RETRY_NUM) return -1; } mmc[minor].offset++; return SECSIZ; } static int seek_mmc(int minor, int pos) { if(minor >= MMC_NUM) return -1; if((pos % SECSIZ) != 0) return -1; mmc[minor].offset = pos / SECSIZ; return 0; } static int ioctl_mmc(int minor, int data, int op) { int i, ret, start, size; int *params; char *ptr; if(minor >= MMC_NUM) return -1; ret = 0; switch(op) { case DEV_INFO: break; case DISK_CACHE: ret = -1; params = (int*)data; mmc[minor].cache_start = 0; mmc[minor].cache_size = 0; if(mmc[minor].cache != 0) device_free(SuperTask, (char*)mmc[minor].cache); start = params[0]; size = params[1]; mmc[minor].cache = device_malloc(SuperTask, size * SECSIZ); if(mmc[minor].cache == 0) break; ret = 0; mmc[minor].offset = start; ptr = (char*)mmc[minor].cache; for(i = 0;i < size;i++) { read_mmc(minor, ptr, SECSIZ); ptr = &ptr[SECSIZ]; } mmc[minor].cache_start = start; mmc[minor].cache_size = size; break; case MMC_CSD: (*(mmc[minor].mmc_config_read))(minor, (char *)data, 9, 16); break; case MMC_CID: (*(mmc[minor].mmc_config_read))(minor, (char *)data, 10, 16); break; default: ret = -1; } return ret; } static Functions func; int device_main(int argc, char **argv) { unsigned int minor, n, i, ret, addr; mmc = (mmcinfo*)malloc(sizeof(mmcinfo) * MMC_NUM); #ifndef _KERNEL_ for(minor = 0;minor < MMC_NUM;minor++) { mmc[minor].sci = 0xff; mmc[minor].cs_positive = 0; mmc[minor].sci_speed = 1; mmc[minor].eject_port = 0xff; mmc[minor].eject_bit = 0xff; } minor = 0; for(n = 1;n < argc;n++) { if(memcmp(argv[n], "mmc", 3) == 0) { minor = stoi(&argv[n][3]); if(minor >= MMC_NUM) minor = 0; } else if(memcmp(argv[n], "p=", 2) == 0) { mmc[minor].port = stoi(&argv[n][2]); } else if(memcmp(argv[n], "cs=", 3) == 0) { CS = 1 << stoi(&argv[n][3]); } else if(memcmp(argv[n], "clk=", 4) == 0) { CLK = 1 << stoi(&argv[n][4]); } else if(memcmp(argv[n], "cmd=", 4) == 0) { CMD = 1 << stoi(&argv[n][4]); } else if(memcmp(argv[n], "dat=", 4) == 0) { DATA = 1 << stoi(&argv[n][4]); } else if(memcmp(argv[n], "sio=", 4) == 0) { mmc[minor].sci = stoi(&argv[n][4]); } else if(memcmp(argv[n], "csp=", 4) == 0) { mmc[minor].cs_positive = stoi(&argv[n][4]); } else if(memcmp(argv[n], "spd=", 4) == 0) { mmc[minor].sci_speed = stoi(&argv[n][4]); if(mmc[minor].sci_speed > 63) mmc[minor].sci_speed = 63; } else if(memcmp(argv[n], "eject=", 6) == 0) { i = stoh(&argv[n][6]); mmc[minor].eject_port = (i >> 4) & 0x0f; mmc[minor].eject_bit = i & 0x0f; } } #endif for(minor = 0;minor < MMC_NUM;minor++) { #ifdef _KERNEL_ mmc[minor].cs_positive = mmc_config[minor].bits[4]; mmc[minor].eject_port = mmc_config[minor].bits[5]; mmc[minor].eject_bit = mmc_config[minor].bits[6]; #if defined(__arm__) CS = 1 << mmc_config[minor].bits[0]; CLK = 1 << mmc_config[minor].bits[1]; CMD = 1 << mmc_config[minor].bits[2]; DATA = 1 << mmc_config[minor].bits[3]; #endif #if defined(__H8300H__) || defined(__sh__) mmc[minor].port = mmc_config[minor].port; CS = 1 << mmc_config[minor].bits[0]; if(mmc_config[minor].bits[2] == 0) { mmc[minor].sci = mmc_config[minor].bits[1]; mmc[minor].sci_speed = mmc_config[minor].bits[7]; if(mmc[minor].sci_speed == 0) mmc[minor].sci_speed = 1; if(mmc[minor].sci_speed > 63) mmc[minor].sci_speed = 63; } else { mmc[minor].sci = 0xff; CLK = 1 << mmc_config[minor].bits[1]; CMD = 1 << mmc_config[minor].bits[2]; DATA = 1 << mmc_config[minor].bits[3]; } #endif #endif } func.open_dev = open_mmc; func.close_dev = close_mmc; func.write_dev = write_mmc; func.read_dev = read_mmc; func.seek_dev = seek_mmc; func.ioctl_dev = ioctl_mmc; func.poll_dev = 0; strcpy(&(func.name[0]), "mmc"); device_return(&func); }