FloppyDiskDevice.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. #include <Kernel/Arch/i386/PIT.h>
  2. #include <Kernel/Devices/FloppyDiskDevice.h>
  3. #include <Kernel/FileSystem/ProcFS.h>
  4. #include <Kernel/IO.h>
  5. #include <Kernel/Process.h>
  6. #include <Kernel/VM/MemoryManager.h>
  7. // Uncomment me for a LOT of output
  8. //#define FLOPPY_DEBUG
  9. // THESE ARE OFFSETS!
  10. #define FLOPPY_STATUS_A 0x00 // ro
  11. #define FLOPPY_STATUS_B 0x01 // ro
  12. #define FLOPPY_DOR 0x02 // rw
  13. #define FLOPPY_TDR 0x03 // rw
  14. #define FLOPPY_MSR 0x04 // ro
  15. #define FLOPPY_DSR 0x04 // wo
  16. #define FLOPPY_FIFO 0x05
  17. #define FLOPPY_RSVD 0x06
  18. #define FLOPPY_DIR 0x07 // ro
  19. #define FLOPPY_CCR 0x07 // wo
  20. #define FLOPPY_STATUS_DIR 0x01
  21. #define FLOPPY_STATUS_WP 0x02
  22. #define FLOPPY_STATUS_INDX 0x04
  23. #define FLOPPY_STATUS_HDSEL 0x08
  24. #define FLOPPY_STATUS_TRK0 0x10
  25. #define FLOPPY_STATUS_STEP 0x20
  26. #define FLOPPY_STATUS_DRV2 0x40
  27. #define FLOPPY_STATUS_INTW 0x80 // A.K.A INT_PENDING
  28. #define FLOPPY_DOR_DRVSEL0 0x01
  29. #define FLOPPY_DOR_DRVSEL1 0x02
  30. #define FLOPPY_DOR_RESET 0x04
  31. #define FLOPPY_DOR_DMAGATE 0x08
  32. #define FLOPPY_DOR_MOTEN0 0x10
  33. #define FLOPPY_DOR_MOTEN1 0x20
  34. #define FLOPPY_DOR_MOTEN2 0x40
  35. #define FLOPPY_DOR_MOTEN3 0x80
  36. // Preset values to activate drive select and motor enable for each drive
  37. #define FLOPPY_DOR_DRV0 0x1C
  38. #define FLOPPY_DOR_DRV1 0x2D
  39. #define FLOPPY_DOR_DRV2 0x4E
  40. #define FLOPPY_DOR_DRV3 0x8F
  41. #define FLOPPY_MSR_FDD0BSY 0x01
  42. #define FLOPPY_MSR_FDD1BSY 0x02
  43. #define FLOPPY_MSR_FDD2BSY 0x04
  44. #define FLOPPY_MSR_FDD3BSY 0x08
  45. #define FLOPPY_MSR_FDCBSY 0x10
  46. #define FLOPPY_MSR_MODE 0x20 // 0 in DMA mode, 1 in PIO mode
  47. #define FLOPPY_MSR_DIO 0x40 // 0 FDC is expecting data from the CPU, 1 if FDC has data for CPU
  48. #define FLOPPY_MSR_RQM 0x80 // 0 Data register not ready, 1 data register ready
  49. #define FLOPPY_CCR_DRTESEL0 0x01
  50. #define FLOPPY_CCR_DRTESEL1 0x02
  51. #define FLOPPY_MT 0x80 // Multi-track selector. The controller treats 2 tracks (on side 0 and side 1) as a single track instead
  52. #define FLOPPY_MFM 0x40 // 1 Means this disk is double density (double sided??)
  53. #define FLOPPY_SK 0x20 // Skip flag. Skips sectors containing deleted data automatically for us :)
  54. #define SR0_OKAY (0x00) << 6
  55. #define SR0_ABORMAL_TERMINATION (0x01) << 6
  56. #define SR0_INVALID_CMD (0x02) << 6
  57. #define SR0_ABNORMAL_TERM_POLL (0x03) << 6
  58. #define FLOPPY_DMA_CHANNEL 2 // All FDCs are DMA channel 2
  59. #define IRQ_FLOPPY_DRIVE 6
  60. NonnullRefPtr<FloppyDiskDevice> FloppyDiskDevice::create(DriveType type)
  61. {
  62. return adopt(*new FloppyDiskDevice(type));
  63. }
  64. const char* FloppyDiskDevice::class_name() const
  65. {
  66. if (m_controller_version == 0x90)
  67. return "Intel 82078 Floppy Disk Controller";
  68. else if (m_controller_version == 0x80)
  69. return "NEC uPD765";
  70. return "Generic Floppy Disk Controller";
  71. }
  72. FloppyDiskDevice::FloppyDiskDevice(FloppyDiskDevice::DriveType type)
  73. : IRQHandler(IRQ_FLOPPY_DRIVE)
  74. , DiskDevice(89, (type == FloppyDiskDevice::DriveType::Master) ? 0 : 1, BYTES_PER_SECTOR)
  75. , m_io_base_addr((type == FloppyDiskDevice::DriveType::Master) ? 0x3F0 : 0x370)
  76. {
  77. initialize();
  78. }
  79. FloppyDiskDevice::~FloppyDiskDevice()
  80. {
  81. }
  82. bool FloppyDiskDevice::read_block(unsigned index, u8* data) const
  83. {
  84. return const_cast<FloppyDiskDevice*>(this)->read_blocks(index, 1, data);
  85. }
  86. bool FloppyDiskDevice::write_block(unsigned index, const u8* data)
  87. {
  88. return write_sectors_with_dma(index, 1, data);
  89. }
  90. bool FloppyDiskDevice::read_blocks(unsigned index, u16 count, u8* data)
  91. {
  92. return read_sectors_with_dma(index, count, data);
  93. }
  94. bool FloppyDiskDevice::write_blocks(unsigned index, u16 count, const u8* data)
  95. {
  96. return write_sectors_with_dma(index, count, data);
  97. ;
  98. }
  99. bool FloppyDiskDevice::read_sectors_with_dma(u16 lba, u16 count, u8* outbuf)
  100. {
  101. LOCKER(m_lock); // Acquire lock
  102. #ifdef FLOPPY_DEBUG
  103. kprintf("fdc: read_sectors_with_dma lba = %d count = %d\n", lba, count);
  104. #endif
  105. motor_enable(is_slave() ? 1 : 0); // Should I bother casting this?!
  106. write_ccr(0);
  107. recalibrate(); // Recalibrate the drive
  108. // We have to wait for about 300ms for the drive to spin up, because of
  109. // the inertia of the motor and diskette. This is only
  110. // important on real hardware
  111. // TODO: Fix this if you want to get it running on real hardware. This code doesn't allow
  112. // time for the disk to spin up.
  113. //u32 start = PIT::seconds_since_boot();
  114. //while(start < PIT::seconds_since_boot() + 1)
  115. // ;
  116. disable_irq();
  117. IO::out8(0xA, FLOPPY_DMA_CHANNEL | 0x4); // Channel 2 SEL, MASK_ON = 1
  118. IO::out8(0x0B, 0x56); // Begin DMA, Single Transfer, Increment, Auto, FDC -> RAM, Channel 2
  119. IO::out8(0xA, 0x2); // Unmask channel 2. The transfer will now begin
  120. // Translate the LBA address into something the FDC understands.
  121. u16 cylinder = lba2cylinder(lba);
  122. u16 head = lba2head(lba);
  123. u16 sector = lba2sector(lba);
  124. #ifdef FLOPPY_DEBUG
  125. kprintf("fdc: addr = 0x%x c = %d h = %d s = %d\n", lba * BYTES_PER_SECTOR, cylinder, head, sector);
  126. #endif
  127. // Intel recommends 3 attempts for a read/write
  128. for (int i = 0; i < 3; i++) {
  129. // Now actually send the command to the drive. This is a big one!
  130. send_byte(FLOPPY_MFM | FLOPPY_MT | FLOPPY_SK | static_cast<u8>(FloppyCommand::ReadData));
  131. send_byte(head << 2 | is_slave() ? 1 : 0);
  132. send_byte(cylinder);
  133. send_byte(head);
  134. send_byte(sector);
  135. send_byte(SECTORS_PER_CYLINDER >> 8); // Yikes!
  136. send_byte((sector + 1) >= SECTORS_PER_CYLINDER ? SECTORS_PER_CYLINDER : sector + 1);
  137. send_byte(0x27); // GPL3 value. The Datasheet doesn't really specify the values for this properly...
  138. send_byte(0xff);
  139. enable_irq();
  140. wait_for_irq(); // TODO: See if there was a lockup here via some "timeout counter"
  141. m_interrupted = false;
  142. // Flush FIFO
  143. read_byte();
  144. read_byte();
  145. read_byte();
  146. u8 cyl = read_byte();
  147. read_byte();
  148. read_byte();
  149. read_byte();
  150. if (cyl != cylinder) {
  151. #ifdef FLOPPY_DEBUG
  152. kprintf("fdc: cyl != cylinder (cyl = %d cylinder = %d)! Retrying...\n", cyl, cylinder);
  153. #endif
  154. continue;
  155. }
  156. // Let the controller know we handled the interrupt
  157. send_byte(FloppyCommand::SenseInterrupt);
  158. u8 st0 = read_byte();
  159. u8 pcn = read_byte();
  160. static_cast<void>(st0);
  161. static_cast<void>(pcn);
  162. memcpy(outbuf, m_dma_buffer_page->paddr().as_ptr(), 512 * count);
  163. return true;
  164. }
  165. #ifdef FLOPPY_DEBUG
  166. kprintf("fdc: out of read attempts (check your hardware maybe!?)\n");
  167. #endif
  168. return false;
  169. }
  170. bool FloppyDiskDevice::write_sectors_with_dma(u16 lba, u16 count, const u8* inbuf)
  171. {
  172. LOCKER(m_lock); // Acquire lock
  173. #ifdef FLOPPY_DEBUG
  174. kprintf("fdc: write_sectors_with_dma lba = %d count = %d\n", lba, count);
  175. #endif
  176. motor_enable(is_slave() ? 1 : 0); // Should I bother casting this?!
  177. write_ccr(0);
  178. recalibrate(); // Recalibrate the drive
  179. // We have to wait for about 300ms for the drive to spin up, because of
  180. // the inertia of the motor and diskette.
  181. // TODO: Fix this abomination please!
  182. //u32 start = PIT::seconds_since_boot();
  183. //while(start < PIT::seconds_since_boot() + 1)
  184. // ;
  185. disable_irq();
  186. IO::out8(0xA, FLOPPY_DMA_CHANNEL | 0x4); // Channel 2 SEL, MASK_ON = 1
  187. IO::out8(0x0B, 0x5A); // Begin DMA, Single Transfer, Increment, Auto, RAM -> FDC, Channel 2
  188. IO::out8(0xA, 0x2); // Unmask channel 2. The transfer will now begin
  189. u16 cylinder = lba2cylinder(lba);
  190. u16 head = lba2head(lba);
  191. u16 sector = lba2sector(lba);
  192. #ifdef FLOPPY_DEBUG
  193. kprintf("fdc: addr = 0x%x c = %d h = %d s = %d\n", lba * BYTES_PER_SECTOR, cylinder, head, sector);
  194. #endif
  195. for (int i = 0; i < 3; i++) {
  196. // Now actually send the command to the drive. This is a big one!
  197. send_byte(FLOPPY_MFM | FLOPPY_MT | static_cast<u8>(FloppyCommand::WriteData));
  198. send_byte(head << 2 | is_slave() ? 1 : 0);
  199. send_byte(cylinder);
  200. send_byte(head);
  201. send_byte(sector);
  202. send_byte(SECTORS_PER_CYLINDER >> 8); // Yikes!
  203. send_byte((sector + 1) >= SECTORS_PER_CYLINDER ? SECTORS_PER_CYLINDER : sector + 1);
  204. send_byte(0x27); // GPL3 value. The Datasheet doesn't really specify the values for this properly...
  205. send_byte(0xff);
  206. enable_irq();
  207. wait_for_irq(); // TODO: See if there was a lockup here via some "timeout counter"
  208. m_interrupted = false;
  209. // Flush FIFO
  210. read_byte();
  211. read_byte();
  212. read_byte();
  213. u8 cyl = read_byte();
  214. read_byte();
  215. read_byte();
  216. read_byte();
  217. if (cyl != cylinder) {
  218. #ifdef FLOPPY_DEBUG
  219. kprintf("fdc: cyl != cylinder (cyl = %d cylinder = %d)! Retrying...\n", cyl, cylinder);
  220. #endif
  221. continue;
  222. }
  223. // Let the controller know we handled the interrupt
  224. send_byte(FloppyCommand::SenseInterrupt);
  225. u8 st0 = read_byte();
  226. u8 pcn = read_byte();
  227. static_cast<void>(st0);
  228. static_cast<void>(pcn);
  229. memcpy(m_dma_buffer_page->paddr().as_ptr(), inbuf, 512 * count);
  230. return true;
  231. }
  232. #ifdef FLOPPY_DEBUG
  233. kprintf("fdc: out of read attempts (check your hardware maybe!?)\n");
  234. #endif
  235. return false;
  236. }
  237. bool FloppyDiskDevice::wait_for_irq()
  238. {
  239. #ifdef FLOPPY_DEBUG
  240. kprintf("fdc: Waiting for interrupt...\n");
  241. #endif
  242. while (!m_interrupted) {
  243. Scheduler::yield();
  244. }
  245. memory_barrier();
  246. return true;
  247. }
  248. void FloppyDiskDevice::handle_irq()
  249. {
  250. // The only thing we need to do is acknowledge the IRQ happened
  251. m_interrupted = true;
  252. #ifdef FLOPPY_DEBUG
  253. kprintf("fdc: Received IRQ!\n");
  254. #endif
  255. }
  256. void FloppyDiskDevice::send_byte(u8 value) const
  257. {
  258. for (int i = 0; i < 1024; i++) {
  259. if (read_msr() & FLOPPY_MSR_RQM) {
  260. IO::out8(m_io_base_addr + FLOPPY_FIFO, value);
  261. return;
  262. }
  263. }
  264. #ifdef FLOPPY_DEBUG
  265. kprintf("fdc: FIFO write timed out!\n");
  266. #endif
  267. }
  268. void FloppyDiskDevice::send_byte(FloppyCommand value) const
  269. {
  270. for (int i = 0; i < 1024; i++) {
  271. if (read_msr() & FLOPPY_MSR_RQM) {
  272. IO::out8(m_io_base_addr + FLOPPY_FIFO, static_cast<u8>(value));
  273. return;
  274. }
  275. }
  276. #ifdef FLOPPY_DEBUG
  277. kprintf("fdc: FIFO write timed out!\n");
  278. #endif
  279. }
  280. u8 FloppyDiskDevice::read_byte() const
  281. {
  282. for (int i = 0; i < 1024; i++) {
  283. if (read_msr() & (FLOPPY_MSR_RQM | FLOPPY_MSR_DIO)) {
  284. return IO::in8(m_io_base_addr + FLOPPY_FIFO);
  285. }
  286. }
  287. #ifdef FLOPPY_DEBUG
  288. kprintf("fdc: FIFO read timed out!\n");
  289. #endif
  290. return 0xff;
  291. }
  292. void FloppyDiskDevice::write_dor(u8 value) const
  293. {
  294. IO::out8(m_io_base_addr + FLOPPY_DOR, value);
  295. }
  296. void FloppyDiskDevice::write_ccr(u8 value) const
  297. {
  298. IO::out8(m_io_base_addr + FLOPPY_CCR, value);
  299. }
  300. u8 FloppyDiskDevice::read_msr() const
  301. {
  302. return IO::in8(m_io_base_addr + FLOPPY_MSR);
  303. }
  304. void FloppyDiskDevice::motor_enable(bool slave) const
  305. {
  306. u8 val = slave ? 0x1C : 0x2D;
  307. write_dor(val);
  308. }
  309. bool FloppyDiskDevice::is_busy() const
  310. {
  311. return read_msr() & FLOPPY_MSR;
  312. }
  313. bool FloppyDiskDevice::recalibrate()
  314. {
  315. #ifdef FLOPPY_DEBUG
  316. kprintf("fdc: recalibrating drive...\n");
  317. #endif
  318. u8 slave = is_slave() ? 1 : 0;
  319. motor_enable(slave);
  320. for (int i = 0; i < 16; i++) {
  321. send_byte(FloppyCommand::Recalibrate);
  322. send_byte(slave);
  323. wait_for_irq();
  324. m_interrupted = false;
  325. send_byte(FloppyCommand::SenseInterrupt);
  326. u8 st0 = read_byte();
  327. u8 pcn = read_byte();
  328. static_cast<void>(st0);
  329. if (pcn == 0)
  330. return true;
  331. }
  332. #ifdef FLOPPY_DEBUG
  333. kprintf("fdc: failed to calibrate drive (check your hardware!)\n");
  334. #endif
  335. return false;
  336. }
  337. bool FloppyDiskDevice::seek(u16 lba)
  338. {
  339. u8 head = lba2head(lba) & 0x01;
  340. u8 cylinder = lba2cylinder(lba) & 0xff;
  341. u8 slave = is_slave() ? 1 : 0;
  342. // First, we need to enable the correct drive motor
  343. motor_enable(slave);
  344. #ifdef FLOPPY_DEBUG
  345. kprintf("fdc: seeking to cylinder %d on side %d on drive %d\n", cylinder, head, slave);
  346. #endif
  347. // Try at most 5 times to seek to the desired cylinder
  348. for (int attempt = 0; attempt < 5; attempt++) {
  349. send_byte(FloppyCommand::Seek);
  350. send_byte((head << 2) | slave);
  351. send_byte(cylinder);
  352. wait_for_irq();
  353. m_interrupted = false;
  354. send_byte(FloppyCommand::SenseInterrupt);
  355. u8 st0 = read_byte();
  356. u8 pcn = read_byte();
  357. if ((st0 >> 5) != 1 || pcn != cylinder || (st0 & 0x01)) {
  358. #ifdef FLOPPY_DEBUG
  359. kprintf("fdc: failed to seek to cylinder %d on attempt %d!\n", cylinder, attempt);
  360. #endif
  361. continue;
  362. }
  363. return true;
  364. }
  365. kprintf("fdc: failed to seek after 3 attempts! Aborting...\n");
  366. return false;
  367. }
  368. // This is following Intel's datasheet for the 82077, page 41
  369. void FloppyDiskDevice::initialize()
  370. {
  371. #ifdef FLOPPY_DEBUG
  372. kprintf("fdc: m_io_base = 0x%x IRQn = %d\n", m_io_base_addr, IRQ_FLOPPY_DRIVE);
  373. #endif
  374. enable_irq();
  375. // Get the version of the Floppy Disk Controller
  376. send_byte(FloppyCommand::Version);
  377. m_controller_version = read_byte();
  378. kprintf("fdc: Version = 0x%x\n", m_controller_version);
  379. // Reset
  380. write_dor(0);
  381. write_dor(FLOPPY_DOR_RESET | FLOPPY_DOR_DMAGATE);
  382. write_ccr(0);
  383. wait_for_irq();
  384. m_interrupted = false;
  385. // "If (and only if) drive polling mode is turned on, send 4 Sense Interrupt commands (required). "
  386. // Sorry OSDev, but the Intel Manual states otherwise. This ALWAYS needs to be performed.
  387. for (int i = 0; i < 4; i++) {
  388. send_byte(FloppyCommand::SenseInterrupt);
  389. u8 sr0 = read_byte();
  390. u8 trk = read_byte();
  391. kprintf("sr0 = 0x%x, cyl = 0x%x\n", sr0, trk);
  392. }
  393. // This is hardcoded for a 3.5" floppy disk drive
  394. send_byte(FloppyCommand::Specify);
  395. send_byte(0x08); // (SRT << 4) | HUT
  396. send_byte(0x0A); // (HLT << 1) | NDMA
  397. // Allocate a buffer page for us to read into. This only needs to be one sector in size.
  398. m_dma_buffer_page = MM.allocate_supervisor_physical_page();
  399. #ifdef FLOPPY_DEBUG
  400. kprintf("fdc: allocated supervisor page at paddr 0x%x\n", m_dma_buffer_page->paddr());
  401. #endif
  402. // Now, let's initialise channel 2 of the DMA controller!
  403. // This only needs to be done here, then we can just change the direction of
  404. // the transfer
  405. IO::out8(0xA, FLOPPY_DMA_CHANNEL | 0x4); // Channel 2 SEL, MASK_ON = 1
  406. IO::out8(0xC, 0xFF); // Reset Master Flip Flop
  407. // Set the buffer page address (the lower 16-bits)
  408. IO::out8(0x4, m_dma_buffer_page->paddr().get() & 0xff);
  409. IO::out8(0x4, (m_dma_buffer_page->paddr().get() >> 8) & 0xff);
  410. IO::out8(0xC, 0xFF); // Reset Master Flip Flop again
  411. IO::out8(0x05, (SECTORS_PER_CYLINDER * BYTES_PER_SECTOR) & 0xff);
  412. IO::out8(0x05, (SECTORS_PER_CYLINDER * BYTES_PER_SECTOR) >> 8);
  413. IO::out8(0x81, (m_dma_buffer_page->paddr().get() >> 16) & 0xff); // Supervisor page could be a 24-bit address, so set the External Page R/W register
  414. IO::out8(0xA, 0x2); // Unmask Channel 2
  415. #ifdef FLOPPY_DEBUG
  416. kprintf("fdc: fd%d initialised succesfully!\n", is_slave() ? 1 : 0);
  417. #endif
  418. }