trunk/src/mame/drivers/firebeat.c
| r25365 | r25366 | |
| 1734 | 1734 | } |
| 1735 | 1735 | |
| 1736 | 1736 | static MACHINE_CONFIG_FRAGMENT( cdrom_config ) |
| 1737 | | MCFG_DEVICE_MODIFY("device:cdda") |
| 1738 | | MCFG_SOUND_ROUTE(0, "^^^^^lspeaker", 1.0) |
| 1739 | | MCFG_SOUND_ROUTE(1, "^^^^^rspeaker", 1.0) |
| 1737 | MCFG_DEVICE_MODIFY("cdda") |
| 1738 | MCFG_SOUND_ROUTE(0, "^^^^lspeaker", 1.0) |
| 1739 | MCFG_SOUND_ROUTE(1, "^^^^rspeaker", 1.0) |
| 1740 | 1740 | MACHINE_CONFIG_END |
| 1741 | 1741 | |
| 1742 | 1742 | static MACHINE_CONFIG_START( firebeat, firebeat_state ) |
| r25365 | r25366 | |
| 1783 | 1783 | MCFG_SOUND_ROUTE(0, "lspeaker", 1.0) |
| 1784 | 1784 | MCFG_SOUND_ROUTE(1, "rspeaker", 1.0) |
| 1785 | 1785 | |
| 1786 | | // TODO: Hookup cdrom audio |
| 1787 | | // MCFG_SOUND_MODIFY("scsi1:cdda") |
| 1788 | | // MCFG_SOUND_ROUTE(0, "^^lspeaker", 1.0) |
| 1789 | | // MCFG_SOUND_ROUTE(1, "^^rspeaker", 1.0) |
| 1790 | | |
| 1791 | 1786 | MCFG_PC16552D_ADD("duart_com", firebeat_com0_interface, firebeat_com1_interface, XTAL_19_6608MHz) // pgmd to 9600baud |
| 1792 | 1787 | MCFG_PC16552D_ADD("duart_midi", firebeat_midi0_interface, firebeat_midi1_interface, XTAL_24MHz) // in all memory maps, pgmd to 31250baud |
| 1793 | 1788 | MACHINE_CONFIG_END |
| r25365 | r25366 | |
| 2066 | 2061 | ROM_REGION(0xc0, "user2", 0) // Security dongle |
| 2067 | 2062 | ROM_LOAD("gq977-ja", 0x00, 0xc0, BAD_DUMP CRC(55b5abdb) SHA1(d8da5bac005235480a1815bd0a79c3e8a63ebad1)) |
| 2068 | 2063 | |
| 2069 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2064 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2070 | 2065 | DISK_IMAGE_READONLY( "977jaa01", 0, BAD_DUMP SHA1(59c03d8eb366167feef741d42d9d8b54bfeb3c1e) ) |
| 2071 | 2066 | |
| 2072 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2067 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2073 | 2068 | DISK_IMAGE_READONLY( "977jaa02", 0, SHA1(bd07c25ee3e1edc962997f6a5bb1700897231fb2) ) |
| 2074 | 2069 | ROM_END |
| 2075 | 2070 | |
| r25365 | r25366 | |
| 2080 | 2075 | ROM_REGION(0xc0, "user2", 0) // Security dongle |
| 2081 | 2076 | ROM_LOAD( "gqa11-ja", 0x000000, 0x0000c0, CRC(2ed8e2ae) SHA1(b8c3410dab643111b2d2027068175ba018a0a67e) ) |
| 2082 | 2077 | |
| 2083 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2078 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2084 | 2079 | DISK_IMAGE_READONLY( "a11jaa01", 0, SHA1(539ec6f1c1d198b0d6ce5543eadcbb4d9917fa42) ) |
| 2085 | 2080 | |
| 2086 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2081 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2087 | 2082 | DISK_IMAGE_READONLY( "a11jaa02", 0, SHA1(575069570cb4a2b58b199a1329d45b189a20fcc9) ) |
| 2088 | 2083 | ROM_END |
| 2089 | 2084 | |
| r25365 | r25366 | |
| 2094 | 2089 | ROM_REGION(0xc0, "user2", ROMREGION_ERASE00) // Security dongle |
| 2095 | 2090 | ROM_LOAD("gq974-ja", 0x00, 0xc0, BAD_DUMP CRC(4578f29b) SHA1(faaeaf6357c1e86e898e7017566cfd2fc7ee3d6f)) |
| 2096 | 2091 | |
| 2097 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2092 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2098 | 2093 | DISK_IMAGE_READONLY( "974jac01", 0, BAD_DUMP SHA1(c6145d7090e44c87f71ba626620d2ae2596a75ca) ) |
| 2099 | 2094 | |
| 2100 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2095 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2101 | 2096 | DISK_IMAGE_READONLY( "974jaa02", 1, BAD_DUMP SHA1(3b9946083239eb5687f66a49df24568bffa4fbbd) ) |
| 2102 | 2097 | ROM_END |
| 2103 | 2098 | |
| r25365 | r25366 | |
| 2108 | 2103 | ROM_REGION(0xc0, "user2", ROMREGION_ERASE00) // Security dongle |
| 2109 | 2104 | ROM_LOAD("gca01-ja", 0x00, 0xc0, BAD_DUMP CRC(2bda339d) SHA1(031cb3f44e7a89cd62a9ba948f3d19d53a325abd)) |
| 2110 | 2105 | |
| 2111 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2106 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2112 | 2107 | DISK_IMAGE_READONLY( "a01jaa01", 0, BAD_DUMP SHA1(37bc3879719b3d3c6bc8a5691abd7aa4aec87d45) ) |
| 2113 | 2108 | |
| 2114 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2109 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2115 | 2110 | DISK_IMAGE_READONLY( "a01jaa02", 1, BAD_DUMP SHA1(a3fdeee0f85a7a9718c0fb1cc642ac22d3eff8db) ) |
| 2116 | 2111 | ROM_END |
| 2117 | 2112 | |
| r25365 | r25366 | |
| 2122 | 2117 | ROM_REGION(0xc0, "user2", 0) // Security dongle |
| 2123 | 2118 | ROM_LOAD("gca12-ja", 0x00, 0xc0, BAD_DUMP CRC(cf01dc15) SHA1(da8d208233487ebe65a0a9826fc72f1f459baa26)) |
| 2124 | 2119 | |
| 2125 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2120 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2126 | 2121 | DISK_IMAGE_READONLY( "a12jaa01", 0, BAD_DUMP SHA1(10f2284248e51b1adf0fde173df72ad97fe0e5c8) ) |
| 2127 | 2122 | |
| 2128 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2123 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2129 | 2124 | DISK_IMAGE_READONLY( "a12jaa02", 1, BAD_DUMP SHA1(1256ce9d71350d355a256f83c7b319f0e6e84525) ) |
| 2130 | 2125 | ROM_END |
| 2131 | 2126 | |
| r25365 | r25366 | |
| 2139 | 2134 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2140 | 2135 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2141 | 2136 | |
| 2142 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2137 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2143 | 2138 | DISK_IMAGE_READONLY( "gq986jaa01", 0, SHA1(e5368ac029b0bdf29943ae66677b5521ae1176e1) ) |
| 2144 | 2139 | |
| 2145 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2140 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2146 | 2141 | DISK_IMAGE( "gq986jaa02", 1, SHA1(53367d3d5f91422fe386c42716492a0ae4332390) ) |
| 2147 | 2142 | ROM_END |
| 2148 | 2143 | |
| r25365 | r25366 | |
| 2156 | 2151 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2157 | 2152 | ROM_LOAD16_WORD_SWAP( "a02jaa04.3q", 0x000000, 0x080000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683) ) |
| 2158 | 2153 | |
| 2159 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2154 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2160 | 2155 | DISK_IMAGE_READONLY( "a04jaa01", 0, SHA1(87136ddad1d786b4d5f04381fcbf679ab666e6c9) ) |
| 2161 | 2156 | |
| 2162 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2157 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2163 | 2158 | DISK_IMAGE_READONLY( "a04jaa02", 1, SHA1(49a017dde76f84829f6e99a678524c40665c3bfd) ) |
| 2164 | 2159 | ROM_END |
| 2165 | 2160 | |
| r25365 | r25366 | |
| 2173 | 2168 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2174 | 2169 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2175 | 2170 | |
| 2176 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2171 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2177 | 2172 | DISK_IMAGE_READONLY( "gqa16jaa01", 0, SHA1(7a7e475d06c74a273f821fdfde0743b33d566e4c) ) |
| 2178 | 2173 | |
| 2179 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2174 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2180 | 2175 | DISK_IMAGE( "gqa16jaa02", 1, SHA1(e39067300e9440ff19cb98c1abc234fa3d5b26d1) ) |
| 2181 | 2176 | ROM_END |
| 2182 | 2177 | |
| r25365 | r25366 | |
| 2190 | 2185 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2191 | 2186 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2192 | 2187 | |
| 2193 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2188 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2194 | 2189 | DISK_IMAGE_READONLY( "b00jab01", 0, SHA1(259c733ca4d30281205b46b7bf8d60c9d01aa818) ) |
| 2195 | 2190 | |
| 2196 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2191 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2197 | 2192 | DISK_IMAGE_READONLY( "b00jaa02", 1, SHA1(c8ce2f8ee6aeeedef9c110a59e68fcec7b669ad6) ) |
| 2198 | 2193 | ROM_END |
| 2199 | 2194 | |
| r25365 | r25366 | |
| 2207 | 2202 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2208 | 2203 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2209 | 2204 | |
| 2210 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2205 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2211 | 2206 | DISK_IMAGE_READONLY( "gqb30jaa01", 0, SHA1(0ff3e40e3717ce23337b3a2438bdaca01cba9e30) ) |
| 2212 | 2207 | |
| 2213 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2208 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2214 | 2209 | DISK_IMAGE_READONLY( "gqb30jaa02", 1, SHA1(f067d502c23efe0267aada5706f5bc7a54605942) ) |
| 2215 | 2210 | ROM_END |
| 2216 | 2211 | |
| r25365 | r25366 | |
| 2224 | 2219 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2225 | 2220 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2226 | 2221 | |
| 2227 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2222 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2228 | 2223 | DISK_IMAGE_READONLY( "gea02jaa01", 0, SHA1(e81203b6812336c4d00476377193340031ef11b1) ) |
| 2229 | 2224 | |
| 2230 | | DISK_REGION( "ata:1:cdrom:device" ) // data DVD-ROM |
| 2225 | DISK_REGION( "ata:1:cdrom" ) // data DVD-ROM |
| 2231 | 2226 | DISK_IMAGE_READONLY( "gea02jaa02", 1, SHA1(7212e399779f37a5dcb8317a8f635a3b3f620aa9) ) |
| 2232 | 2227 | ROM_END |
| 2233 | 2228 | |
| r25365 | r25366 | |
| 2238 | 2233 | ROM_REGION(0xc0, "user2", ROMREGION_ERASE00) // Security dongle |
| 2239 | 2234 | ROM_LOAD("gq977-ko", 0x00, 0xc0, BAD_DUMP CRC(ee743323) SHA1(2042e45879795557ad3cc21b37962f6bf54da60d)) |
| 2240 | 2235 | |
| 2241 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2236 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2242 | 2237 | DISK_IMAGE_READONLY( "977kaa01", 0, BAD_DUMP SHA1(7af9f4949ffa10ea5fc18b6c88c2abc710df3cf9) ) |
| 2243 | 2238 | |
| 2244 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2239 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2245 | 2240 | DISK_IMAGE_READONLY( "977kaa02", 1, SHA1(0feb5ac56269ad4a8401fcfe3bb98b01a0169177) ) |
| 2246 | 2241 | ROM_END |
| 2247 | 2242 | |
| r25365 | r25366 | |
| 2252 | 2247 | ROM_REGION(0xc0, "user2", ROMREGION_ERASE00) // Security dongle |
| 2253 | 2248 | ROM_LOAD("gq977-ja", 0x00, 0xc0, BAD_DUMP CRC(55b5abdb) SHA1(d8da5bac005235480a1815bd0a79c3e8a63ebad1)) |
| 2254 | 2249 | |
| 2255 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2250 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2256 | 2251 | DISK_IMAGE_READONLY( "gc977jaa01", 0, SHA1(7ed1f4b55105c93fec74468436bfb1d540bce944) ) |
| 2257 | 2252 | |
| 2258 | | DISK_REGION( "ata:1:cdrom:device" ) // audio CD-ROM |
| 2253 | DISK_REGION( "ata:1:cdrom" ) // audio CD-ROM |
| 2259 | 2254 | DISK_IMAGE_READONLY( "gc977jaa02", 1, SHA1(74ce8c90575fd562807def7d561392d0f91f2bc6) ) |
| 2260 | 2255 | ROM_END |
| 2261 | 2256 | |
| r25365 | r25366 | |
| 2270 | 2265 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2271 | 2266 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, BAD_DUMP CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2272 | 2267 | |
| 2273 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2268 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2274 | 2269 | DISK_IMAGE_READONLY( "gcb07jca01", 0, SHA1(f906379bdebee314e2ca97c7756259c8c25897fd) ) |
| 2275 | 2270 | |
| 2276 | 2271 | DISK_REGION( "ata:1:hdd:image" ) // data HDD |
| r25365 | r25366 | |
| 2287 | 2282 | ROM_REGION(0x80000, "audiocpu", 0) // SPU 68K program |
| 2288 | 2283 | ROM_LOAD16_WORD_SWAP("a02jaa04.3q", 0x00000, 0x80000, BAD_DUMP CRC(8c6000dd) SHA1(94ab2a66879839411eac6c673b25143d15836683)) |
| 2289 | 2284 | |
| 2290 | | DISK_REGION( "ata:0:cdrom:device" ) // program CD-ROM |
| 2285 | DISK_REGION( "ata:0:cdrom" ) // program CD-ROM |
| 2291 | 2286 | DISK_IMAGE_READONLY( "gcc01jca01", 0, SHA1(3e7af83670d791591ad838823422959987f7aab9) ) |
| 2292 | 2287 | |
| 2293 | 2288 | DISK_REGION( "ata:1:hdd:image" ) // data HDD |
trunk/src/mame/machine/gdrom.c
| r25365 | r25366 | |
| 4 | 4 | |
| 5 | 5 | ***************************************************************************/ |
| 6 | 6 | |
| 7 | | #include "emu.h" |
| 8 | | #include "machine/scsihle.h" |
| 9 | | #include "cdrom.h" |
| 10 | | #include "imagedev/chd_cd.h" |
| 11 | 7 | #include "gdrom.h" |
| 12 | | #include "debugger.h" |
| 13 | 8 | |
| 14 | 9 | #define GDROM_BUSY_STATE 0x00 |
| 15 | 10 | #define GDROM_PAUSE_STATE 0x01 |
| r25365 | r25366 | |
| 91 | 86 | }; |
| 92 | 87 | |
| 93 | 88 | |
| 94 | | static void phys_frame_to_msf(int phys_frame, int *m, int *s, int *f) |
| 89 | void gdrom_device::device_reset() |
| 95 | 90 | { |
| 96 | | *m = phys_frame / (60*75); |
| 97 | | phys_frame -= (*m * 60 * 75); |
| 98 | | *s = phys_frame / 75; |
| 99 | | *f = phys_frame % 75; |
| 100 | | } |
| 101 | | |
| 102 | | // device type definition |
| 103 | | const device_type SCSI_GDROM = &device_creator<scsi_gdrom_device>; |
| 104 | | |
| 105 | | scsi_gdrom_device::scsi_gdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 106 | | : scsihle_device(mconfig, SCSI_GDROM, "SCSI GDROM", tag, owner, clock, "scsi_gdrom", __FILE__), |
| 107 | | m_cdda(*this, "cdda") |
| 108 | | { |
| 109 | | } |
| 110 | | |
| 111 | | void scsi_gdrom_device::device_start() |
| 112 | | { |
| 113 | | save_item( NAME( lba ) ); |
| 114 | | save_item( NAME( blocks ) ); |
| 115 | | save_item( NAME( last_lba ) ); |
| 116 | | save_item( NAME( bytes_per_sector ) ); |
| 117 | | save_item( NAME( num_subblocks ) ); |
| 118 | | save_item( NAME( cur_subblock ) ); |
| 119 | | save_item( NAME( play_err_flag ) ); |
| 120 | | } |
| 121 | | |
| 122 | | void scsi_gdrom_device::device_reset() |
| 123 | | { |
| 124 | | scsihle_device::device_reset(); |
| 125 | | |
| 126 | 91 | static const UINT8 GDROM_Def_Cmd11_Reply[32] = |
| 127 | 92 | { |
| 128 | 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x19, 0x00, 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, |
| r25365 | r25366 | |
| 132 | 97 | for(int i = 0;i<32;i++) |
| 133 | 98 | GDROM_Cmd11_Reply[i] = GDROM_Def_Cmd11_Reply[i]; |
| 134 | 99 | |
| 135 | | is_file = TRUE; |
| 136 | | cdrom = subdevice<cdrom_image_device>("image")->get_cdrom_file(); |
| 137 | | if( !cdrom ) |
| 138 | | { |
| 139 | | // try to locate the CHD from a DISK_REGION |
| 140 | | chd_file *chd = get_disk_handle( machine(), tag() ); |
| 141 | | if( chd != NULL ) |
| 142 | | { |
| 143 | | is_file = FALSE; |
| 144 | | cdrom = cdrom_open( chd ); |
| 145 | | } |
| 146 | | } |
| 147 | | |
| 148 | | if (!cdrom) |
| 149 | | { |
| 150 | | logerror("GDROM: no CD found!\n"); |
| 151 | | } |
| 152 | | |
| 153 | | lba = 0; |
| 154 | | blocks = 0; |
| 155 | | last_lba = 0; |
| 156 | | bytes_per_sector = 2048; |
| 157 | | num_subblocks = 1; |
| 158 | | cur_subblock = 0; |
| 159 | | play_err_flag = 0; |
| 100 | atapi_cdrom_device::device_reset(); |
| 160 | 101 | } |
| 161 | 102 | |
| 162 | | void scsi_gdrom_device::device_stop() |
| 163 | | { |
| 164 | | if (!is_file) |
| 165 | | { |
| 166 | | if( cdrom ) |
| 167 | | { |
| 168 | | cdrom_close( cdrom ); |
| 169 | | } |
| 170 | | } |
| 171 | | } |
| 172 | | |
| 173 | | cdrom_interface scsi_gdrom_device::cd_intf = { 0, 0 }; |
| 174 | | |
| 175 | | static MACHINE_CONFIG_FRAGMENT(scsi_cdrom) |
| 176 | | MCFG_CDROM_ADD("image", scsi_gdrom_device::cd_intf) |
| 177 | | MCFG_SOUND_ADD("cdda", CDDA, 0) |
| 178 | | MACHINE_CONFIG_END |
| 179 | | |
| 180 | | machine_config_constructor scsi_gdrom_device::device_mconfig_additions() const |
| 181 | | { |
| 182 | | return MACHINE_CONFIG_NAME(scsi_cdrom); |
| 183 | | } |
| 184 | | |
| 185 | 103 | // scsicd_exec_command |
| 186 | 104 | // |
| 187 | 105 | // Execute a SCSI command. |
| 188 | 106 | |
| 189 | | void scsi_gdrom_device::ExecCommand( int *transferLength ) |
| 107 | void gdrom_device::ExecCommand() |
| 190 | 108 | { |
| 191 | | int trk; |
| 192 | | |
| 193 | 109 | switch ( command[0] ) |
| 194 | 110 | { |
| 195 | | case 0x03: // REQUEST SENSE |
| 196 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 197 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 198 | | break; |
| 199 | | |
| 200 | 111 | case 0x11: // REQ_MODE |
| 201 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 112 | m_phase = SCSI_PHASE_DATAIN; |
| 202 | 113 | printf("REQ_MODE %02x %02x %02x %02x %02x %02x\n", |
| 203 | 114 | command[0], command[1], |
| 204 | 115 | command[2], command[3], |
| 205 | 116 | command[4], command[5]); |
| 206 | 117 | // if (SCSILengthFromUINT8( &command[ 4 ] ) < 32) return -1; |
| 207 | 118 | transferOffset = command[2]; |
| 208 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 119 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 209 | 120 | break; |
| 210 | 121 | |
| 211 | 122 | case 0x12: // INQUIRY |
| 212 | 123 | logerror("GDROM: REQUEST SENSE\n"); |
| 213 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 124 | m_phase = SCSI_PHASE_DATAOUT; |
| 214 | 125 | //transferOffset = command[2]; |
| 215 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 126 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 216 | 127 | printf("SET_MODE %02x %02x\n",command[2],command[4]); |
| 217 | 128 | break; |
| 218 | 129 | |
| 219 | | case 0x15: // MODE SELECT(6) |
| 220 | | logerror("GDROM: MODE SELECT(6) length %x control %x\n", command[4], command[5]); |
| 221 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 222 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 223 | | break; |
| 224 | | |
| 225 | | case 0x1a: // MODE SENSE(6) |
| 226 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 227 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 228 | | break; |
| 229 | | |
| 230 | | case 0x1b: // START STOP UNIT |
| 231 | | if (m_cdda != NULL) |
| 232 | | { |
| 233 | | m_cdda->stop_audio(); |
| 234 | | } |
| 235 | | SetPhase( SCSI_PHASE_STATUS ); |
| 236 | | *transferLength = 0; |
| 237 | | break; |
| 238 | | |
| 239 | | case 0x1e: // PREVENT ALLOW MEDIUM REMOVAL |
| 240 | | SetPhase( SCSI_PHASE_STATUS ); |
| 241 | | *transferLength = 0; |
| 242 | | break; |
| 243 | | |
| 244 | | case 0x25: // READ CAPACITY |
| 245 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 246 | | *transferLength = 8; |
| 247 | | break; |
| 248 | | |
| 249 | | case 0x28: // READ(10) |
| 250 | | |
| 251 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 252 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 253 | | |
| 254 | | logerror("GDROM: READ(10) at LBA %x for %d blocks (%d bytes)\n", lba, blocks, blocks * bytes_per_sector); |
| 255 | | |
| 256 | | if (num_subblocks > 1) |
| 257 | | { |
| 258 | | cur_subblock = lba % num_subblocks; |
| 259 | | lba /= num_subblocks; |
| 260 | | } |
| 261 | | else |
| 262 | | { |
| 263 | | cur_subblock = 0; |
| 264 | | } |
| 265 | | |
| 266 | | if (m_cdda != NULL) |
| 267 | | { |
| 268 | | m_cdda->stop_audio(); |
| 269 | | } |
| 270 | | |
| 271 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 272 | | *transferLength = blocks * bytes_per_sector; |
| 273 | | break; |
| 274 | | |
| 275 | 130 | case 0x30: // CD_READ |
| 276 | 131 | if (command[1] & 1) |
| 277 | 132 | { |
| 278 | 133 | fatalerror("GDROM: MSF mode used for CD_READ, unsupported\n"); |
| 279 | | *transferLength = 0; |
| 134 | m_transfer_length = 0; |
| 280 | 135 | } |
| 281 | 136 | else |
| 282 | 137 | { |
| r25365 | r25366 | |
| 296 | 151 | fatalerror("GDROM: Unhandled data_select %d\n", data_select); |
| 297 | 152 | } |
| 298 | 153 | |
| 299 | | printf("GDROM: CD_READ at LBA %x for %d blocks (%d bytes, read type %d, data select %d)\n", lba, blocks, blocks * bytes_per_sector, read_type, data_select); |
| 154 | printf("GDROM: CD_READ at LBA %x for %d blocks (%d bytes, read type %d, data select %d)\n", lba, blocks, blocks * m_sector_bytes, read_type, data_select); |
| 300 | 155 | |
| 301 | 156 | if (num_subblocks > 1) |
| 302 | 157 | { |
| r25365 | r25366 | |
| 313 | 168 | m_cdda->stop_audio(); |
| 314 | 169 | } |
| 315 | 170 | |
| 316 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 317 | | *transferLength = blocks * bytes_per_sector; |
| 171 | m_phase = SCSI_PHASE_DATAIN; |
| 172 | m_transfer_length = blocks * m_sector_bytes; |
| 318 | 173 | } |
| 319 | 174 | break; |
| 320 | 175 | |
| 321 | | case 0x42: // READ SUB-CHANNEL |
| 322 | | // logerror("GDROM: READ SUB-CHANNEL type %d\n", command[3]); |
| 323 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 324 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 325 | | break; |
| 326 | | |
| 327 | | case 0x43: // READ TOC |
| 328 | | { |
| 329 | | int start_trk = command[6]; |
| 330 | | int end_trk = cdrom_get_last_track(cdrom); |
| 331 | | int length; |
| 332 | | int allocation_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 333 | | |
| 334 | | if( start_trk == 0 ) |
| 335 | | { |
| 336 | | start_trk = 1; |
| 337 | | } |
| 338 | | if( start_trk == 0xaa ) |
| 339 | | { |
| 340 | | end_trk = start_trk; |
| 341 | | } |
| 342 | | |
| 343 | | length = 4 + ( 8 * ( ( end_trk - start_trk ) + 1 ) ); |
| 344 | | if( length > allocation_length ) |
| 345 | | { |
| 346 | | length = allocation_length; |
| 347 | | } |
| 348 | | else if( length < 4 ) |
| 349 | | { |
| 350 | | length = 4; |
| 351 | | } |
| 352 | | |
| 353 | | if (m_cdda != NULL) |
| 354 | | { |
| 355 | | m_cdda->stop_audio(); |
| 356 | | } |
| 357 | | |
| 358 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 359 | | *transferLength = length; |
| 360 | | //debugger_break(machine()); |
| 361 | | break; |
| 362 | | } |
| 363 | | |
| 364 | 176 | // READ TOC (GD-ROM ver.) |
| 365 | 177 | case 0x14: |
| 366 | 178 | { |
| r25365 | r25366 | |
| 393 | 205 | m_cdda->stop_audio(); |
| 394 | 206 | } |
| 395 | 207 | |
| 396 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 397 | | *transferLength = length; |
| 208 | m_phase = SCSI_PHASE_DATAIN; |
| 209 | m_transfer_length = length; |
| 398 | 210 | break; |
| 399 | 211 | } |
| 400 | 212 | |
| 401 | | case 0x45: // PLAY AUDIO(10) |
| 402 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 403 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 404 | | |
| 405 | | // special cases: lba of 0 means MSF of 00:02:00 |
| 406 | | if (lba == 0) |
| 407 | | { |
| 408 | | lba = 150; |
| 409 | | } |
| 410 | | else if (lba == 0xffffffff) |
| 411 | | { |
| 412 | | logerror("GDROM: play audio from current not implemented!\n"); |
| 413 | | } |
| 414 | | |
| 415 | | logerror("GDROM: PLAY AUDIO(10) at LBA %x for %x blocks\n", lba, blocks); |
| 416 | | |
| 417 | | trk = cdrom_get_track(cdrom, lba); |
| 418 | | |
| 419 | | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 420 | | { |
| 421 | | play_err_flag = 0; |
| 422 | | if (m_cdda != NULL) |
| 423 | | m_cdda->start_audio(lba, blocks); |
| 424 | | } |
| 425 | | else |
| 426 | | { |
| 427 | | logerror("GDROM: track is NOT audio!\n"); |
| 428 | | play_err_flag = 1; |
| 429 | | } |
| 430 | | |
| 431 | | SetPhase( SCSI_PHASE_STATUS ); |
| 432 | | *transferLength = 0; |
| 433 | | break; |
| 434 | | |
| 435 | | case 0x48: // PLAY AUDIO TRACK/INDEX |
| 436 | | // be careful: tracks here are zero-based, but the SCSI command |
| 437 | | // uses the real CD track number which is 1-based! |
| 438 | | lba = cdrom_get_track_start(cdrom, command[4]-1); |
| 439 | | blocks = cdrom_get_track_start(cdrom, command[7]-1) - lba; |
| 440 | | if (command[4] > command[7]) |
| 441 | | { |
| 442 | | blocks = 0; |
| 443 | | } |
| 444 | | |
| 445 | | if (command[4] == command[7]) |
| 446 | | { |
| 447 | | blocks = cdrom_get_track_start(cdrom, command[4]) - lba; |
| 448 | | } |
| 449 | | |
| 450 | | if (blocks && cdrom) |
| 451 | | { |
| 452 | | if (m_cdda != NULL) |
| 453 | | m_cdda->start_audio(lba, blocks); |
| 454 | | } |
| 455 | | |
| 456 | | logerror("GDROM: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], blocks); |
| 457 | | SetPhase( SCSI_PHASE_STATUS ); |
| 458 | | *transferLength = 0; |
| 459 | | break; |
| 460 | | |
| 461 | | case 0x4b: // PAUSE/RESUME |
| 462 | | if (cdrom) |
| 463 | | { |
| 464 | | if (m_cdda != NULL) |
| 465 | | m_cdda->pause_audio((command[8] & 0x01) ^ 0x01); |
| 466 | | } |
| 467 | | |
| 468 | | logerror("GDROM: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE"); |
| 469 | | SetPhase( SCSI_PHASE_STATUS ); |
| 470 | | *transferLength = 0; |
| 471 | | break; |
| 472 | | |
| 473 | | case 0x55: // MODE SELECT(10) |
| 474 | | logerror("GDROM: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]); |
| 475 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 476 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 477 | | break; |
| 478 | | |
| 479 | | case 0x5a: // MODE SENSE(10) |
| 480 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 481 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 482 | | break; |
| 483 | | |
| 484 | | case 0xa5: // PLAY AUDIO(12) |
| 485 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 486 | | blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; |
| 487 | | |
| 488 | | // special cases: lba of 0 means MSF of 00:02:00 |
| 489 | | if (lba == 0) |
| 490 | | { |
| 491 | | lba = 150; |
| 492 | | } |
| 493 | | else if (lba == 0xffffffff) |
| 494 | | { |
| 495 | | logerror("GDROM: play audio from current not implemented!\n"); |
| 496 | | } |
| 497 | | |
| 498 | | logerror("GDROM: PLAY AUDIO(12) at LBA %x for %x blocks\n", lba, blocks); |
| 499 | | |
| 500 | | trk = cdrom_get_track(cdrom, lba); |
| 501 | | |
| 502 | | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 503 | | { |
| 504 | | play_err_flag = 0; |
| 505 | | if (m_cdda != NULL) |
| 506 | | m_cdda->start_audio(lba, blocks); |
| 507 | | } |
| 508 | | else |
| 509 | | { |
| 510 | | logerror("GDROM: track is NOT audio!\n"); |
| 511 | | play_err_flag = 1; |
| 512 | | } |
| 513 | | SetPhase( SCSI_PHASE_STATUS ); |
| 514 | | *transferLength = 0; |
| 515 | | break; |
| 516 | | |
| 517 | | case 0xa8: // READ(12) |
| 518 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 519 | | blocks = command[7]<<16 | command[8]<<8 | command[9]; |
| 520 | | |
| 521 | | logerror("GDROM: READ(12) at LBA %x for %x blocks (%x bytes)\n", lba, blocks, blocks * bytes_per_sector); |
| 522 | | |
| 523 | | if (num_subblocks > 1) |
| 524 | | { |
| 525 | | cur_subblock = lba % num_subblocks; |
| 526 | | lba /= num_subblocks; |
| 527 | | } |
| 528 | | else |
| 529 | | { |
| 530 | | cur_subblock = 0; |
| 531 | | } |
| 532 | | |
| 533 | | if (m_cdda != NULL) |
| 534 | | { |
| 535 | | m_cdda->stop_audio(); |
| 536 | | } |
| 537 | | |
| 538 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 539 | | *transferLength = blocks * bytes_per_sector; |
| 540 | | break; |
| 541 | | |
| 542 | | case 0xbb: // SET CD SPEED |
| 543 | | logerror("GDROM: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]); |
| 544 | | SetPhase( SCSI_PHASE_STATUS ); |
| 545 | | *transferLength = 0; |
| 546 | | break; |
| 547 | | |
| 548 | 213 | case 0x70: |
| 549 | | SetPhase( SCSI_PHASE_STATUS ); |
| 550 | | *transferLength = 0; |
| 214 | m_phase = SCSI_PHASE_STATUS; |
| 215 | m_transfer_length = 0; |
| 551 | 216 | break; |
| 552 | 217 | |
| 553 | 218 | case 0x71: |
| 554 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 555 | | *transferLength = sizeof(GDROM_Cmd71_Reply); |
| 219 | m_phase = SCSI_PHASE_DATAIN; |
| 220 | m_transfer_length = sizeof(GDROM_Cmd71_Reply); |
| 556 | 221 | break; |
| 557 | 222 | |
| 558 | 223 | case 0x40: |
| 559 | 224 | if(command[1] & 0xf) |
| 560 | 225 | { |
| 561 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 562 | | *transferLength = 0xe; |
| 226 | m_phase = SCSI_PHASE_DATAIN; |
| 227 | m_transfer_length = 0xe; |
| 563 | 228 | } |
| 564 | 229 | else |
| 565 | 230 | { |
| r25365 | r25366 | |
| 568 | 233 | break; |
| 569 | 234 | |
| 570 | 235 | default: |
| 571 | | scsihle_device::ExecCommand( transferLength ); |
| 236 | t10mmc::ExecCommand(); |
| 572 | 237 | break; |
| 573 | 238 | } |
| 574 | 239 | } |
| r25365 | r25366 | |
| 577 | 242 | // |
| 578 | 243 | // Read data from the device resulting from the execution of a command |
| 579 | 244 | |
| 580 | | void scsi_gdrom_device::ReadData( UINT8 *data, int dataLength ) |
| 245 | void gdrom_device::ReadData( UINT8 *data, int dataLength ) |
| 581 | 246 | { |
| 582 | 247 | int i; |
| 583 | | UINT32 last_phys_frame; |
| 584 | | UINT32 temp; |
| 585 | 248 | UINT8 tmp_buffer[2048]; |
| 586 | 249 | |
| 587 | 250 | switch ( command[0] ) |
| 588 | 251 | { |
| 589 | | case 0x03: // REQUEST SENSE |
| 590 | | logerror("GDROM: Reading REQUEST SENSE data\n"); |
| 591 | | |
| 592 | | memset( data, 0, dataLength ); |
| 593 | | |
| 594 | | data[0] = 0x71; // deferred error |
| 595 | | |
| 596 | | if (m_cdda != NULL && m_cdda->audio_active()) |
| 597 | | { |
| 598 | | data[12] = 0x00; |
| 599 | | data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS |
| 600 | | } |
| 601 | | else if (play_err_flag) |
| 602 | | { |
| 603 | | play_err_flag = 0; |
| 604 | | data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK |
| 605 | | data[13] = 0x00; |
| 606 | | } |
| 607 | | // (else 00/00 means no error to report) |
| 608 | | break; |
| 609 | | |
| 610 | 252 | case 0x11: // REQ_MODE |
| 611 | 253 | printf("REQ_MODE: dataLength %d\n", dataLength); |
| 612 | 254 | memcpy(data, &GDROM_Cmd11_Reply[transferOffset], (dataLength >= 32-transferOffset) ? 32-transferOffset : dataLength); |
| 613 | 255 | break; |
| 614 | 256 | |
| 615 | | case 0x25: // READ CAPACITY |
| 616 | | logerror("GDROM: READ CAPACITY\n"); |
| 617 | | |
| 618 | | temp = cdrom_get_track_start(cdrom, 0xaa); |
| 619 | | temp--; // return the last used block on the disc |
| 620 | | |
| 621 | | data[0] = (temp>>24) & 0xff; |
| 622 | | data[1] = (temp>>16) & 0xff; |
| 623 | | data[2] = (temp>>8) & 0xff; |
| 624 | | data[3] = (temp & 0xff); |
| 625 | | data[4] = 0; |
| 626 | | data[5] = 0; |
| 627 | | data[6] = (bytes_per_sector>>8)&0xff; |
| 628 | | data[7] = (bytes_per_sector & 0xff); |
| 629 | | break; |
| 630 | | |
| 631 | | case 0x28: // READ(10) |
| 632 | | case 0xa8: // READ(12) |
| 633 | | logerror("GDROM: read %x dataLength, \n", dataLength); |
| 634 | | if ((cdrom) && (blocks)) |
| 635 | | { |
| 636 | | while (dataLength > 0) |
| 637 | | { |
| 638 | | if (!cdrom_read_data(cdrom, lba, tmp_buffer, CD_TRACK_MODE1)) |
| 639 | | { |
| 640 | | logerror("GDROM: CD read error!\n"); |
| 641 | | } |
| 642 | | |
| 643 | | logerror("True LBA: %d, buffer half: %d\n", lba, cur_subblock * bytes_per_sector); |
| 644 | | |
| 645 | | memcpy(data, &tmp_buffer[cur_subblock * bytes_per_sector], bytes_per_sector); |
| 646 | | |
| 647 | | cur_subblock++; |
| 648 | | if (cur_subblock >= num_subblocks) |
| 649 | | { |
| 650 | | cur_subblock = 0; |
| 651 | | |
| 652 | | lba++; |
| 653 | | blocks--; |
| 654 | | } |
| 655 | | |
| 656 | | last_lba = lba; |
| 657 | | dataLength -= bytes_per_sector; |
| 658 | | data += bytes_per_sector; |
| 659 | | } |
| 660 | | } |
| 661 | | break; |
| 662 | | |
| 663 | 257 | case 0x30: // CD_READ |
| 664 | 258 | logerror("GDROM: read %x dataLength, \n", dataLength); |
| 665 | 259 | if ((cdrom) && (blocks)) |
| r25365 | r25366 | |
| 671 | 265 | logerror("GDROM: CD read error!\n"); |
| 672 | 266 | } |
| 673 | 267 | |
| 674 | | logerror("True LBA: %d, buffer half: %d\n", lba, cur_subblock * bytes_per_sector); |
| 268 | logerror("True LBA: %d, buffer half: %d\n", lba, cur_subblock * m_sector_bytes); |
| 675 | 269 | |
| 676 | | memcpy(data, &tmp_buffer[cur_subblock * bytes_per_sector], bytes_per_sector); |
| 270 | memcpy(data, &tmp_buffer[cur_subblock * m_sector_bytes], m_sector_bytes); |
| 677 | 271 | |
| 678 | 272 | cur_subblock++; |
| 679 | 273 | if (cur_subblock >= num_subblocks) |
| r25365 | r25366 | |
| 685 | 279 | } |
| 686 | 280 | |
| 687 | 281 | last_lba = lba; |
| 688 | | dataLength -= bytes_per_sector; |
| 689 | | data += bytes_per_sector; |
| 282 | dataLength -= m_sector_bytes; |
| 283 | data += m_sector_bytes; |
| 690 | 284 | } |
| 691 | 285 | } |
| 692 | | |
| 693 | | case 0x42: // READ SUB-CHANNEL |
| 694 | | switch (command[3]) |
| 695 | | { |
| 696 | | case 1: // return current position |
| 697 | | { |
| 698 | | int audio_active; |
| 699 | | int msf; |
| 700 | | |
| 701 | | if (!cdrom) |
| 702 | | { |
| 703 | | return; |
| 704 | | } |
| 705 | | |
| 706 | | logerror("GDROM: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]); |
| 707 | | |
| 708 | | msf = command[1] & 0x2; |
| 709 | | |
| 710 | | audio_active = m_cdda != NULL && m_cdda->audio_active(); |
| 711 | | if (audio_active) |
| 712 | | { |
| 713 | | if (m_cdda->audio_paused()) |
| 714 | | { |
| 715 | | data[1] = 0x12; // audio is paused |
| 716 | | } |
| 717 | | else |
| 718 | | { |
| 719 | | data[1] = 0x11; // audio in progress |
| 720 | | } |
| 721 | | } |
| 722 | | else |
| 723 | | { |
| 724 | | if (m_cdda != NULL && m_cdda->audio_ended()) |
| 725 | | { |
| 726 | | data[1] = 0x13; // ended successfully |
| 727 | | } |
| 728 | | else |
| 729 | | { |
| 730 | | // data[1] = 0x14; // stopped due to error |
| 731 | | data[1] = 0x15; // No current audio status to return |
| 732 | | } |
| 733 | | } |
| 734 | | |
| 735 | | // if audio is playing, get the latest LBA from the CDROM layer |
| 736 | | if (audio_active) |
| 737 | | { |
| 738 | | last_lba = m_cdda->get_audio_lba(); |
| 739 | | } |
| 740 | | else |
| 741 | | { |
| 742 | | last_lba = 0; |
| 743 | | } |
| 744 | | |
| 745 | | data[2] = 0; |
| 746 | | data[3] = 12; // data length |
| 747 | | data[4] = 0x01; // sub-channel format code |
| 748 | | data[5] = 0x10 | (audio_active ? 0 : 4); |
| 749 | | data[6] = cdrom_get_track(cdrom, last_lba) + 1; // track |
| 750 | | data[7] = 0; // index |
| 751 | | |
| 752 | | last_phys_frame = last_lba; |
| 753 | | |
| 754 | | if (msf) |
| 755 | | { |
| 756 | | int m,s,f; |
| 757 | | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 758 | | data[8] = 0; |
| 759 | | data[9] = m; |
| 760 | | data[10] = s; |
| 761 | | data[11] = f; |
| 762 | | } |
| 763 | | else |
| 764 | | { |
| 765 | | data[8] = last_phys_frame>>24; |
| 766 | | data[9] = (last_phys_frame>>16)&0xff; |
| 767 | | data[10] = (last_phys_frame>>8)&0xff; |
| 768 | | data[11] = last_phys_frame&0xff; |
| 769 | | } |
| 770 | | |
| 771 | | last_phys_frame -= cdrom_get_track_start(cdrom, data[6] - 1); |
| 772 | | |
| 773 | | if (msf) |
| 774 | | { |
| 775 | | int m,s,f; |
| 776 | | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 777 | | data[12] = 0; |
| 778 | | data[13] = m; |
| 779 | | data[14] = s; |
| 780 | | data[15] = f; |
| 781 | | } |
| 782 | | else |
| 783 | | { |
| 784 | | data[12] = last_phys_frame>>24; |
| 785 | | data[13] = (last_phys_frame>>16)&0xff; |
| 786 | | data[14] = (last_phys_frame>>8)&0xff; |
| 787 | | data[15] = last_phys_frame&0xff; |
| 788 | | } |
| 789 | | break; |
| 790 | | } |
| 791 | | default: |
| 792 | | logerror("GDROM: Unknown subchannel type %d requested\n", command[3]); |
| 793 | | } |
| 794 | 286 | break; |
| 795 | 287 | |
| 796 | | case 0x43: // READ TOC |
| 797 | | /* |
| 798 | | Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out. |
| 799 | | That makes sense in terms of how real-world CDs are referred to, but |
| 800 | | our internal routines for tracks use "0" as track 1. That probably |
| 801 | | should be fixed... |
| 802 | | */ |
| 803 | | logerror("GDROM: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1); |
| 804 | | switch (command[2] & 0x0f) |
| 805 | | { |
| 806 | | case 0: // normal |
| 807 | | { |
| 808 | | int start_trk; |
| 809 | | int end_trk; |
| 810 | | int len; |
| 811 | | int in_len; |
| 812 | | int dptr; |
| 813 | | UINT32 tstart; |
| 814 | | |
| 815 | | start_trk = command[6]; |
| 816 | | if( start_trk == 0 ) |
| 817 | | { |
| 818 | | start_trk = 1; |
| 819 | | } |
| 820 | | |
| 821 | | end_trk = cdrom_get_last_track(cdrom); |
| 822 | | len = (end_trk * 8) + 2; |
| 823 | | |
| 824 | | // the returned TOC DATA LENGTH must be the full amount, |
| 825 | | // regardless of how much we're able to pass back due to in_len |
| 826 | | dptr = 0; |
| 827 | | data[dptr++] = (len>>8) & 0xff; |
| 828 | | data[dptr++] = (len & 0xff); |
| 829 | | data[dptr++] = 1; |
| 830 | | data[dptr++] = end_trk; |
| 831 | | |
| 832 | | if( start_trk == 0xaa ) |
| 833 | | { |
| 834 | | end_trk = 0xaa; |
| 835 | | } |
| 836 | | |
| 837 | | in_len = command[7]<<8 | command[8]; |
| 838 | | |
| 839 | | for (i = start_trk; i <= end_trk; i++) |
| 840 | | { |
| 841 | | int cdrom_track = i; |
| 842 | | if( cdrom_track != 0xaa ) |
| 843 | | { |
| 844 | | cdrom_track--; |
| 845 | | } |
| 846 | | |
| 847 | | if( dptr >= in_len ) |
| 848 | | { |
| 849 | | break; |
| 850 | | } |
| 851 | | |
| 852 | | data[dptr++] = 0; |
| 853 | | data[dptr++] = cdrom_get_adr_control(cdrom, cdrom_track); |
| 854 | | data[dptr++] = i; |
| 855 | | data[dptr++] = 0; |
| 856 | | |
| 857 | | tstart = cdrom_get_track_start(cdrom, cdrom_track); |
| 858 | | if ((command[1]&2)>>1) |
| 859 | | tstart = lba_to_msf(tstart); |
| 860 | | data[dptr++] = (tstart>>24) & 0xff; |
| 861 | | data[dptr++] = (tstart>>16) & 0xff; |
| 862 | | data[dptr++] = (tstart>>8) & 0xff; |
| 863 | | data[dptr++] = (tstart & 0xff); |
| 864 | | } |
| 865 | | } |
| 866 | | break; |
| 867 | | default: |
| 868 | | logerror("GDROM: Unhandled READ TOC format %d\n", command[2]&0xf); |
| 869 | | break; |
| 870 | | } |
| 871 | | break; |
| 872 | | |
| 873 | 288 | case 0x14: // READ TOC (GD-ROM ver.) |
| 874 | 289 | /* |
| 875 | 290 | Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out. |
| r25365 | r25366 | |
| 947 | 362 | } |
| 948 | 363 | break; |
| 949 | 364 | |
| 950 | | case 0x1a: // MODE SENSE(6) |
| 951 | | case 0x5a: // MODE SENSE(10) |
| 952 | | logerror("GDROM: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6); |
| 953 | | |
| 954 | | switch (command[2] & 0x3f) |
| 955 | | { |
| 956 | | case 0xe: // CD Audio control page |
| 957 | | data[0] = 0x8e; // page E, parameter is savable |
| 958 | | data[1] = 0x0e; // page length |
| 959 | | data[2] = 0x04; // IMMED = 1, SOTC = 0 |
| 960 | | data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved |
| 961 | | |
| 962 | | // connect each audio channel to 1 output port |
| 963 | | data[8] = 1; |
| 964 | | data[10] = 2; |
| 965 | | data[12] = 4; |
| 966 | | data[14] = 8; |
| 967 | | |
| 968 | | // indicate max volume |
| 969 | | data[9] = data[11] = data[13] = data[15] = 0xff; |
| 970 | | break; |
| 971 | | |
| 972 | | default: |
| 973 | | logerror("GDROM: MODE SENSE unknown page %x\n", command[2] & 0x3f); |
| 974 | | break; |
| 975 | | } |
| 976 | | break; |
| 977 | | |
| 978 | 365 | case 0x71: |
| 979 | 366 | memcpy(data, &GDROM_Cmd71_Reply[0], sizeof(GDROM_Cmd71_Reply)); |
| 980 | 367 | break; |
| r25365 | r25366 | |
| 997 | 384 | break; |
| 998 | 385 | |
| 999 | 386 | default: |
| 1000 | | scsihle_device::ReadData( data, dataLength ); |
| 387 | t10mmc::ReadData( data, dataLength ); |
| 1001 | 388 | break; |
| 1002 | 389 | } |
| 1003 | 390 | } |
| r25365 | r25366 | |
| 1006 | 393 | // |
| 1007 | 394 | // Write data to the CD-ROM device as part of the execution of a command |
| 1008 | 395 | |
| 1009 | | void scsi_gdrom_device::WriteData( UINT8 *data, int dataLength ) |
| 396 | void gdrom_device::WriteData( UINT8 *data, int dataLength ) |
| 1010 | 397 | { |
| 1011 | 398 | switch (command[ 0 ]) |
| 1012 | 399 | { |
| 1013 | | case 0x15: // MODE SELECT(6) |
| 1014 | | case 0x55: // MODE SELECT(10) |
| 1015 | | logerror("GDROM: MODE SELECT page %x\n", data[0] & 0x3f); |
| 1016 | | |
| 1017 | | switch (data[0] & 0x3f) |
| 1018 | | { |
| 1019 | | case 0x0: // vendor-specific |
| 1020 | | // check for SGI extension to force 512-byte blocks |
| 1021 | | if ((data[3] == 8) && (data[10] == 2)) |
| 1022 | | { |
| 1023 | | logerror("GDROM: Experimental SGI 512-byte block extension enabled\n"); |
| 1024 | | |
| 1025 | | bytes_per_sector = 512; |
| 1026 | | num_subblocks = 4; |
| 1027 | | } |
| 1028 | | else |
| 1029 | | { |
| 1030 | | logerror("GDROM: Unknown vendor-specific page!\n"); |
| 1031 | | } |
| 1032 | | break; |
| 1033 | | |
| 1034 | | case 0xe: // audio page |
| 1035 | | logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]); |
| 1036 | | logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]); |
| 1037 | | logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]); |
| 1038 | | logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]); |
| 1039 | | break; |
| 1040 | | } |
| 1041 | | break; |
| 1042 | | |
| 1043 | 400 | case 0x12: |
| 1044 | 401 | memcpy(&GDROM_Cmd11_Reply[transferOffset], data, (dataLength >= 32-transferOffset) ? 32-transferOffset : dataLength); |
| 1045 | 402 | break; |
| 1046 | 403 | |
| 1047 | 404 | default: |
| 1048 | | scsihle_device::WriteData( data, dataLength ); |
| 405 | t10mmc::WriteData( data, dataLength ); |
| 1049 | 406 | break; |
| 1050 | 407 | } |
| 1051 | 408 | } |
| 1052 | 409 | |
| 1053 | | void scsi_gdrom_device::GetDevice( void **_cdrom ) |
| 1054 | | { |
| 1055 | | *(cdrom_file **)_cdrom = cdrom; |
| 1056 | | } |
| 1057 | | |
| 1058 | | void scsi_gdrom_device::SetDevice( void *_cdrom ) |
| 1059 | | { |
| 1060 | | cdrom = (cdrom_file *) _cdrom; |
| 1061 | | } |
| 1062 | | |
| 1063 | | int scsi_gdrom_device::GetSectorBytes() |
| 1064 | | { |
| 1065 | | return bytes_per_sector; |
| 1066 | | } |
| 1067 | | |
| 1068 | 410 | // device type definition |
| 1069 | 411 | const device_type GDROM = &device_creator<gdrom_device>; |
| 1070 | 412 | |
| 1071 | | gdrom_device::gdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 1072 | | : atapi_hle_device(mconfig, GDROM, "GDROM", tag, owner, clock, "gdrom", __FILE__) |
| 413 | gdrom_device::gdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 414 | atapi_cdrom_device(mconfig, GDROM, "GDROM", tag, owner, clock, "gdrom", __FILE__) |
| 1073 | 415 | { |
| 1074 | 416 | } |
| 1075 | 417 | |
| 1076 | | static MACHINE_CONFIG_FRAGMENT( gdrom ) |
| 1077 | | MCFG_DEVICE_ADD("device", SCSI_GDROM, 0) |
| 1078 | | MACHINE_CONFIG_END |
| 1079 | | |
| 1080 | | //------------------------------------------------- |
| 1081 | | // machine_config_additions - device-specific |
| 1082 | | // machine configurations |
| 1083 | | //------------------------------------------------- |
| 1084 | | |
| 1085 | | machine_config_constructor gdrom_device::device_mconfig_additions() const |
| 1086 | | { |
| 1087 | | return MACHINE_CONFIG_NAME( gdrom ); |
| 1088 | | } |
| 1089 | | |
| 1090 | 418 | void gdrom_device::device_start() |
| 1091 | 419 | { |
| 420 | save_item(NAME(read_type)); |
| 421 | save_item(NAME(data_select)); |
| 422 | save_item(NAME(transferOffset)); |
| 423 | |
| 424 | /// TODO: split identify buffer into another method as device_start() should be called after it's filled in, but the atapi_cdrom_device has it's own. |
| 425 | atapi_cdrom_device::device_start(); |
| 426 | |
| 1092 | 427 | memset(m_identify_buffer, 0, sizeof(m_identify_buffer)); |
| 1093 | 428 | |
| 1094 | 429 | m_identify_buffer[0] = 0x8600; // ATAPI device, cmd set 6 compliant, DRQ within 3 ms of PACKET command |
| r25365 | r25366 | |
| 1123 | 458 | |
| 1124 | 459 | m_identify_buffer[63]=7; // multi word dma mode 0-2 supported |
| 1125 | 460 | m_identify_buffer[64]=1; // PIO mode 3 supported |
| 1126 | | |
| 1127 | | atapi_hle_device::device_start(); |
| 1128 | 461 | } |
| 1129 | 462 | |
| 1130 | | void gdrom_device::perform_diagnostic() |
| 1131 | | { |
| 1132 | | m_error = IDE_ERROR_DIAGNOSTIC_PASSED; |
| 1133 | | } |
| 1134 | | |
| 1135 | 463 | void gdrom_device::process_buffer() |
| 1136 | 464 | { |
| 1137 | 465 | atapi_hle_device::process_buffer(); |
| 1138 | 466 | m_sector_number = 0x80 | GDROM_PAUSE_STATE; /// HACK: find out when this should be updated |
| 1139 | 467 | } |
| 1140 | | |
| 1141 | | void gdrom_device::identify_packet_device() |
| 1142 | | { |
| 1143 | | } |
trunk/src/emu/machine/scsicd.c
| r25365 | r25366 | |
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | | scsicd.c - Implementation of a SCSI CD-ROM device, using MAME's cdrom.c primitives |
| 3 | scsicd.c - Implementation of a SCSI CD-ROM device |
| 4 | 4 | |
| 5 | 5 | ***************************************************************************/ |
| 6 | 6 | |
| 7 | | #include "emu.h" |
| 8 | | #include "machine/scsihle.h" |
| 9 | | #include "cdrom.h" |
| 10 | | #include "imagedev/chd_cd.h" |
| 11 | 7 | #include "scsicd.h" |
| 12 | 8 | |
| 13 | | static void phys_frame_to_msf(int phys_frame, int *m, int *s, int *f) |
| 14 | | { |
| 15 | | *m = phys_frame / (60*75); |
| 16 | | phys_frame -= (*m * 60 * 75); |
| 17 | | *s = phys_frame / 75; |
| 18 | | *f = phys_frame % 75; |
| 19 | | } |
| 20 | | |
| 21 | 9 | // device type definition |
| 22 | 10 | const device_type SCSICD = &device_creator<scsicd_device>; |
| 23 | 11 | |
| 24 | | scsicd_device::scsicd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 25 | | : scsihle_device(mconfig, SCSICD, "SCSICD", tag, owner, clock, "scsicd", __FILE__), |
| 26 | | m_cdda(*this, "cdda") |
| 12 | scsicd_device::scsicd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 13 | scsihle_device(mconfig, SCSICD, "SCSICD", tag, owner, clock, "scsicd", __FILE__) |
| 27 | 14 | { |
| 28 | 15 | } |
| 29 | 16 | |
| 30 | 17 | scsicd_device::scsicd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : |
| 31 | | scsihle_device(mconfig, type, name, tag, owner, clock, shortname, source), |
| 32 | | m_cdda(*this, "cdda") |
| 18 | scsihle_device(mconfig, type, name, tag, owner, clock, shortname, source) |
| 33 | 19 | { |
| 34 | 20 | } |
| 35 | 21 | |
| 36 | 22 | void scsicd_device::device_start() |
| 37 | 23 | { |
| 38 | | scsihle_device::device_start(); |
| 24 | m_image = subdevice<cdrom_image_device>("image"); |
| 25 | m_cdda = subdevice<cdda_device>("cdda"); |
| 39 | 26 | |
| 40 | | save_item( NAME( lba ) ); |
| 41 | | save_item( NAME( blocks ) ); |
| 42 | | save_item( NAME( last_lba ) ); |
| 43 | | save_item( NAME( bytes_per_sector ) ); |
| 44 | | save_item( NAME( num_subblocks ) ); |
| 45 | | save_item( NAME( cur_subblock ) ); |
| 46 | | save_item( NAME( play_err_flag ) ); |
| 27 | scsihle_device::device_start(); |
| 47 | 28 | } |
| 48 | 29 | |
| 49 | | void scsicd_device::device_reset() |
| 50 | | { |
| 51 | | scsihle_device::device_reset(); |
| 52 | | |
| 53 | | SetDevice( subdevice<cdrom_image_device>("image")->get_cdrom_file() ); |
| 54 | | if( !cdrom ) |
| 55 | | { |
| 56 | | logerror( "SCSICD %s: no CD found!\n", tag() ); |
| 57 | | } |
| 58 | | |
| 59 | | lba = 0; |
| 60 | | blocks = 0; |
| 61 | | last_lba = 0; |
| 62 | | bytes_per_sector = 2048; |
| 63 | | num_subblocks = 1; |
| 64 | | cur_subblock = 0; |
| 65 | | play_err_flag = 0; |
| 66 | | } |
| 67 | | |
| 68 | 30 | cdrom_interface scsicd_device::cd_intf = { "cdrom", NULL }; |
| 69 | 31 | |
| 70 | 32 | static MACHINE_CONFIG_FRAGMENT(scsi_cdrom) |
| r25365 | r25366 | |
| 76 | 38 | { |
| 77 | 39 | return MACHINE_CONFIG_NAME(scsi_cdrom); |
| 78 | 40 | } |
| 79 | | |
| 80 | | // scsicd_exec_command |
| 81 | | // |
| 82 | | // Execute a SCSI command. |
| 83 | | |
| 84 | | void scsicd_device::ExecCommand( int *transferLength ) |
| 85 | | { |
| 86 | | int trk; |
| 87 | | |
| 88 | | switch ( command[0] ) |
| 89 | | { |
| 90 | | case 0x03: // REQUEST SENSE |
| 91 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 92 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 93 | | break; |
| 94 | | |
| 95 | | case 0x12: // INQUIRY |
| 96 | | logerror("SCSICD: REQUEST SENSE\n"); |
| 97 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 98 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 99 | | break; |
| 100 | | |
| 101 | | case 0x15: // MODE SELECT(6) |
| 102 | | logerror("SCSICD: MODE SELECT(6) length %x control %x\n", command[4], command[5]); |
| 103 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 104 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 105 | | break; |
| 106 | | |
| 107 | | case 0x1a: // MODE SENSE(6) |
| 108 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 109 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 110 | | break; |
| 111 | | |
| 112 | | case 0x1b: // START STOP UNIT |
| 113 | | m_cdda->stop_audio(); |
| 114 | | SetPhase( SCSI_PHASE_STATUS ); |
| 115 | | *transferLength = 0; |
| 116 | | break; |
| 117 | | |
| 118 | | case 0x1e: // PREVENT ALLOW MEDIUM REMOVAL |
| 119 | | SetPhase( SCSI_PHASE_STATUS ); |
| 120 | | *transferLength = 0; |
| 121 | | break; |
| 122 | | |
| 123 | | case 0x25: // READ CAPACITY |
| 124 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 125 | | *transferLength = 8; |
| 126 | | break; |
| 127 | | |
| 128 | | case 0x28: // READ(10) |
| 129 | | |
| 130 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 131 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 132 | | |
| 133 | | logerror("SCSICD: READ(10) at LBA %x for %d blocks (%d bytes)\n", lba, blocks, blocks * bytes_per_sector); |
| 134 | | |
| 135 | | if (num_subblocks > 1) |
| 136 | | { |
| 137 | | cur_subblock = lba % num_subblocks; |
| 138 | | lba /= num_subblocks; |
| 139 | | } |
| 140 | | else |
| 141 | | { |
| 142 | | cur_subblock = 0; |
| 143 | | } |
| 144 | | |
| 145 | | m_cdda->stop_audio(); |
| 146 | | |
| 147 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 148 | | *transferLength = blocks * bytes_per_sector; |
| 149 | | break; |
| 150 | | |
| 151 | | case 0x42: // READ SUB-CHANNEL |
| 152 | | // logerror("SCSICD: READ SUB-CHANNEL type %d\n", command[3]); |
| 153 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 154 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 155 | | break; |
| 156 | | |
| 157 | | case 0x43: // READ TOC |
| 158 | | { |
| 159 | | int start_trk = command[6]; |
| 160 | | int end_trk = cdrom_get_last_track(cdrom); |
| 161 | | int length; |
| 162 | | int allocation_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 163 | | |
| 164 | | if( start_trk == 0 ) |
| 165 | | { |
| 166 | | start_trk = 1; |
| 167 | | } |
| 168 | | if( start_trk == 0xaa ) |
| 169 | | { |
| 170 | | end_trk = start_trk; |
| 171 | | } |
| 172 | | |
| 173 | | length = 4 + ( 8 * ( ( end_trk - start_trk ) + 1 ) ); |
| 174 | | if( length > allocation_length ) |
| 175 | | { |
| 176 | | length = allocation_length; |
| 177 | | } |
| 178 | | else if( length < 4 ) |
| 179 | | { |
| 180 | | length = 4; |
| 181 | | } |
| 182 | | |
| 183 | | m_cdda->stop_audio(); |
| 184 | | |
| 185 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 186 | | *transferLength = length; |
| 187 | | break; |
| 188 | | } |
| 189 | | case 0x45: // PLAY AUDIO(10) |
| 190 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 191 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 192 | | |
| 193 | | // special cases: lba of 0 means MSF of 00:02:00 |
| 194 | | if (lba == 0) |
| 195 | | { |
| 196 | | lba = 150; |
| 197 | | } |
| 198 | | else if (lba == 0xffffffff) |
| 199 | | { |
| 200 | | logerror("SCSICD: play audio from current not implemented!\n"); |
| 201 | | } |
| 202 | | |
| 203 | | logerror("SCSICD: PLAY AUDIO(10) at LBA %x for %x blocks\n", lba, blocks); |
| 204 | | |
| 205 | | trk = cdrom_get_track(cdrom, lba); |
| 206 | | |
| 207 | | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 208 | | { |
| 209 | | play_err_flag = 0; |
| 210 | | m_cdda->start_audio(lba, blocks); |
| 211 | | } |
| 212 | | else |
| 213 | | { |
| 214 | | logerror("SCSICD: track is NOT audio!\n"); |
| 215 | | play_err_flag = 1; |
| 216 | | } |
| 217 | | |
| 218 | | SetPhase( SCSI_PHASE_STATUS ); |
| 219 | | *transferLength = 0; |
| 220 | | break; |
| 221 | | |
| 222 | | case 0x48: // PLAY AUDIO TRACK/INDEX |
| 223 | | // be careful: tracks here are zero-based, but the SCSI command |
| 224 | | // uses the real CD track number which is 1-based! |
| 225 | | lba = cdrom_get_track_start(cdrom, command[4]-1); |
| 226 | | blocks = cdrom_get_track_start(cdrom, command[7]-1) - lba; |
| 227 | | if (command[4] > command[7]) |
| 228 | | { |
| 229 | | blocks = 0; |
| 230 | | } |
| 231 | | |
| 232 | | if (command[4] == command[7]) |
| 233 | | { |
| 234 | | blocks = cdrom_get_track_start(cdrom, command[4]) - lba; |
| 235 | | } |
| 236 | | |
| 237 | | if (blocks && cdrom) |
| 238 | | { |
| 239 | | m_cdda->start_audio(lba, blocks); |
| 240 | | } |
| 241 | | |
| 242 | | logerror("SCSICD: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], blocks); |
| 243 | | SetPhase( SCSI_PHASE_STATUS ); |
| 244 | | *transferLength = 0; |
| 245 | | break; |
| 246 | | |
| 247 | | case 0x4b: // PAUSE/RESUME |
| 248 | | if (cdrom) |
| 249 | | { |
| 250 | | m_cdda->pause_audio((command[8] & 0x01) ^ 0x01); |
| 251 | | } |
| 252 | | |
| 253 | | logerror("SCSICD: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE"); |
| 254 | | SetPhase( SCSI_PHASE_STATUS ); |
| 255 | | *transferLength = 0; |
| 256 | | break; |
| 257 | | |
| 258 | | case 0x4e: // STOP |
| 259 | | if (cdrom) |
| 260 | | { |
| 261 | | m_cdda->stop_audio(); |
| 262 | | } |
| 263 | | |
| 264 | | logerror("SCSICD: STOP_PLAY_SCAN\n"); |
| 265 | | SetPhase( SCSI_PHASE_STATUS ); |
| 266 | | *transferLength = 0; |
| 267 | | break; |
| 268 | | |
| 269 | | case 0x55: // MODE SELECT(10) |
| 270 | | logerror("SCSICD: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]); |
| 271 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 272 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 273 | | break; |
| 274 | | |
| 275 | | case 0x5a: // MODE SENSE(10) |
| 276 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 277 | | *transferLength = SCSILengthFromUINT16( &command[ 7 ] ); |
| 278 | | break; |
| 279 | | |
| 280 | | case 0xa5: // PLAY AUDIO(12) |
| 281 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 282 | | blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; |
| 283 | | |
| 284 | | // special cases: lba of 0 means MSF of 00:02:00 |
| 285 | | if (lba == 0) |
| 286 | | { |
| 287 | | lba = 150; |
| 288 | | } |
| 289 | | else if (lba == 0xffffffff) |
| 290 | | { |
| 291 | | logerror("SCSICD: play audio from current not implemented!\n"); |
| 292 | | } |
| 293 | | |
| 294 | | logerror("SCSICD: PLAY AUDIO(12) at LBA %x for %x blocks\n", lba, blocks); |
| 295 | | |
| 296 | | trk = cdrom_get_track(cdrom, lba); |
| 297 | | |
| 298 | | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 299 | | { |
| 300 | | play_err_flag = 0; |
| 301 | | m_cdda->start_audio(lba, blocks); |
| 302 | | } |
| 303 | | else |
| 304 | | { |
| 305 | | logerror("SCSICD: track is NOT audio!\n"); |
| 306 | | play_err_flag = 1; |
| 307 | | } |
| 308 | | SetPhase( SCSI_PHASE_STATUS ); |
| 309 | | *transferLength = 0; |
| 310 | | break; |
| 311 | | |
| 312 | | case 0xa8: // READ(12) |
| 313 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 314 | | blocks = command[7]<<16 | command[8]<<8 | command[9]; |
| 315 | | |
| 316 | | logerror("SCSICD: READ(12) at LBA %x for %x blocks (%x bytes)\n", lba, blocks, blocks * bytes_per_sector); |
| 317 | | |
| 318 | | if (num_subblocks > 1) |
| 319 | | { |
| 320 | | cur_subblock = lba % num_subblocks; |
| 321 | | lba /= num_subblocks; |
| 322 | | } |
| 323 | | else |
| 324 | | { |
| 325 | | cur_subblock = 0; |
| 326 | | } |
| 327 | | |
| 328 | | m_cdda->stop_audio(); |
| 329 | | |
| 330 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 331 | | *transferLength = blocks * bytes_per_sector; |
| 332 | | break; |
| 333 | | |
| 334 | | case 0xbb: // SET CD SPEED |
| 335 | | logerror("SCSICD: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]); |
| 336 | | SetPhase( SCSI_PHASE_STATUS ); |
| 337 | | *transferLength = 0; |
| 338 | | break; |
| 339 | | |
| 340 | | default: |
| 341 | | scsihle_device::ExecCommand( transferLength ); |
| 342 | | } |
| 343 | | } |
| 344 | | |
| 345 | | // scsicd_read_data |
| 346 | | // |
| 347 | | // Read data from the device resulting from the execution of a command |
| 348 | | |
| 349 | | void scsicd_device::ReadData( UINT8 *data, int dataLength ) |
| 350 | | { |
| 351 | | int i; |
| 352 | | UINT32 last_phys_frame; |
| 353 | | UINT32 temp; |
| 354 | | UINT8 tmp_buffer[2048]; |
| 355 | | |
| 356 | | switch ( command[0] ) |
| 357 | | { |
| 358 | | case 0x03: // REQUEST SENSE |
| 359 | | logerror("SCSICD: Reading REQUEST SENSE data\n"); |
| 360 | | |
| 361 | | memset( data, 0, dataLength ); |
| 362 | | |
| 363 | | data[0] = 0x71; // deferred error |
| 364 | | |
| 365 | | if (m_cdda->audio_active()) |
| 366 | | { |
| 367 | | data[12] = 0x00; |
| 368 | | data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS |
| 369 | | } |
| 370 | | else if (play_err_flag) |
| 371 | | { |
| 372 | | play_err_flag = 0; |
| 373 | | data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK |
| 374 | | data[13] = 0x00; |
| 375 | | } |
| 376 | | // (else 00/00 means no error to report) |
| 377 | | break; |
| 378 | | |
| 379 | | case 0x12: // INQUIRY |
| 380 | | memset( data, 0, dataLength ); |
| 381 | | data[0] = 0x05; // device is present, device is CD/DVD (MMC-3) |
| 382 | | data[1] = 0x80; // media is removable |
| 383 | | data[2] = 0x05; // device complies with SPC-3 standard |
| 384 | | data[3] = 0x02; // response data format = SPC-3 standard |
| 385 | | // some Konami games freak out if this isn't "Sony", so we'll lie |
| 386 | | // this is the actual drive on my Nagano '98 board |
| 387 | | strcpy((char *)&data[8], "Sony"); |
| 388 | | strcpy((char *)&data[16], "CDU-76S"); |
| 389 | | strcpy((char *)&data[32], "1.0"); |
| 390 | | break; |
| 391 | | |
| 392 | | case 0x25: // READ CAPACITY |
| 393 | | logerror("SCSICD: READ CAPACITY\n"); |
| 394 | | |
| 395 | | temp = cdrom_get_track_start(cdrom, 0xaa); |
| 396 | | temp--; // return the last used block on the disc |
| 397 | | |
| 398 | | data[0] = (temp>>24) & 0xff; |
| 399 | | data[1] = (temp>>16) & 0xff; |
| 400 | | data[2] = (temp>>8) & 0xff; |
| 401 | | data[3] = (temp & 0xff); |
| 402 | | data[4] = 0; |
| 403 | | data[5] = 0; |
| 404 | | data[6] = (bytes_per_sector>>8)&0xff; |
| 405 | | data[7] = (bytes_per_sector & 0xff); |
| 406 | | break; |
| 407 | | |
| 408 | | case 0x28: // READ(10) |
| 409 | | case 0xa8: // READ(12) |
| 410 | | logerror("SCSICD: read %x dataLength, \n", dataLength); |
| 411 | | if ((cdrom) && (blocks)) |
| 412 | | { |
| 413 | | while (dataLength > 0) |
| 414 | | { |
| 415 | | if (!cdrom_read_data(cdrom, lba, tmp_buffer, CD_TRACK_MODE1)) |
| 416 | | { |
| 417 | | logerror("SCSICD: CD read error!\n"); |
| 418 | | } |
| 419 | | |
| 420 | | logerror("True LBA: %d, buffer half: %d\n", lba, cur_subblock * bytes_per_sector); |
| 421 | | |
| 422 | | memcpy(data, &tmp_buffer[cur_subblock * bytes_per_sector], bytes_per_sector); |
| 423 | | |
| 424 | | cur_subblock++; |
| 425 | | if (cur_subblock >= num_subblocks) |
| 426 | | { |
| 427 | | cur_subblock = 0; |
| 428 | | |
| 429 | | lba++; |
| 430 | | blocks--; |
| 431 | | } |
| 432 | | |
| 433 | | last_lba = lba; |
| 434 | | dataLength -= bytes_per_sector; |
| 435 | | data += bytes_per_sector; |
| 436 | | } |
| 437 | | } |
| 438 | | break; |
| 439 | | |
| 440 | | case 0x42: // READ SUB-CHANNEL |
| 441 | | switch (command[3]) |
| 442 | | { |
| 443 | | case 1: // return current position |
| 444 | | { |
| 445 | | int msf; |
| 446 | | |
| 447 | | if (!cdrom) |
| 448 | | { |
| 449 | | return; |
| 450 | | } |
| 451 | | |
| 452 | | logerror("SCSICD: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]); |
| 453 | | |
| 454 | | msf = command[1] & 0x2; |
| 455 | | |
| 456 | | int audio_active = m_cdda->audio_active(); |
| 457 | | if (audio_active) |
| 458 | | { |
| 459 | | // if audio is playing, get the latest LBA from the CDROM layer |
| 460 | | last_lba = m_cdda->get_audio_lba(); |
| 461 | | if (m_cdda->audio_paused()) |
| 462 | | { |
| 463 | | data[1] = 0x12; // audio is paused |
| 464 | | } |
| 465 | | else |
| 466 | | { |
| 467 | | data[1] = 0x11; // audio in progress |
| 468 | | } |
| 469 | | } |
| 470 | | else |
| 471 | | { |
| 472 | | last_lba = 0; |
| 473 | | if (m_cdda->audio_ended()) |
| 474 | | { |
| 475 | | data[1] = 0x13; // ended successfully |
| 476 | | } |
| 477 | | else |
| 478 | | { |
| 479 | | // data[1] = 0x14; // stopped due to error |
| 480 | | data[1] = 0x15; // No current audio status to return |
| 481 | | } |
| 482 | | } |
| 483 | | |
| 484 | | data[2] = 0; |
| 485 | | data[3] = 12; // data length |
| 486 | | data[4] = 0x01; // sub-channel format code |
| 487 | | data[5] = 0x10 | (audio_active ? 0 : 4); |
| 488 | | data[6] = cdrom_get_track(cdrom, last_lba) + 1; // track |
| 489 | | data[7] = 0; // index |
| 490 | | |
| 491 | | last_phys_frame = last_lba; |
| 492 | | |
| 493 | | if (msf) |
| 494 | | { |
| 495 | | int m,s,f; |
| 496 | | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 497 | | data[8] = 0; |
| 498 | | data[9] = m; |
| 499 | | data[10] = s; |
| 500 | | data[11] = f; |
| 501 | | } |
| 502 | | else |
| 503 | | { |
| 504 | | data[8] = last_phys_frame>>24; |
| 505 | | data[9] = (last_phys_frame>>16)&0xff; |
| 506 | | data[10] = (last_phys_frame>>8)&0xff; |
| 507 | | data[11] = last_phys_frame&0xff; |
| 508 | | } |
| 509 | | |
| 510 | | last_phys_frame -= cdrom_get_track_start(cdrom, data[6] - 1); |
| 511 | | |
| 512 | | if (msf) |
| 513 | | { |
| 514 | | int m,s,f; |
| 515 | | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 516 | | data[12] = 0; |
| 517 | | data[13] = m; |
| 518 | | data[14] = s; |
| 519 | | data[15] = f; |
| 520 | | } |
| 521 | | else |
| 522 | | { |
| 523 | | data[12] = last_phys_frame>>24; |
| 524 | | data[13] = (last_phys_frame>>16)&0xff; |
| 525 | | data[14] = (last_phys_frame>>8)&0xff; |
| 526 | | data[15] = last_phys_frame&0xff; |
| 527 | | } |
| 528 | | break; |
| 529 | | } |
| 530 | | default: |
| 531 | | logerror("SCSICD: Unknown subchannel type %d requested\n", command[3]); |
| 532 | | } |
| 533 | | break; |
| 534 | | |
| 535 | | case 0x43: // READ TOC |
| 536 | | /* |
| 537 | | Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out. |
| 538 | | That makes sense in terms of how real-world CDs are referred to, but |
| 539 | | our internal routines for tracks use "0" as track 1. That probably |
| 540 | | should be fixed... |
| 541 | | */ |
| 542 | | logerror("SCSICD: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1); |
| 543 | | switch (command[2] & 0x0f) |
| 544 | | { |
| 545 | | case 0: // normal |
| 546 | | { |
| 547 | | int start_trk; |
| 548 | | int end_trk; |
| 549 | | int len; |
| 550 | | int in_len; |
| 551 | | int dptr; |
| 552 | | UINT32 tstart; |
| 553 | | |
| 554 | | start_trk = command[6]; |
| 555 | | if( start_trk == 0 ) |
| 556 | | { |
| 557 | | start_trk = 1; |
| 558 | | } |
| 559 | | |
| 560 | | end_trk = cdrom_get_last_track(cdrom); |
| 561 | | len = (end_trk * 8) + 2; |
| 562 | | |
| 563 | | // the returned TOC DATA LENGTH must be the full amount, |
| 564 | | // regardless of how much we're able to pass back due to in_len |
| 565 | | dptr = 0; |
| 566 | | data[dptr++] = (len>>8) & 0xff; |
| 567 | | data[dptr++] = (len & 0xff); |
| 568 | | data[dptr++] = 1; |
| 569 | | data[dptr++] = end_trk; |
| 570 | | |
| 571 | | if( start_trk == 0xaa ) |
| 572 | | { |
| 573 | | end_trk = 0xaa; |
| 574 | | } |
| 575 | | |
| 576 | | in_len = command[7]<<8 | command[8]; |
| 577 | | |
| 578 | | for (i = start_trk; i <= end_trk; i++) |
| 579 | | { |
| 580 | | int cdrom_track = i; |
| 581 | | if( cdrom_track != 0xaa ) |
| 582 | | { |
| 583 | | cdrom_track--; |
| 584 | | } |
| 585 | | |
| 586 | | if( dptr >= in_len ) |
| 587 | | { |
| 588 | | break; |
| 589 | | } |
| 590 | | |
| 591 | | data[dptr++] = 0; |
| 592 | | data[dptr++] = cdrom_get_adr_control(cdrom, cdrom_track); |
| 593 | | data[dptr++] = i; |
| 594 | | data[dptr++] = 0; |
| 595 | | |
| 596 | | tstart = cdrom_get_track_start(cdrom, cdrom_track); |
| 597 | | if ((command[1]&2)>>1) |
| 598 | | tstart = lba_to_msf(tstart); |
| 599 | | data[dptr++] = (tstart>>24) & 0xff; |
| 600 | | data[dptr++] = (tstart>>16) & 0xff; |
| 601 | | data[dptr++] = (tstart>>8) & 0xff; |
| 602 | | data[dptr++] = (tstart & 0xff); |
| 603 | | } |
| 604 | | } |
| 605 | | break; |
| 606 | | default: |
| 607 | | logerror("SCSICD: Unhandled READ TOC format %d\n", command[2]&0xf); |
| 608 | | break; |
| 609 | | } |
| 610 | | break; |
| 611 | | |
| 612 | | case 0x1a: // MODE SENSE(6) |
| 613 | | case 0x5a: // MODE SENSE(10) |
| 614 | | logerror("SCSICD: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6); |
| 615 | | |
| 616 | | switch (command[2] & 0x3f) |
| 617 | | { |
| 618 | | case 0xe: // CD Audio control page |
| 619 | | data[0] = 0x8e; // page E, parameter is savable |
| 620 | | data[1] = 0x0e; // page length |
| 621 | | data[2] = 0x04; // IMMED = 1, SOTC = 0 |
| 622 | | data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved |
| 623 | | |
| 624 | | // connect each audio channel to 1 output port |
| 625 | | data[8] = 1; |
| 626 | | data[10] = 2; |
| 627 | | data[12] = 4; |
| 628 | | data[14] = 8; |
| 629 | | |
| 630 | | // indicate max volume |
| 631 | | data[9] = data[11] = data[13] = data[15] = 0xff; |
| 632 | | break; |
| 633 | | case 0x2a: // Page capabilities |
| 634 | | data[0] = 0x2a; |
| 635 | | data[1] = 0x14; // page length |
| 636 | | data[2] = 0x00; data[3] = 0x00; // CD-R only |
| 637 | | data[4] = 0x01; // can play audio |
| 638 | | data[5] = 0; |
| 639 | | data[6] = 0; |
| 640 | | data[7] = 0; |
| 641 | | data[8] = 0x02; data[9] = 0xc0; // 4x speed |
| 642 | | data[10] = 0; |
| 643 | | data[11] = 2; // two volumen levels |
| 644 | | data[12] = 0x00; data[13] = 0x00; // buffer |
| 645 | | data[14] = 0x02; data[15] = 0xc0; // 4x read speed |
| 646 | | data[16] = 0; |
| 647 | | data[17] = 0; |
| 648 | | data[18] = 0; |
| 649 | | data[19] = 0; |
| 650 | | data[20] = 0; |
| 651 | | data[21] = 0; |
| 652 | | break; |
| 653 | | |
| 654 | | default: |
| 655 | | logerror("SCSICD: MODE SENSE unknown page %x\n", command[2] & 0x3f); |
| 656 | | break; |
| 657 | | } |
| 658 | | break; |
| 659 | | |
| 660 | | default: |
| 661 | | scsihle_device::ReadData( data, dataLength ); |
| 662 | | break; |
| 663 | | } |
| 664 | | } |
| 665 | | |
| 666 | | // scsicd_write_data |
| 667 | | // |
| 668 | | // Write data to the CD-ROM device as part of the execution of a command |
| 669 | | |
| 670 | | void scsicd_device::WriteData( UINT8 *data, int dataLength ) |
| 671 | | { |
| 672 | | switch (command[ 0 ]) |
| 673 | | { |
| 674 | | case 0x15: // MODE SELECT(6) |
| 675 | | case 0x55: // MODE SELECT(10) |
| 676 | | logerror("SCSICD: MODE SELECT page %x\n", data[0] & 0x3f); |
| 677 | | |
| 678 | | switch (data[0] & 0x3f) |
| 679 | | { |
| 680 | | case 0x0: // vendor-specific |
| 681 | | // check for SGI extension to force 512-byte blocks |
| 682 | | if ((data[3] == 8) && (data[10] == 2)) |
| 683 | | { |
| 684 | | logerror("SCSICD: Experimental SGI 512-byte block extension enabled\n"); |
| 685 | | |
| 686 | | bytes_per_sector = 512; |
| 687 | | num_subblocks = 4; |
| 688 | | } |
| 689 | | else |
| 690 | | { |
| 691 | | logerror("SCSICD: Unknown vendor-specific page!\n"); |
| 692 | | } |
| 693 | | break; |
| 694 | | |
| 695 | | case 0xe: // audio page |
| 696 | | logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]); |
| 697 | | logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]); |
| 698 | | logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]); |
| 699 | | logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]); |
| 700 | | break; |
| 701 | | } |
| 702 | | break; |
| 703 | | |
| 704 | | default: |
| 705 | | scsihle_device::WriteData( data, dataLength ); |
| 706 | | break; |
| 707 | | } |
| 708 | | } |
| 709 | | |
| 710 | | void scsicd_device::GetDevice( void **_cdrom ) |
| 711 | | { |
| 712 | | *(cdrom_file **)_cdrom = cdrom; |
| 713 | | } |
| 714 | | |
| 715 | | void scsicd_device::SetDevice( void *_cdrom ) |
| 716 | | { |
| 717 | | cdrom = (cdrom_file *)_cdrom; |
| 718 | | m_cdda->set_cdrom(cdrom); |
| 719 | | } |
| 720 | | |
| 721 | | int scsicd_device::GetSectorBytes() |
| 722 | | { |
| 723 | | return bytes_per_sector; |
| 724 | | } |
trunk/src/emu/machine/cr589.c
| r25365 | r25366 | |
| 1 | 1 | #include "cr589.h" |
| 2 | | #include "scsicd.h" |
| 3 | | #include "machine/cr589.h" |
| 4 | 2 | |
| 5 | | // device type definition |
| 6 | | const device_type SCSI_CR589 = &device_creator<scsi_cr589_device>; |
| 7 | 3 | |
| 8 | | scsi_cr589_device::scsi_cr589_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 9 | | : scsicd_device(mconfig, SCSI_CR589, "SCSI CR589", tag, owner, clock, "scsi_cr589", __FILE__), |
| 10 | | device_nvram_interface(mconfig, *this) |
| 11 | | { |
| 12 | | } |
| 13 | | |
| 14 | 4 | static const int identity_offset = 0x3ab; |
| 15 | 5 | static const char download_identity[] = "MATSHITA CD98Q4 DOWNLOADGS0N"; |
| 16 | 6 | |
| 17 | | void scsi_cr589_device::device_start() |
| 18 | | { |
| 19 | | scsicd_device::device_start(); |
| 20 | | |
| 21 | | download = 0; |
| 22 | | |
| 23 | | save_item(NAME(download)); |
| 24 | | save_item(NAME(buffer)); |
| 25 | | save_item(NAME(bufferOffset)); |
| 26 | | } |
| 27 | | |
| 28 | | |
| 29 | | |
| 30 | 7 | //------------------------------------------------- |
| 31 | 8 | // nvram_default - called to initialize NVRAM to |
| 32 | 9 | // its default state |
| 33 | 10 | //------------------------------------------------- |
| 34 | 11 | |
| 35 | | void scsi_cr589_device::nvram_default() |
| 12 | void matsushita_cr589_device::nvram_default() |
| 36 | 13 | { |
| 37 | 14 | memset( buffer, 0, sizeof(buffer)); |
| 38 | 15 | memcpy( &buffer[ identity_offset ], "MATSHITACD-ROM CR-589 GS0N", 28 ); |
| r25365 | r25366 | |
| 45 | 22 | // .nv file |
| 46 | 23 | //------------------------------------------------- |
| 47 | 24 | |
| 48 | | void scsi_cr589_device::nvram_read(emu_file &file) |
| 25 | void matsushita_cr589_device::nvram_read(emu_file &file) |
| 49 | 26 | { |
| 50 | 27 | file.read(buffer, sizeof(buffer)); |
| 51 | 28 | } |
| r25365 | r25366 | |
| 57 | 34 | // .nv file |
| 58 | 35 | //------------------------------------------------- |
| 59 | 36 | |
| 60 | | void scsi_cr589_device::nvram_write(emu_file &file) |
| 37 | void matsushita_cr589_device::nvram_write(emu_file &file) |
| 61 | 38 | { |
| 62 | 39 | file.write(buffer, sizeof(buffer)); |
| 63 | 40 | } |
| 64 | 41 | |
| 65 | 42 | |
| 66 | 43 | |
| 67 | | void scsi_cr589_device::ExecCommand( int *transferLength ) |
| 44 | void matsushita_cr589_device::ExecCommand() |
| 68 | 45 | { |
| 69 | 46 | switch( command[ 0 ] ) |
| 70 | 47 | { |
| 71 | 48 | case 0x3b: // WRITE BUFFER |
| 72 | 49 | bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ]; |
| 73 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 74 | | *transferLength = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; |
| 50 | m_phase = SCSI_PHASE_DATAOUT; |
| 51 | m_transfer_length = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; |
| 75 | 52 | break; |
| 76 | 53 | |
| 77 | 54 | case 0x3c: // READ BUFFER |
| 78 | 55 | bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ]; |
| 79 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 80 | | *transferLength = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; |
| 56 | m_phase = SCSI_PHASE_DATAIN; |
| 57 | m_transfer_length = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; |
| 81 | 58 | break; |
| 82 | 59 | |
| 83 | 60 | case 0xcc: // FIRMWARE DOWNLOAD ENABLE |
| 84 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 85 | | *transferLength = SCSILengthFromUINT16( &command[7] ); |
| 61 | m_phase = SCSI_PHASE_DATAOUT; |
| 62 | m_transfer_length = SCSILengthFromUINT16( &command[7] ); |
| 86 | 63 | break; |
| 87 | 64 | |
| 88 | 65 | default: |
| 89 | | scsicd_device::ExecCommand( transferLength ); |
| 66 | t10mmc::ExecCommand(); |
| 90 | 67 | } |
| 91 | 68 | } |
| 92 | 69 | |
| 93 | | void scsi_cr589_device::ReadData( UINT8 *data, int dataLength ) |
| 70 | void matsushita_cr589_device::ReadData( UINT8 *data, int dataLength ) |
| 94 | 71 | { |
| 95 | 72 | switch( command[ 0 ] ) |
| 96 | 73 | { |
| 97 | 74 | case 0x12: // INQUIRY |
| 98 | | scsicd_device::ReadData( data, dataLength ); |
| 75 | t10mmc::ReadData( data, dataLength ); |
| 99 | 76 | |
| 100 | 77 | if( download ) |
| 101 | 78 | { |
| r25365 | r25366 | |
| 113 | 90 | break; |
| 114 | 91 | |
| 115 | 92 | default: |
| 116 | | scsicd_device::ReadData( data, dataLength ); |
| 93 | t10mmc::ReadData( data, dataLength ); |
| 117 | 94 | break; |
| 118 | 95 | } |
| 119 | 96 | } |
| 120 | 97 | |
| 121 | | void scsi_cr589_device::WriteData( UINT8 *data, int dataLength ) |
| 98 | void matsushita_cr589_device::WriteData( UINT8 *data, int dataLength ) |
| 122 | 99 | { |
| 123 | 100 | switch( command[ 0 ] ) |
| 124 | 101 | { |
| r25365 | r25366 | |
| 139 | 116 | break; |
| 140 | 117 | |
| 141 | 118 | default: |
| 142 | | scsicd_device::WriteData( data, dataLength ); |
| 119 | t10mmc::WriteData( data, dataLength ); |
| 143 | 120 | break; |
| 144 | 121 | } |
| 145 | 122 | } |
| r25365 | r25366 | |
| 147 | 124 | // device type definition |
| 148 | 125 | const device_type CR589 = &device_creator<matsushita_cr589_device>; |
| 149 | 126 | |
| 150 | | matsushita_cr589_device::matsushita_cr589_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 151 | | : atapi_hle_device(mconfig, CR589, "Matsushita CR589", tag, owner, clock, "cr589", __FILE__) |
| 127 | matsushita_cr589_device::matsushita_cr589_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 128 | atapi_cdrom_device(mconfig, CR589, "Matsushita CR589", tag, owner, clock, "cr589", __FILE__), |
| 129 | device_nvram_interface(mconfig, *this) |
| 152 | 130 | { |
| 153 | 131 | } |
| 154 | 132 | |
| 155 | | static MACHINE_CONFIG_FRAGMENT( cr589 ) |
| 156 | | MCFG_DEVICE_ADD("device", SCSI_CR589, 0) |
| 157 | | MACHINE_CONFIG_END |
| 158 | | |
| 159 | | //------------------------------------------------- |
| 160 | | // machine_config_additions - device-specific |
| 161 | | // machine configurations |
| 162 | | //------------------------------------------------- |
| 163 | | |
| 164 | | machine_config_constructor matsushita_cr589_device::device_mconfig_additions() const |
| 165 | | { |
| 166 | | return MACHINE_CONFIG_NAME( cr589 ); |
| 167 | | } |
| 168 | | |
| 169 | 133 | void matsushita_cr589_device::device_start() |
| 170 | 134 | { |
| 135 | save_item(NAME(download)); |
| 136 | save_item(NAME(buffer)); |
| 137 | save_item(NAME(bufferOffset)); |
| 138 | |
| 139 | atapi_cdrom_device::device_start(); |
| 140 | |
| 141 | /// TODO: split identify buffer into another method as device_start() should be called after it's filled in, but the atapi_cdrom_device has it's own. |
| 171 | 142 | memset(m_identify_buffer, 0, sizeof(m_identify_buffer)); |
| 172 | 143 | |
| 173 | 144 | m_identify_buffer[ 0 ] = 0x8500; // ATAPI device, cmd set 5 compliant, DRQ within 3 ms of PACKET command |
| r25365 | r25366 | |
| 199 | 170 | m_identify_buffer[ 46 ] = (' ' << 8) | ' '; |
| 200 | 171 | |
| 201 | 172 | m_identify_buffer[ 49 ] = 0x0400; // IORDY may be disabled |
| 202 | | |
| 203 | | atapi_hle_device::device_start(); |
| 204 | 173 | } |
| 205 | 174 | |
| 206 | | void matsushita_cr589_device::perform_diagnostic() |
| 175 | void matsushita_cr589_device::device_reset() |
| 207 | 176 | { |
| 208 | | m_error = IDE_ERROR_DIAGNOSTIC_PASSED; |
| 209 | | } |
| 177 | atapi_cdrom_device::device_reset(); |
| 210 | 178 | |
| 211 | | void matsushita_cr589_device::identify_packet_device() |
| 212 | | { |
| 179 | download = 0; |
| 180 | bufferOffset = 0; |
| 213 | 181 | } |
trunk/src/emu/machine/t10mmc.c
| r0 | r25366 | |
| 1 | #include "t10mmc.h" |
| 2 | |
| 3 | static void phys_frame_to_msf(int phys_frame, int *m, int *s, int *f) |
| 4 | { |
| 5 | *m = phys_frame / (60*75); |
| 6 | phys_frame -= (*m * 60 * 75); |
| 7 | *s = phys_frame / 75; |
| 8 | *f = phys_frame % 75; |
| 9 | } |
| 10 | |
| 11 | void t10mmc::t10_start(device_t &device) |
| 12 | { |
| 13 | t10spc::t10_start(device); |
| 14 | |
| 15 | device.save_item(NAME(lba)); |
| 16 | device.save_item(NAME(blocks)); |
| 17 | device.save_item(NAME(last_lba)); |
| 18 | device.save_item(NAME(num_subblocks)); |
| 19 | device.save_item(NAME(cur_subblock)); |
| 20 | device.save_item(NAME(play_err_flag)); |
| 21 | } |
| 22 | |
| 23 | void t10mmc::t10_reset() |
| 24 | { |
| 25 | t10spc::t10_reset(); |
| 26 | |
| 27 | SetDevice( m_image->get_cdrom_file() ); |
| 28 | if( !cdrom ) |
| 29 | { |
| 30 | logerror( "T10MMC %s: no CD found!\n", m_image->tag() ); |
| 31 | } |
| 32 | |
| 33 | lba = 0; |
| 34 | blocks = 0; |
| 35 | last_lba = 0; |
| 36 | m_sector_bytes = 2048; |
| 37 | num_subblocks = 1; |
| 38 | cur_subblock = 0; |
| 39 | play_err_flag = 0; |
| 40 | } |
| 41 | |
| 42 | // scsicd_exec_command |
| 43 | // |
| 44 | // Execute a SCSI command. |
| 45 | |
| 46 | void t10mmc::ExecCommand() |
| 47 | { |
| 48 | int trk; |
| 49 | |
| 50 | switch ( command[0] ) |
| 51 | { |
| 52 | case 0x03: // REQUEST SENSE |
| 53 | m_phase = SCSI_PHASE_DATAIN; |
| 54 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 55 | break; |
| 56 | |
| 57 | case 0x12: // INQUIRY |
| 58 | logerror("T10MMC: REQUEST SENSE\n"); |
| 59 | m_phase = SCSI_PHASE_DATAIN; |
| 60 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 61 | break; |
| 62 | |
| 63 | case 0x15: // MODE SELECT(6) |
| 64 | logerror("T10MMC: MODE SELECT(6) length %x control %x\n", command[4], command[5]); |
| 65 | m_phase = SCSI_PHASE_DATAOUT; |
| 66 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 67 | break; |
| 68 | |
| 69 | case 0x1a: // MODE SENSE(6) |
| 70 | m_phase = SCSI_PHASE_DATAIN; |
| 71 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 72 | break; |
| 73 | |
| 74 | case 0x1b: // START STOP UNIT |
| 75 | m_cdda->stop_audio(); |
| 76 | m_phase = SCSI_PHASE_STATUS; |
| 77 | m_transfer_length = 0; |
| 78 | break; |
| 79 | |
| 80 | case 0x1e: // PREVENT ALLOW MEDIUM REMOVAL |
| 81 | m_phase = SCSI_PHASE_STATUS; |
| 82 | m_transfer_length = 0; |
| 83 | break; |
| 84 | |
| 85 | case 0x25: // READ CAPACITY |
| 86 | m_phase = SCSI_PHASE_DATAIN; |
| 87 | m_transfer_length = 8; |
| 88 | break; |
| 89 | |
| 90 | case 0x28: // READ(10) |
| 91 | |
| 92 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 93 | blocks = SCSILengthFromUINT16( &command[7] ); |
| 94 | |
| 95 | logerror("T10MMC: READ(10) at LBA %x for %d blocks (%d bytes)\n", lba, blocks, blocks * m_sector_bytes); |
| 96 | |
| 97 | if (num_subblocks > 1) |
| 98 | { |
| 99 | cur_subblock = lba % num_subblocks; |
| 100 | lba /= num_subblocks; |
| 101 | } |
| 102 | else |
| 103 | { |
| 104 | cur_subblock = 0; |
| 105 | } |
| 106 | |
| 107 | m_cdda->stop_audio(); |
| 108 | |
| 109 | m_phase = SCSI_PHASE_DATAIN; |
| 110 | m_transfer_length = blocks * m_sector_bytes; |
| 111 | break; |
| 112 | |
| 113 | case 0x42: // READ SUB-CHANNEL |
| 114 | // logerror("T10MMC: READ SUB-CHANNEL type %d\n", command[3]); |
| 115 | m_phase = SCSI_PHASE_DATAIN; |
| 116 | m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 117 | break; |
| 118 | |
| 119 | case 0x43: // READ TOC |
| 120 | { |
| 121 | int start_trk = command[6]; |
| 122 | int end_trk = cdrom_get_last_track(cdrom); |
| 123 | int length; |
| 124 | int allocation_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 125 | |
| 126 | if( start_trk == 0 ) |
| 127 | { |
| 128 | start_trk = 1; |
| 129 | } |
| 130 | if( start_trk == 0xaa ) |
| 131 | { |
| 132 | end_trk = start_trk; |
| 133 | } |
| 134 | |
| 135 | length = 4 + ( 8 * ( ( end_trk - start_trk ) + 1 ) ); |
| 136 | if( length > allocation_length ) |
| 137 | { |
| 138 | length = allocation_length; |
| 139 | } |
| 140 | else if( length < 4 ) |
| 141 | { |
| 142 | length = 4; |
| 143 | } |
| 144 | |
| 145 | m_cdda->stop_audio(); |
| 146 | |
| 147 | m_phase = SCSI_PHASE_DATAIN; |
| 148 | m_transfer_length = length; |
| 149 | break; |
| 150 | } |
| 151 | case 0x45: // PLAY AUDIO(10) |
| 152 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 153 | blocks = SCSILengthFromUINT16( &command[7] ); |
| 154 | |
| 155 | // special cases: lba of 0 means MSF of 00:02:00 |
| 156 | if (lba == 0) |
| 157 | { |
| 158 | lba = 150; |
| 159 | } |
| 160 | else if (lba == 0xffffffff) |
| 161 | { |
| 162 | logerror("T10MMC: play audio from current not implemented!\n"); |
| 163 | } |
| 164 | |
| 165 | logerror("T10MMC: PLAY AUDIO(10) at LBA %x for %x blocks\n", lba, blocks); |
| 166 | |
| 167 | trk = cdrom_get_track(cdrom, lba); |
| 168 | |
| 169 | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 170 | { |
| 171 | play_err_flag = 0; |
| 172 | m_cdda->start_audio(lba, blocks); |
| 173 | } |
| 174 | else |
| 175 | { |
| 176 | logerror("T10MMC: track is NOT audio!\n"); |
| 177 | play_err_flag = 1; |
| 178 | } |
| 179 | |
| 180 | m_phase = SCSI_PHASE_STATUS; |
| 181 | m_transfer_length = 0; |
| 182 | break; |
| 183 | |
| 184 | case 0x48: // PLAY AUDIO TRACK/INDEX |
| 185 | // be careful: tracks here are zero-based, but the SCSI command |
| 186 | // uses the real CD track number which is 1-based! |
| 187 | lba = cdrom_get_track_start(cdrom, command[4]-1); |
| 188 | blocks = cdrom_get_track_start(cdrom, command[7]-1) - lba; |
| 189 | if (command[4] > command[7]) |
| 190 | { |
| 191 | blocks = 0; |
| 192 | } |
| 193 | |
| 194 | if (command[4] == command[7]) |
| 195 | { |
| 196 | blocks = cdrom_get_track_start(cdrom, command[4]) - lba; |
| 197 | } |
| 198 | |
| 199 | if (blocks && cdrom) |
| 200 | { |
| 201 | m_cdda->start_audio(lba, blocks); |
| 202 | } |
| 203 | |
| 204 | logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], blocks); |
| 205 | m_phase = SCSI_PHASE_STATUS; |
| 206 | m_transfer_length = 0; |
| 207 | break; |
| 208 | |
| 209 | case 0x4b: // PAUSE/RESUME |
| 210 | if (cdrom) |
| 211 | { |
| 212 | m_cdda->pause_audio((command[8] & 0x01) ^ 0x01); |
| 213 | } |
| 214 | |
| 215 | logerror("T10MMC: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE"); |
| 216 | m_phase = SCSI_PHASE_STATUS; |
| 217 | m_transfer_length = 0; |
| 218 | break; |
| 219 | |
| 220 | case 0x4e: // STOP |
| 221 | if (cdrom) |
| 222 | { |
| 223 | m_cdda->stop_audio(); |
| 224 | } |
| 225 | |
| 226 | logerror("T10MMC: STOP_PLAY_SCAN\n"); |
| 227 | m_phase = SCSI_PHASE_STATUS; |
| 228 | m_transfer_length = 0; |
| 229 | break; |
| 230 | |
| 231 | case 0x55: // MODE SELECT(10) |
| 232 | logerror("T10MMC: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]); |
| 233 | m_phase = SCSI_PHASE_DATAOUT; |
| 234 | m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 235 | break; |
| 236 | |
| 237 | case 0x5a: // MODE SENSE(10) |
| 238 | m_phase = SCSI_PHASE_DATAIN; |
| 239 | m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); |
| 240 | break; |
| 241 | |
| 242 | case 0xa5: // PLAY AUDIO(12) |
| 243 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 244 | blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; |
| 245 | |
| 246 | // special cases: lba of 0 means MSF of 00:02:00 |
| 247 | if (lba == 0) |
| 248 | { |
| 249 | lba = 150; |
| 250 | } |
| 251 | else if (lba == 0xffffffff) |
| 252 | { |
| 253 | logerror("T10MMC: play audio from current not implemented!\n"); |
| 254 | } |
| 255 | |
| 256 | logerror("T10MMC: PLAY AUDIO(12) at LBA %x for %x blocks\n", lba, blocks); |
| 257 | |
| 258 | trk = cdrom_get_track(cdrom, lba); |
| 259 | |
| 260 | if (cdrom_get_track_type(cdrom, trk) == CD_TRACK_AUDIO) |
| 261 | { |
| 262 | play_err_flag = 0; |
| 263 | m_cdda->start_audio(lba, blocks); |
| 264 | } |
| 265 | else |
| 266 | { |
| 267 | logerror("T10MMC: track is NOT audio!\n"); |
| 268 | play_err_flag = 1; |
| 269 | } |
| 270 | m_phase = SCSI_PHASE_STATUS; |
| 271 | m_transfer_length = 0; |
| 272 | break; |
| 273 | |
| 274 | case 0xa8: // READ(12) |
| 275 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 276 | blocks = command[7]<<16 | command[8]<<8 | command[9]; |
| 277 | |
| 278 | logerror("T10MMC: READ(12) at LBA %x for %x blocks (%x bytes)\n", lba, blocks, blocks * m_sector_bytes); |
| 279 | |
| 280 | if (num_subblocks > 1) |
| 281 | { |
| 282 | cur_subblock = lba % num_subblocks; |
| 283 | lba /= num_subblocks; |
| 284 | } |
| 285 | else |
| 286 | { |
| 287 | cur_subblock = 0; |
| 288 | } |
| 289 | |
| 290 | m_cdda->stop_audio(); |
| 291 | |
| 292 | m_phase = SCSI_PHASE_DATAIN; |
| 293 | m_transfer_length = blocks * m_sector_bytes; |
| 294 | break; |
| 295 | |
| 296 | case 0xbb: // SET CD SPEED |
| 297 | logerror("T10MMC: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]); |
| 298 | m_phase = SCSI_PHASE_STATUS; |
| 299 | m_transfer_length = 0; |
| 300 | break; |
| 301 | |
| 302 | default: |
| 303 | t10spc::ExecCommand(); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | // scsicd_read_data |
| 308 | // |
| 309 | // Read data from the device resulting from the execution of a command |
| 310 | |
| 311 | void t10mmc::ReadData( UINT8 *data, int dataLength ) |
| 312 | { |
| 313 | int i; |
| 314 | UINT32 last_phys_frame; |
| 315 | UINT32 temp; |
| 316 | UINT8 tmp_buffer[2048]; |
| 317 | |
| 318 | switch ( command[0] ) |
| 319 | { |
| 320 | case 0x03: // REQUEST SENSE |
| 321 | logerror("T10MMC: Reading REQUEST SENSE data\n"); |
| 322 | |
| 323 | memset( data, 0, dataLength ); |
| 324 | |
| 325 | data[0] = 0x71; // deferred error |
| 326 | |
| 327 | if (m_cdda->audio_active()) |
| 328 | { |
| 329 | data[12] = 0x00; |
| 330 | data[13] = 0x11; // AUDIO PLAY OPERATION IN PROGRESS |
| 331 | } |
| 332 | else if (play_err_flag) |
| 333 | { |
| 334 | play_err_flag = 0; |
| 335 | data[12] = 0x64; // ILLEGAL MODE FOR THIS TRACK |
| 336 | data[13] = 0x00; |
| 337 | } |
| 338 | // (else 00/00 means no error to report) |
| 339 | break; |
| 340 | |
| 341 | case 0x12: // INQUIRY |
| 342 | memset( data, 0, dataLength ); |
| 343 | data[0] = 0x05; // device is present, device is CD/DVD (MMC-3) |
| 344 | data[1] = 0x80; // media is removable |
| 345 | data[2] = 0x05; // device complies with SPC-3 standard |
| 346 | data[3] = 0x02; // response data format = SPC-3 standard |
| 347 | // some Konami games freak out if this isn't "Sony", so we'll lie |
| 348 | // this is the actual drive on my Nagano '98 board |
| 349 | strcpy((char *)&data[8], "Sony"); |
| 350 | strcpy((char *)&data[16], "CDU-76S"); |
| 351 | strcpy((char *)&data[32], "1.0"); |
| 352 | break; |
| 353 | |
| 354 | case 0x25: // READ CAPACITY |
| 355 | logerror("T10MMC: READ CAPACITY\n"); |
| 356 | |
| 357 | temp = cdrom_get_track_start(cdrom, 0xaa); |
| 358 | temp--; // return the last used block on the disc |
| 359 | |
| 360 | data[0] = (temp>>24) & 0xff; |
| 361 | data[1] = (temp>>16) & 0xff; |
| 362 | data[2] = (temp>>8) & 0xff; |
| 363 | data[3] = (temp & 0xff); |
| 364 | data[4] = 0; |
| 365 | data[5] = 0; |
| 366 | data[6] = (m_sector_bytes>>8)&0xff; |
| 367 | data[7] = (m_sector_bytes & 0xff); |
| 368 | break; |
| 369 | |
| 370 | case 0x28: // READ(10) |
| 371 | case 0xa8: // READ(12) |
| 372 | logerror("T10MMC: read %x dataLength, \n", dataLength); |
| 373 | if ((cdrom) && (blocks)) |
| 374 | { |
| 375 | while (dataLength > 0) |
| 376 | { |
| 377 | if (!cdrom_read_data(cdrom, lba, tmp_buffer, CD_TRACK_MODE1)) |
| 378 | { |
| 379 | logerror("T10MMC: CD read error!\n"); |
| 380 | } |
| 381 | |
| 382 | logerror("True LBA: %d, buffer half: %d\n", lba, cur_subblock * m_sector_bytes); |
| 383 | |
| 384 | memcpy(data, &tmp_buffer[cur_subblock * m_sector_bytes], m_sector_bytes); |
| 385 | |
| 386 | cur_subblock++; |
| 387 | if (cur_subblock >= num_subblocks) |
| 388 | { |
| 389 | cur_subblock = 0; |
| 390 | |
| 391 | lba++; |
| 392 | blocks--; |
| 393 | } |
| 394 | |
| 395 | last_lba = lba; |
| 396 | dataLength -= m_sector_bytes; |
| 397 | data += m_sector_bytes; |
| 398 | } |
| 399 | } |
| 400 | break; |
| 401 | |
| 402 | case 0x42: // READ SUB-CHANNEL |
| 403 | switch (command[3]) |
| 404 | { |
| 405 | case 1: // return current position |
| 406 | { |
| 407 | int msf; |
| 408 | |
| 409 | if (!cdrom) |
| 410 | { |
| 411 | return; |
| 412 | } |
| 413 | |
| 414 | logerror("T10MMC: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]); |
| 415 | |
| 416 | msf = command[1] & 0x2; |
| 417 | |
| 418 | int audio_active = m_cdda->audio_active(); |
| 419 | if (audio_active) |
| 420 | { |
| 421 | // if audio is playing, get the latest LBA from the CDROM layer |
| 422 | last_lba = m_cdda->get_audio_lba(); |
| 423 | if (m_cdda->audio_paused()) |
| 424 | { |
| 425 | data[1] = 0x12; // audio is paused |
| 426 | } |
| 427 | else |
| 428 | { |
| 429 | data[1] = 0x11; // audio in progress |
| 430 | } |
| 431 | } |
| 432 | else |
| 433 | { |
| 434 | last_lba = 0; |
| 435 | if (m_cdda->audio_ended()) |
| 436 | { |
| 437 | data[1] = 0x13; // ended successfully |
| 438 | } |
| 439 | else |
| 440 | { |
| 441 | // data[1] = 0x14; // stopped due to error |
| 442 | data[1] = 0x15; // No current audio status to return |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | data[2] = 0; |
| 447 | data[3] = 12; // data length |
| 448 | data[4] = 0x01; // sub-channel format code |
| 449 | data[5] = 0x10 | (audio_active ? 0 : 4); |
| 450 | data[6] = cdrom_get_track(cdrom, last_lba) + 1; // track |
| 451 | data[7] = 0; // index |
| 452 | |
| 453 | last_phys_frame = last_lba; |
| 454 | |
| 455 | if (msf) |
| 456 | { |
| 457 | int m,s,f; |
| 458 | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 459 | data[8] = 0; |
| 460 | data[9] = m; |
| 461 | data[10] = s; |
| 462 | data[11] = f; |
| 463 | } |
| 464 | else |
| 465 | { |
| 466 | data[8] = last_phys_frame>>24; |
| 467 | data[9] = (last_phys_frame>>16)&0xff; |
| 468 | data[10] = (last_phys_frame>>8)&0xff; |
| 469 | data[11] = last_phys_frame&0xff; |
| 470 | } |
| 471 | |
| 472 | last_phys_frame -= cdrom_get_track_start(cdrom, data[6] - 1); |
| 473 | |
| 474 | if (msf) |
| 475 | { |
| 476 | int m,s,f; |
| 477 | phys_frame_to_msf(last_phys_frame, &m, &s, &f); |
| 478 | data[12] = 0; |
| 479 | data[13] = m; |
| 480 | data[14] = s; |
| 481 | data[15] = f; |
| 482 | } |
| 483 | else |
| 484 | { |
| 485 | data[12] = last_phys_frame>>24; |
| 486 | data[13] = (last_phys_frame>>16)&0xff; |
| 487 | data[14] = (last_phys_frame>>8)&0xff; |
| 488 | data[15] = last_phys_frame&0xff; |
| 489 | } |
| 490 | break; |
| 491 | } |
| 492 | default: |
| 493 | logerror("T10MMC: Unknown subchannel type %d requested\n", command[3]); |
| 494 | } |
| 495 | break; |
| 496 | |
| 497 | case 0x43: // READ TOC |
| 498 | /* |
| 499 | Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out. |
| 500 | That makes sense in terms of how real-world CDs are referred to, but |
| 501 | our internal routines for tracks use "0" as track 1. That probably |
| 502 | should be fixed... |
| 503 | */ |
| 504 | logerror("T10MMC: READ TOC, format = %d time=%d\n", command[2]&0xf,(command[1]>>1)&1); |
| 505 | switch (command[2] & 0x0f) |
| 506 | { |
| 507 | case 0: // normal |
| 508 | { |
| 509 | int start_trk; |
| 510 | int end_trk; |
| 511 | int len; |
| 512 | int in_len; |
| 513 | int dptr; |
| 514 | UINT32 tstart; |
| 515 | |
| 516 | start_trk = command[6]; |
| 517 | if( start_trk == 0 ) |
| 518 | { |
| 519 | start_trk = 1; |
| 520 | } |
| 521 | |
| 522 | end_trk = cdrom_get_last_track(cdrom); |
| 523 | len = (end_trk * 8) + 2; |
| 524 | |
| 525 | // the returned TOC DATA LENGTH must be the full amount, |
| 526 | // regardless of how much we're able to pass back due to in_len |
| 527 | dptr = 0; |
| 528 | data[dptr++] = (len>>8) & 0xff; |
| 529 | data[dptr++] = (len & 0xff); |
| 530 | data[dptr++] = 1; |
| 531 | data[dptr++] = end_trk; |
| 532 | |
| 533 | if( start_trk == 0xaa ) |
| 534 | { |
| 535 | end_trk = 0xaa; |
| 536 | } |
| 537 | |
| 538 | in_len = command[7]<<8 | command[8]; |
| 539 | |
| 540 | for (i = start_trk; i <= end_trk; i++) |
| 541 | { |
| 542 | int cdrom_track = i; |
| 543 | if( cdrom_track != 0xaa ) |
| 544 | { |
| 545 | cdrom_track--; |
| 546 | } |
| 547 | |
| 548 | if( dptr >= in_len ) |
| 549 | { |
| 550 | break; |
| 551 | } |
| 552 | |
| 553 | data[dptr++] = 0; |
| 554 | data[dptr++] = cdrom_get_adr_control(cdrom, cdrom_track); |
| 555 | data[dptr++] = i; |
| 556 | data[dptr++] = 0; |
| 557 | |
| 558 | tstart = cdrom_get_track_start(cdrom, cdrom_track); |
| 559 | if ((command[1]&2)>>1) |
| 560 | tstart = lba_to_msf(tstart); |
| 561 | data[dptr++] = (tstart>>24) & 0xff; |
| 562 | data[dptr++] = (tstart>>16) & 0xff; |
| 563 | data[dptr++] = (tstart>>8) & 0xff; |
| 564 | data[dptr++] = (tstart & 0xff); |
| 565 | } |
| 566 | } |
| 567 | break; |
| 568 | default: |
| 569 | logerror("T10MMC: Unhandled READ TOC format %d\n", command[2]&0xf); |
| 570 | break; |
| 571 | } |
| 572 | break; |
| 573 | |
| 574 | case 0x1a: // MODE SENSE(6) |
| 575 | case 0x5a: // MODE SENSE(10) |
| 576 | logerror("T10MMC: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6); |
| 577 | |
| 578 | memset(data, 0, SCSILengthFromUINT16( &command[ 7 ] )); |
| 579 | |
| 580 | switch (command[2] & 0x3f) |
| 581 | { |
| 582 | case 0xe: // CD Audio control page |
| 583 | data[0] = 0x8e; // page E, parameter is savable |
| 584 | data[1] = 0x0e; // page length |
| 585 | data[2] = 0x04; // IMMED = 1, SOTC = 0 |
| 586 | data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved |
| 587 | |
| 588 | // connect each audio channel to 1 output port |
| 589 | data[8] = 1; |
| 590 | data[10] = 2; |
| 591 | data[12] = 4; |
| 592 | data[14] = 8; |
| 593 | |
| 594 | // indicate max volume |
| 595 | data[9] = data[11] = data[13] = data[15] = 0xff; |
| 596 | break; |
| 597 | case 0x2a: // Page capabilities |
| 598 | data[0] = 0x2a; |
| 599 | data[1] = 0x14; // page length |
| 600 | data[2] = 0x00; data[3] = 0x00; // CD-R only |
| 601 | data[4] = 0x01; // can play audio |
| 602 | data[5] = 0; |
| 603 | data[6] = 0; |
| 604 | data[7] = 0; |
| 605 | data[8] = 0x02; data[9] = 0xc0; // 4x speed |
| 606 | data[10] = 0; |
| 607 | data[11] = 2; // two volumen levels |
| 608 | data[12] = 0x00; data[13] = 0x00; // buffer |
| 609 | data[14] = 0x02; data[15] = 0xc0; // 4x read speed |
| 610 | data[16] = 0; |
| 611 | data[17] = 0; |
| 612 | data[18] = 0; |
| 613 | data[19] = 0; |
| 614 | data[20] = 0; |
| 615 | data[21] = 0; |
| 616 | break; |
| 617 | |
| 618 | default: |
| 619 | logerror("T10MMC: MODE SENSE unknown page %x\n", command[2] & 0x3f); |
| 620 | break; |
| 621 | } |
| 622 | break; |
| 623 | |
| 624 | default: |
| 625 | t10spc::ReadData( data, dataLength ); |
| 626 | break; |
| 627 | } |
| 628 | } |
| 629 | |
| 630 | // scsicd_write_data |
| 631 | // |
| 632 | // Write data to the CD-ROM device as part of the execution of a command |
| 633 | |
| 634 | void t10mmc::WriteData( UINT8 *data, int dataLength ) |
| 635 | { |
| 636 | switch (command[ 0 ]) |
| 637 | { |
| 638 | case 0x15: // MODE SELECT(6) |
| 639 | case 0x55: // MODE SELECT(10) |
| 640 | logerror("T10MMC: MODE SELECT page %x\n", data[0] & 0x3f); |
| 641 | |
| 642 | switch (data[0] & 0x3f) |
| 643 | { |
| 644 | case 0x0: // vendor-specific |
| 645 | // check for SGI extension to force 512-byte blocks |
| 646 | if ((data[3] == 8) && (data[10] == 2)) |
| 647 | { |
| 648 | logerror("T10MMC: Experimental SGI 512-byte block extension enabled\n"); |
| 649 | |
| 650 | m_sector_bytes = 512; |
| 651 | num_subblocks = 4; |
| 652 | } |
| 653 | else |
| 654 | { |
| 655 | logerror("T10MMC: Unknown vendor-specific page!\n"); |
| 656 | } |
| 657 | break; |
| 658 | |
| 659 | case 0xe: // audio page |
| 660 | logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]); |
| 661 | logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]); |
| 662 | logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]); |
| 663 | logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]); |
| 664 | break; |
| 665 | } |
| 666 | break; |
| 667 | |
| 668 | default: |
| 669 | t10spc::WriteData( data, dataLength ); |
| 670 | break; |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | void t10mmc::GetDevice( void **_cdrom ) |
| 675 | { |
| 676 | *(cdrom_file **)_cdrom = cdrom; |
| 677 | } |
| 678 | |
| 679 | void t10mmc::SetDevice( void *_cdrom ) |
| 680 | { |
| 681 | cdrom = (cdrom_file *)_cdrom; |
| 682 | m_cdda->set_cdrom(cdrom); |
| 683 | } |
trunk/src/emu/machine/scsihle.c
| r25365 | r25366 | |
| 16 | 16 | void scsihle_device::device_start() |
| 17 | 17 | { |
| 18 | 18 | scsidev_device::device_start(); |
| 19 | t10_start(*this); |
| 19 | 20 | |
| 20 | 21 | req_timer = timer_alloc(0); |
| 21 | 22 | sel_timer = timer_alloc(1); |
| 22 | 23 | dataout_timer = timer_alloc(2); |
| 23 | | |
| 24 | | save_item( NAME( command ) ); |
| 25 | | save_item( NAME( commandLength ) ); |
| 26 | | save_item( NAME( phase ) ); |
| 27 | | |
| 28 | | // Start with bus free |
| 29 | | phase = SCSI_PHASE_BUS_FREE; |
| 30 | 24 | } |
| 31 | 25 | |
| 32 | | #define SCSI_SENSE_SIZE 4 |
| 33 | | |
| 34 | | void scsihle_device::ExecCommand( int *transferLength ) |
| 26 | void scsihle_device::device_reset() |
| 35 | 27 | { |
| 36 | | switch( command[ 0 ] ) |
| 37 | | { |
| 38 | | case SCSI_CMD_TEST_UNIT_READY: |
| 39 | | SetPhase( SCSI_PHASE_STATUS ); |
| 40 | | *transferLength = 0; |
| 41 | | break; |
| 42 | | |
| 43 | | case SCSI_CMD_RECALIBRATE: |
| 44 | | SetPhase( SCSI_PHASE_STATUS ); |
| 45 | | *transferLength = 0; |
| 46 | | break; |
| 47 | | |
| 48 | | case SCSI_CMD_REQUEST_SENSE: |
| 49 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 50 | | *transferLength = SCSI_SENSE_SIZE; |
| 51 | | break; |
| 52 | | |
| 53 | | case SCSI_CMD_SEND_DIAGNOSTIC: |
| 54 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 55 | | *transferLength = ( command[ 3 ] << 8 ) + command[ 4 ]; |
| 56 | | break; |
| 57 | | |
| 58 | | default: |
| 59 | | logerror( "%s: SCSIDEV unknown command %02x\n", machine().describe_context(), command[ 0 ] ); |
| 60 | | *transferLength = 0; |
| 61 | | break; |
| 62 | | } |
| 28 | t10_reset(); |
| 63 | 29 | } |
| 64 | 30 | |
| 65 | | void scsihle_device::ReadData( UINT8 *data, int dataLength ) |
| 66 | | { |
| 67 | | switch( command[ 0 ] ) |
| 68 | | { |
| 69 | | case SCSI_CMD_REQUEST_SENSE: |
| 70 | | data[ 0 ] = SCSI_SENSE_NO_SENSE; |
| 71 | | data[ 1 ] = 0x00; |
| 72 | | data[ 2 ] = 0x00; |
| 73 | | data[ 3 ] = 0x00; |
| 74 | | break; |
| 75 | | default: |
| 76 | | logerror( "%s: SCSIDEV unknown read %02x\n", machine().describe_context(), command[ 0 ] ); |
| 77 | | break; |
| 78 | | } |
| 79 | | } |
| 80 | | |
| 81 | | void scsihle_device::WriteData( UINT8 *data, int dataLength ) |
| 82 | | { |
| 83 | | switch( command[ 0 ] ) |
| 84 | | { |
| 85 | | case SCSI_CMD_SEND_DIAGNOSTIC: |
| 86 | | break; |
| 87 | | |
| 88 | | default: |
| 89 | | logerror( "%s: SCSIDEV unknown write %02x\n", machine().describe_context(), command[ 0 ] ); |
| 90 | | break; |
| 91 | | } |
| 92 | | } |
| 93 | | |
| 94 | | void scsihle_device::SetPhase( int _phase ) |
| 95 | | { |
| 96 | | phase = _phase; |
| 97 | | } |
| 98 | | |
| 99 | | void scsihle_device::GetPhase( int *_phase) |
| 100 | | { |
| 101 | | *_phase = phase; |
| 102 | | } |
| 103 | | |
| 104 | | void scsihle_device::SetCommand( UINT8 *_command, int _commandLength ) |
| 105 | | { |
| 106 | | if( _commandLength > sizeof( command ) ) |
| 107 | | { |
| 108 | | /// TODO: output an error. |
| 109 | | return; |
| 110 | | } |
| 111 | | |
| 112 | | memcpy( command, _command, _commandLength ); |
| 113 | | commandLength = _commandLength; |
| 114 | | |
| 115 | | SetPhase( SCSI_PHASE_COMMAND ); |
| 116 | | } |
| 117 | | |
| 118 | 31 | int scsihle_device::GetDeviceID() |
| 119 | 32 | { |
| 120 | 33 | return scsiID; |
| r25365 | r25366 | |
| 126 | 39 | scsidev.scsiID = _scsiID; |
| 127 | 40 | } |
| 128 | 41 | |
| 129 | | int SCSILengthFromUINT8( UINT8 *length ) |
| 130 | | { |
| 131 | | if( *length == 0 ) |
| 132 | | { |
| 133 | | return 256; |
| 134 | | } |
| 135 | | |
| 136 | | return *length; |
| 137 | | } |
| 138 | | |
| 139 | | int SCSILengthFromUINT16( UINT8 *length ) |
| 140 | | { |
| 141 | | return ( *(length) << 8 ) | *(length + 1 ); |
| 142 | | } |
| 143 | | |
| 144 | 42 | #define BSY_DELAY_NS 50 |
| 145 | 43 | #define REQ_DELAY_NS 90 |
| 146 | 44 | |
| r25365 | r25366 | |
| 160 | 58 | |
| 161 | 59 | |
| 162 | 60 | #define IS_COMMAND(cmd) (command[0]==cmd) |
| 163 | | #define IS_READ_COMMAND() ((command[0]==0x08) || (command[0]==0x28) || (command[0]==0xa8)) |
| 164 | | #define IS_WRITE_COMMAND() ((command[0]==0x0a) || (command[0]==0x2a)) |
| 165 | 61 | |
| 166 | 62 | #define FORMAT_UNIT_TIMEOUT 5 |
| 167 | 63 | |
| r25365 | r25366 | |
| 231 | 127 | |
| 232 | 128 | void scsihle_device::scsibus_read_data() |
| 233 | 129 | { |
| 234 | | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 130 | data_last = (bytes_left >= m_sector_bytes) ? m_sector_bytes : bytes_left; |
| 235 | 131 | |
| 236 | 132 | LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last); |
| 237 | 133 | |
| r25365 | r25366 | |
| 284 | 180 | void scsihle_device::scsibus_exec_command() |
| 285 | 181 | { |
| 286 | 182 | int command_local = 0; |
| 287 | | int newphase; |
| 288 | 183 | |
| 289 | 184 | if(LOGLEVEL) |
| 290 | 185 | dump_command_bytes(); |
| r25365 | r25366 | |
| 300 | 195 | LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10)); |
| 301 | 196 | command_local=1; |
| 302 | 197 | if((command[1] & 0x10)==0x10) |
| 303 | | SetPhase(SCSI_PHASE_DATAOUT); |
| 198 | m_phase = SCSI_PHASE_DATAOUT; |
| 304 | 199 | else |
| 305 | | SetPhase(SCSI_PHASE_STATUS); |
| 200 | m_phase = SCSI_PHASE_STATUS; |
| 306 | 201 | |
| 307 | 202 | bytes_left=4; |
| 308 | 203 | dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT)); |
| r25365 | r25366 | |
| 312 | 207 | LOG(1,"SCSIBUS: Search_data_equaln"); |
| 313 | 208 | command_local=1; |
| 314 | 209 | bytes_left=0; |
| 315 | | SetPhase(SCSI_PHASE_STATUS); |
| 210 | m_phase = SCSI_PHASE_STATUS; |
| 316 | 211 | break; |
| 317 | 212 | |
| 318 | 213 | case SCSI_CMD_READ_DEFECT: |
| r25365 | r25366 | |
| 325 | 220 | buffer[4] = 0x00; // defect list len lsb |
| 326 | 221 | |
| 327 | 222 | bytes_left=4; |
| 328 | | SetPhase(SCSI_PHASE_DATAIN); |
| 223 | m_phase = SCSI_PHASE_DATAIN; |
| 329 | 224 | break; |
| 330 | 225 | |
| 331 | 226 | // write buffer |
| r25365 | r25366 | |
| 333 | 228 | LOG(1,"SCSIBUS: write_buffer\n"); |
| 334 | 229 | command_local=1; |
| 335 | 230 | bytes_left=(command[7]<<8)+command[8]; |
| 336 | | SetPhase(SCSI_PHASE_DATAOUT); |
| 231 | m_phase = SCSI_PHASE_DATAOUT; |
| 337 | 232 | break; |
| 338 | 233 | |
| 339 | 234 | // read buffer |
| r25365 | r25366 | |
| 341 | 236 | LOG(1,"SCSIBUS: read_buffer\n"); |
| 342 | 237 | command_local=1; |
| 343 | 238 | bytes_left=(command[7]<<8)+command[8]; |
| 344 | | SetPhase(SCSI_PHASE_DATAIN); |
| 239 | m_phase = SCSI_PHASE_DATAIN; |
| 345 | 240 | break; |
| 346 | 241 | } |
| 347 | 242 | |
| r25365 | r25366 | |
| 351 | 246 | if(!command_local) |
| 352 | 247 | { |
| 353 | 248 | SetCommand(command, cmd_idx); |
| 354 | | ExecCommand(&bytes_left); |
| 249 | ExecCommand(); |
| 250 | GetLength(&bytes_left); |
| 355 | 251 | data_idx=0; |
| 356 | 252 | } |
| 357 | 253 | |
| 358 | | GetPhase(&newphase); |
| 254 | scsi_change_phase(m_phase); |
| 359 | 255 | |
| 360 | | scsi_change_phase(newphase); |
| 361 | | |
| 362 | 256 | LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); |
| 363 | 257 | |
| 364 | 258 | // This is correct as we need to read from disk for commands other than just read data |
| 365 | | if ((phase == SCSI_PHASE_DATAIN) && (!command_local)) |
| 259 | if ((m_phase == SCSI_PHASE_DATAIN) && (!command_local)) |
| 366 | 260 | scsibus_read_data(); |
| 367 | 261 | } |
| 368 | 262 | |
| r25365 | r25366 | |
| 384 | 278 | |
| 385 | 279 | void scsihle_device::scsi_change_phase(UINT8 newphase) |
| 386 | 280 | { |
| 387 | | LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[phase],phasenames[newphase]); |
| 281 | LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[m_phase],phasenames[newphase]); |
| 388 | 282 | |
| 389 | | phase=newphase; |
| 283 | m_phase=newphase; |
| 390 | 284 | cmd_idx=0; |
| 391 | 285 | data_idx=0; |
| 392 | 286 | |
| 393 | | switch(phase) |
| 287 | switch(m_phase) |
| 394 | 288 | { |
| 395 | 289 | case SCSI_PHASE_BUS_FREE: |
| 396 | 290 | scsi_out( 0, SCSI_MASK_ALL ); |
| r25365 | r25366 | |
| 443 | 337 | return; |
| 444 | 338 | } |
| 445 | 339 | |
| 446 | | switch (phase) |
| 340 | switch (m_phase) |
| 447 | 341 | { |
| 448 | 342 | case SCSI_PHASE_BUS_FREE: |
| 449 | 343 | // Note this assumes we only have one initiator and therefore |
| r25365 | r25366 | |
| 458 | 352 | { |
| 459 | 353 | if( ( data & SCSI_MASK_SEL ) == 0 ) |
| 460 | 354 | { |
| 461 | | sectorbytes = GetSectorBytes(); |
| 462 | 355 | scsi_change_phase(SCSI_PHASE_COMMAND); |
| 463 | 356 | } |
| 464 | 357 | else |
| r25365 | r25366 | |
| 500 | 393 | { |
| 501 | 394 | // check to see if we have reached the end of the block buffer |
| 502 | 395 | // and that there is more data to read from the scsi disk |
| 503 | | if(data_idx==sectorbytes) |
| 396 | if(data_idx == m_sector_bytes) |
| 504 | 397 | { |
| 505 | 398 | scsibus_read_data(); |
| 506 | 399 | } |
| r25365 | r25366 | |
| 548 | 441 | |
| 549 | 442 | // If the data buffer is full flush it to the SCSI disk |
| 550 | 443 | |
| 551 | | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 444 | data_last = (bytes_left >= m_sector_bytes) ? m_sector_bytes : bytes_left; |
| 552 | 445 | |
| 553 | 446 | if(data_idx == data_last) |
| 554 | 447 | scsibus_write_data(); |
trunk/src/emu/machine/t10sbc.c
| r0 | r25366 | |
| 1 | #include "t10sbc.h" |
| 2 | |
| 3 | void t10sbc::t10_start(device_t &device) |
| 4 | { |
| 5 | t10spc::t10_start(device); |
| 6 | |
| 7 | device.save_item( NAME( lba ) ); |
| 8 | device.save_item( NAME( blocks ) ); |
| 9 | } |
| 10 | |
| 11 | void t10sbc::t10_reset() |
| 12 | { |
| 13 | t10spc::t10_reset(); |
| 14 | |
| 15 | disk = m_image->get_hard_disk_file(); |
| 16 | if (!disk) |
| 17 | { |
| 18 | logerror("T10SBC %s: no HD found!\n", m_image->owner()->tag()); |
| 19 | } |
| 20 | else |
| 21 | { |
| 22 | // get hard disk sector size from CHD metadata |
| 23 | const hard_disk_info *hdinfo = hard_disk_get_info(disk); |
| 24 | m_sector_bytes = hdinfo->sectorbytes; |
| 25 | } |
| 26 | |
| 27 | lba = 0; |
| 28 | blocks = 0; |
| 29 | m_sector_bytes = 512; |
| 30 | } |
| 31 | |
| 32 | // scsihd_exec_command |
| 33 | void t10sbc::ExecCommand() |
| 34 | { |
| 35 | switch ( command[0] ) |
| 36 | { |
| 37 | case 0x03: // REQUEST SENSE |
| 38 | m_phase = SCSI_PHASE_DATAIN; |
| 39 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 40 | break; |
| 41 | |
| 42 | case 0x04: // FORMAT UNIT |
| 43 | m_phase = SCSI_PHASE_STATUS; |
| 44 | m_transfer_length = 0; |
| 45 | break; |
| 46 | |
| 47 | case 0x08: // READ(6) |
| 48 | lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; |
| 49 | blocks = SCSILengthFromUINT8( &command[4] ); |
| 50 | |
| 51 | logerror("T10SBC: READ at LBA %x for %x blocks\n", lba, blocks); |
| 52 | |
| 53 | m_phase = SCSI_PHASE_DATAIN; |
| 54 | m_transfer_length = blocks * m_sector_bytes; |
| 55 | break; |
| 56 | |
| 57 | case 0x0a: // WRITE(6) |
| 58 | lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; |
| 59 | blocks = SCSILengthFromUINT8( &command[4] ); |
| 60 | |
| 61 | logerror("T10SBC: WRITE to LBA %x for %x blocks\n", lba, blocks); |
| 62 | |
| 63 | m_phase = SCSI_PHASE_DATAOUT; |
| 64 | m_transfer_length = blocks * m_sector_bytes; |
| 65 | break; |
| 66 | |
| 67 | case 0x12: // INQUIRY |
| 68 | m_phase = SCSI_PHASE_DATAIN; |
| 69 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 70 | break; |
| 71 | |
| 72 | case 0x15: // MODE SELECT (used to set CDDA volume) |
| 73 | logerror("T10SBC: MODE SELECT length %x control %x\n", command[4], command[5]); |
| 74 | m_phase = SCSI_PHASE_DATAOUT; |
| 75 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 76 | break; |
| 77 | |
| 78 | case 0x1a: // MODE SENSE(6) |
| 79 | m_phase = SCSI_PHASE_DATAIN; |
| 80 | m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); |
| 81 | break; |
| 82 | |
| 83 | case 0x25: // READ CAPACITY |
| 84 | m_phase = SCSI_PHASE_DATAIN; |
| 85 | m_transfer_length = 8; |
| 86 | break; |
| 87 | |
| 88 | case 0x28: // READ(10) |
| 89 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 90 | blocks = SCSILengthFromUINT16( &command[7] ); |
| 91 | |
| 92 | logerror("T10SBC: READ at LBA %x for %x blocks\n", lba, blocks); |
| 93 | |
| 94 | m_phase = SCSI_PHASE_DATAIN; |
| 95 | m_transfer_length = blocks * m_sector_bytes; |
| 96 | break; |
| 97 | |
| 98 | case 0x2a: // WRITE (10) |
| 99 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 100 | blocks = SCSILengthFromUINT16( &command[7] ); |
| 101 | |
| 102 | logerror("T10SBC: WRITE to LBA %x for %x blocks\n", lba, blocks); |
| 103 | |
| 104 | m_phase = SCSI_PHASE_DATAOUT; |
| 105 | m_transfer_length = blocks * m_sector_bytes; |
| 106 | break; |
| 107 | |
| 108 | case 0xa8: // READ(12) |
| 109 | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 110 | blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; |
| 111 | |
| 112 | logerror("T10SBC: READ at LBA %x for %x blocks\n", lba, blocks); |
| 113 | |
| 114 | m_phase = SCSI_PHASE_DATAIN; |
| 115 | m_transfer_length = blocks * m_sector_bytes; |
| 116 | break; |
| 117 | |
| 118 | default: |
| 119 | t10spc::ExecCommand(); |
| 120 | break; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | void t10sbc::ReadData( UINT8 *data, int dataLength ) |
| 125 | { |
| 126 | int i; |
| 127 | |
| 128 | // if we're a drive without a disk, return all zeroes |
| 129 | if (!disk) |
| 130 | { |
| 131 | memset(data, 0, dataLength); |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | switch ( command[0] ) |
| 136 | { |
| 137 | case 0x03: // REQUEST SENSE |
| 138 | data[0] = 0x80; // valid sense |
| 139 | for (i = 1; i < 12; i++) |
| 140 | { |
| 141 | data[i] = 0; |
| 142 | } |
| 143 | break; |
| 144 | |
| 145 | case 0x12: // INQUIRY |
| 146 | memset( data, 0, dataLength ); |
| 147 | data[0] = 0x00; // device is direct-access (e.g. hard disk) |
| 148 | data[1] = 0x00; // media is not removable |
| 149 | data[2] = 0x05; // device complies with SPC-3 standard |
| 150 | data[3] = 0x02; // response data format = SPC-3 standard |
| 151 | // Apple HD SC setup utility needs to see this |
| 152 | strcpy((char *)&data[8], " SEAGATE"); |
| 153 | strcpy((char *)&data[16], " ST225N"); |
| 154 | strcpy((char *)&data[32], "1.0"); |
| 155 | break; |
| 156 | |
| 157 | case 0x1a: // MODE SENSE (6 byte) |
| 158 | // special Apple ID page. this is a vendor-specific page, |
| 159 | // so unless collisions occur there should be no need |
| 160 | // to change it. |
| 161 | if ((command[2] & 0x3f) == 0x30) |
| 162 | { |
| 163 | memset(data, 0, 40); |
| 164 | data[0] = 0x14; |
| 165 | strcpy((char *)&data[14], "APPLE COMPUTER, INC."); |
| 166 | } |
| 167 | break; |
| 168 | |
| 169 | case 0x08: // READ(6) |
| 170 | case 0x28: // READ(10) |
| 171 | case 0xa8: // READ(12) |
| 172 | if ((disk) && (blocks)) |
| 173 | { |
| 174 | while (dataLength > 0) |
| 175 | { |
| 176 | if (!hard_disk_read(disk, lba, data)) |
| 177 | { |
| 178 | logerror("T10SBC: HD read error!\n"); |
| 179 | } |
| 180 | lba++; |
| 181 | blocks--; |
| 182 | dataLength -= m_sector_bytes; |
| 183 | data += m_sector_bytes; |
| 184 | } |
| 185 | } |
| 186 | break; |
| 187 | |
| 188 | |
| 189 | case 0x25: // READ CAPACITY |
| 190 | { |
| 191 | hard_disk_info *info; |
| 192 | UINT32 temp; |
| 193 | |
| 194 | info = hard_disk_get_info(disk); |
| 195 | |
| 196 | logerror("T10SBC: READ CAPACITY\n"); |
| 197 | |
| 198 | // get # of sectors |
| 199 | temp = info->cylinders * info->heads * info->sectors; |
| 200 | temp--; |
| 201 | |
| 202 | data[0] = (temp>>24) & 0xff; |
| 203 | data[1] = (temp>>16) & 0xff; |
| 204 | data[2] = (temp>>8) & 0xff; |
| 205 | data[3] = (temp & 0xff); |
| 206 | data[4] = (info->sectorbytes>>24)&0xff; |
| 207 | data[5] = (info->sectorbytes>>16)&0xff; |
| 208 | data[6] = (info->sectorbytes>>8)&0xff; |
| 209 | data[7] = (info->sectorbytes & 0xff); |
| 210 | } |
| 211 | break; |
| 212 | |
| 213 | default: |
| 214 | t10spc::ReadData( data, dataLength ); |
| 215 | break; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | void t10sbc::WriteData( UINT8 *data, int dataLength ) |
| 220 | { |
| 221 | if (!disk) |
| 222 | { |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | switch ( command[0] ) |
| 227 | { |
| 228 | case 0x0a: // WRITE(6) |
| 229 | case 0x2a: // WRITE(10) |
| 230 | if ((disk) && (blocks)) |
| 231 | { |
| 232 | while (dataLength > 0) |
| 233 | { |
| 234 | if (!hard_disk_write(disk, lba, data)) |
| 235 | { |
| 236 | logerror("T10SBC: HD write error!\n"); |
| 237 | } |
| 238 | lba++; |
| 239 | blocks--; |
| 240 | dataLength -= m_sector_bytes; |
| 241 | data += m_sector_bytes; |
| 242 | } |
| 243 | } |
| 244 | break; |
| 245 | |
| 246 | default: |
| 247 | t10spc::WriteData( data, dataLength ); |
| 248 | break; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | void t10sbc::GetDevice( void **_disk ) |
| 253 | { |
| 254 | *(hard_disk_file **)_disk = disk; |
| 255 | } |
| 256 | |
| 257 | void t10sbc::SetDevice( void *_disk ) |
| 258 | { |
| 259 | disk = (hard_disk_file *)_disk; |
| 260 | } |
trunk/src/emu/machine/scsihd.c
| r25365 | r25366 | |
| 4 | 4 | |
| 5 | 5 | ***************************************************************************/ |
| 6 | 6 | |
| 7 | | #include "emu.h" |
| 8 | | #include "machine/scsihle.h" |
| 9 | | #include "harddisk.h" |
| 10 | | #include "imagedev/harddriv.h" |
| 11 | 7 | #include "scsihd.h" |
| 12 | 8 | |
| 13 | 9 | // device type definition |
| r25365 | r25366 | |
| 25 | 21 | |
| 26 | 22 | void scsihd_device::device_start() |
| 27 | 23 | { |
| 28 | | scsihle_device::device_start(); |
| 24 | m_image = subdevice<harddisk_image_device>("image"); |
| 29 | 25 | |
| 30 | | save_item( NAME( lba ) ); |
| 31 | | save_item( NAME( blocks ) ); |
| 26 | scsihle_device::device_start(); |
| 32 | 27 | } |
| 33 | 28 | |
| 34 | | void scsihd_device::device_reset() |
| 35 | | { |
| 36 | | scsihle_device::device_reset(); |
| 37 | | |
| 38 | | lba = 0; |
| 39 | | blocks = 0; |
| 40 | | sectorbytes = 512; |
| 41 | | |
| 42 | | disk = subdevice<harddisk_image_device>("image")->get_hard_disk_file(); |
| 43 | | if (!disk) |
| 44 | | { |
| 45 | | logerror("%s SCSIHD: no HD found!\n", tag()); |
| 46 | | } |
| 47 | | else |
| 48 | | { |
| 49 | | // get hard disk sector size from CHD metadata |
| 50 | | const hard_disk_info *hdinfo = hard_disk_get_info(disk); |
| 51 | | sectorbytes = hdinfo->sectorbytes; |
| 52 | | } |
| 53 | | } |
| 54 | | |
| 55 | 29 | harddisk_interface scsihd_device::hd_intf = { NULL, NULL, "scsi_hdd", NULL }; |
| 56 | 30 | |
| 57 | 31 | static MACHINE_CONFIG_FRAGMENT(scsi_harddisk) |
| r25365 | r25366 | |
| 62 | 36 | { |
| 63 | 37 | return MACHINE_CONFIG_NAME(scsi_harddisk); |
| 64 | 38 | } |
| 65 | | |
| 66 | | // scsihd_exec_command |
| 67 | | void scsihd_device::ExecCommand( int *transferLength ) |
| 68 | | { |
| 69 | | switch ( command[0] ) |
| 70 | | { |
| 71 | | case 0x03: // REQUEST SENSE |
| 72 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 73 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 74 | | break; |
| 75 | | |
| 76 | | case 0x04: // FORMAT UNIT |
| 77 | | SetPhase( SCSI_PHASE_STATUS ); |
| 78 | | *transferLength = 0; |
| 79 | | break; |
| 80 | | |
| 81 | | case 0x08: // READ(6) |
| 82 | | lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; |
| 83 | | blocks = SCSILengthFromUINT8( &command[4] ); |
| 84 | | |
| 85 | | logerror("SCSIHD: READ at LBA %x for %x blocks\n", lba, blocks); |
| 86 | | |
| 87 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 88 | | *transferLength = blocks * sectorbytes; |
| 89 | | break; |
| 90 | | |
| 91 | | case 0x0a: // WRITE(6) |
| 92 | | lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; |
| 93 | | blocks = SCSILengthFromUINT8( &command[4] ); |
| 94 | | |
| 95 | | logerror("SCSIHD: WRITE to LBA %x for %x blocks\n", lba, blocks); |
| 96 | | |
| 97 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 98 | | *transferLength = blocks * sectorbytes; |
| 99 | | break; |
| 100 | | |
| 101 | | case 0x12: // INQUIRY |
| 102 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 103 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 104 | | break; |
| 105 | | |
| 106 | | case 0x15: // MODE SELECT (used to set CDDA volume) |
| 107 | | logerror("SCSIHD: MODE SELECT length %x control %x\n", command[4], command[5]); |
| 108 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 109 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 110 | | break; |
| 111 | | |
| 112 | | case 0x1a: // MODE SENSE(6) |
| 113 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 114 | | *transferLength = SCSILengthFromUINT8( &command[ 4 ] ); |
| 115 | | break; |
| 116 | | |
| 117 | | case 0x25: // READ CAPACITY |
| 118 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 119 | | *transferLength = 8; |
| 120 | | break; |
| 121 | | |
| 122 | | case 0x28: // READ(10) |
| 123 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 124 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 125 | | |
| 126 | | logerror("SCSIHD: READ at LBA %x for %x blocks\n", lba, blocks); |
| 127 | | |
| 128 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 129 | | *transferLength = blocks * sectorbytes; |
| 130 | | break; |
| 131 | | |
| 132 | | case 0x2a: // WRITE (10) |
| 133 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 134 | | blocks = SCSILengthFromUINT16( &command[7] ); |
| 135 | | |
| 136 | | logerror("SCSIHD: WRITE to LBA %x for %x blocks\n", lba, blocks); |
| 137 | | |
| 138 | | SetPhase( SCSI_PHASE_DATAOUT ); |
| 139 | | |
| 140 | | *transferLength = blocks * sectorbytes; |
| 141 | | break; |
| 142 | | |
| 143 | | case 0xa8: // READ(12) |
| 144 | | lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; |
| 145 | | blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; |
| 146 | | |
| 147 | | logerror("SCSIHD: READ at LBA %x for %x blocks\n", lba, blocks); |
| 148 | | |
| 149 | | SetPhase( SCSI_PHASE_DATAIN ); |
| 150 | | *transferLength = blocks * sectorbytes; |
| 151 | | break; |
| 152 | | |
| 153 | | default: |
| 154 | | scsihle_device::ExecCommand( transferLength ); |
| 155 | | break; |
| 156 | | } |
| 157 | | } |
| 158 | | |
| 159 | | void scsihd_device::ReadData( UINT8 *data, int dataLength ) |
| 160 | | { |
| 161 | | int i; |
| 162 | | |
| 163 | | // if we're a drive without a disk, return all zeroes |
| 164 | | if (!disk) |
| 165 | | { |
| 166 | | memset(data, 0, dataLength); |
| 167 | | return; |
| 168 | | } |
| 169 | | |
| 170 | | switch ( command[0] ) |
| 171 | | { |
| 172 | | case 0x03: // REQUEST SENSE |
| 173 | | data[0] = 0x80; // valid sense |
| 174 | | for (i = 1; i < 12; i++) |
| 175 | | { |
| 176 | | data[i] = 0; |
| 177 | | } |
| 178 | | break; |
| 179 | | |
| 180 | | case 0x12: // INQUIRY |
| 181 | | memset( data, 0, dataLength ); |
| 182 | | data[0] = 0x00; // device is direct-access (e.g. hard disk) |
| 183 | | data[1] = 0x00; // media is not removable |
| 184 | | data[2] = 0x05; // device complies with SPC-3 standard |
| 185 | | data[3] = 0x02; // response data format = SPC-3 standard |
| 186 | | // Apple HD SC setup utility needs to see this |
| 187 | | strcpy((char *)&data[8], " SEAGATE"); |
| 188 | | strcpy((char *)&data[16], " ST225N"); |
| 189 | | strcpy((char *)&data[32], "1.0"); |
| 190 | | break; |
| 191 | | |
| 192 | | case 0x1a: // MODE SENSE (6 byte) |
| 193 | | // special Apple ID page. this is a vendor-specific page, |
| 194 | | // so unless collisions occur there should be no need |
| 195 | | // to change it. |
| 196 | | if ((command[2] & 0x3f) == 0x30) |
| 197 | | { |
| 198 | | memset(data, 0, 40); |
| 199 | | data[0] = 0x14; |
| 200 | | strcpy((char *)&data[14], "APPLE COMPUTER, INC."); |
| 201 | | } |
| 202 | | break; |
| 203 | | |
| 204 | | case 0x08: // READ(6) |
| 205 | | case 0x28: // READ(10) |
| 206 | | case 0xa8: // READ(12) |
| 207 | | if ((disk) && (blocks)) |
| 208 | | { |
| 209 | | while (dataLength > 0) |
| 210 | | { |
| 211 | | if (!hard_disk_read(disk, lba, data)) |
| 212 | | { |
| 213 | | logerror("SCSIHD: HD read error!\n"); |
| 214 | | } |
| 215 | | lba++; |
| 216 | | blocks--; |
| 217 | | dataLength -= sectorbytes; |
| 218 | | data += sectorbytes; |
| 219 | | } |
| 220 | | } |
| 221 | | break; |
| 222 | | |
| 223 | | |
| 224 | | case 0x25: // READ CAPACITY |
| 225 | | { |
| 226 | | hard_disk_info *info; |
| 227 | | UINT32 temp; |
| 228 | | |
| 229 | | info = hard_disk_get_info(disk); |
| 230 | | |
| 231 | | logerror("SCSIHD: READ CAPACITY\n"); |
| 232 | | |
| 233 | | // get # of sectors |
| 234 | | temp = info->cylinders * info->heads * info->sectors; |
| 235 | | temp--; |
| 236 | | |
| 237 | | data[0] = (temp>>24) & 0xff; |
| 238 | | data[1] = (temp>>16) & 0xff; |
| 239 | | data[2] = (temp>>8) & 0xff; |
| 240 | | data[3] = (temp & 0xff); |
| 241 | | data[4] = (info->sectorbytes>>24)&0xff; |
| 242 | | data[5] = (info->sectorbytes>>16)&0xff; |
| 243 | | data[6] = (info->sectorbytes>>8)&0xff; |
| 244 | | data[7] = (info->sectorbytes & 0xff); |
| 245 | | } |
| 246 | | break; |
| 247 | | |
| 248 | | default: |
| 249 | | scsihle_device::ReadData( data, dataLength ); |
| 250 | | break; |
| 251 | | } |
| 252 | | } |
| 253 | | |
| 254 | | void scsihd_device::WriteData( UINT8 *data, int dataLength ) |
| 255 | | { |
| 256 | | if (!disk) |
| 257 | | { |
| 258 | | return; |
| 259 | | } |
| 260 | | |
| 261 | | switch ( command[0] ) |
| 262 | | { |
| 263 | | case 0x0a: // WRITE(6) |
| 264 | | case 0x2a: // WRITE(10) |
| 265 | | if ((disk) && (blocks)) |
| 266 | | { |
| 267 | | while (dataLength > 0) |
| 268 | | { |
| 269 | | if (!hard_disk_write(disk, lba, data)) |
| 270 | | { |
| 271 | | logerror("SCSIHD: HD write error!\n"); |
| 272 | | } |
| 273 | | lba++; |
| 274 | | blocks--; |
| 275 | | dataLength -= sectorbytes; |
| 276 | | data += sectorbytes; |
| 277 | | } |
| 278 | | } |
| 279 | | break; |
| 280 | | |
| 281 | | default: |
| 282 | | scsihle_device::WriteData( data, dataLength ); |
| 283 | | break; |
| 284 | | } |
| 285 | | } |
| 286 | | |
| 287 | | |
| 288 | | void scsihd_device::GetDevice( void **_disk ) |
| 289 | | { |
| 290 | | *(hard_disk_file **)_disk = disk; |
| 291 | | } |
| 292 | | |
| 293 | | void scsihd_device::SetDevice( void *_disk ) |
| 294 | | { |
| 295 | | disk = (hard_disk_file *)_disk; |
| 296 | | } |
| 297 | | |
| 298 | | int scsihd_device::GetSectorBytes() |
| 299 | | { |
| 300 | | return sectorbytes; |
| 301 | | } |