📄 mfmhd.c
字号:
DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n", CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors); CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; SectorsLeftInRequest -= CURRENT->current_nr_sectors; end_request(1); if (SectorsLeftInRequest) { hdc63463_dataptr = (unsigned int) CURRENT->buffer; Copy_buffer = CURRENT->buffer; Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; errors = &(CURRENT->errors); /* These should match the present calculations of the next logical sector on the device Copy_Sector=CURRENT->sector*2; */ if (Copy_Sector != CURRENT->sector * 2)#ifdef DEBUG /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n", Copy_Sector, CURRENT->sector * 2);#else printk("mfm: Copy_Sector mismatch! Eek!\n");#endif }; /* CURRENT */ }; /* Sectors256LeftInCurrent */ }; old_status = mfm_status; mfm_status = inw(MFM_STATUS); if (mfm_status & (STAT_DER | STAT_ABN)) { /* Something has gone wrong - let's try that again */ if (cont) { DBG("mfm_rw_intr: DER/ABN error\n"); cont->error(); cont->redo(); }; return; }; /* If this code wasn't entered due to command_end but there is now a command end we must read the command results out. If it was entered like this then mfm_interrupt_handler would have done the job. */ if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) && ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) { int len = 0; while (len < 16) { int in; in = inw(MFM_DATAIN); result[len++] = in >> 8; result[len++] = in; }; }; /* Result read */ /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */ /* If end of command move on */ if (mfm_status & (STAT_CED)) { outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ /* End of command - trigger the next command */ if (cont) { cont->done(1); } DBG("mfm_rw_intr: returned from cont->done\n"); } else { /* Its going to generate another interrupt */ SET_INTR(mfm_rw_intr); };}static void mfm_setup_rw(void){ DBG("setting up for rw...\n"); SET_INTR(mfm_rw_intr); issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);}static void mfm_recal_intr(void){#ifdef DEBUG console_printf("recal intr - status = "); print_status();#endif outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ if (mfm_status & (STAT_DER | STAT_ABN)) { printk("recal failed\n"); MFM_DRV_INFO.cylinder = NEED_2_RECAL; if (cont) { cont->error(); cont->redo(); } return; } /* Thats seek end - we are finished */ if (mfm_status & STAT_SED) { issue_command(CMD_POD, NULL, 0); MFM_DRV_INFO.cylinder = 0; mfm_seek(); return; } /* Command end without seek end (see data sheet p.20) for parallel seek - we have to send a POL command to wait for the seek */ if (mfm_status & STAT_CED) { SET_INTR(mfm_recal_intr); issue_command(CMD_POL, NULL, 0); return; } printk("recal: unknown status\n");}static void mfm_seek_intr(void){#ifdef DEBUG console_printf("seek intr - status = "); print_status();#endif outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ if (mfm_status & (STAT_DER | STAT_ABN)) { printk("seek failed\n"); MFM_DRV_INFO.cylinder = NEED_2_RECAL; if (cont) { cont->error(); cont->redo(); } return; } if (mfm_status & STAT_SED) { issue_command(CMD_POD, NULL, 0); MFM_DRV_INFO.cylinder = raw_cmd.cylinder; mfm_seek(); return; } if (mfm_status & STAT_CED) { SET_INTR(mfm_seek_intr); issue_command(CMD_POL, NULL, 0); return; } printk("seek: unknown status\n");}/* IDEA2 seems to work better - its what RiscOS sets my * disc to - on its SECOND call to specify! */#define IDEA2#ifndef IDEA2#define SPEC_SL 0x16#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */#else#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */#endifstatic void mfm_setupspecify (int drive, unsigned char *cmdb){ cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */ cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */ cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */ cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */ cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */ cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */ cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */ cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */ cmdb[8] = SPEC_SH; cmdb[9] = 0x0a; /* gap length 1 */ cmdb[10] = 0x0d; /* gap length 2 */ cmdb[11] = 0x0c; /* gap length 3 */ cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */ cmdb[13] = mfm_info[drive].precomp - 1; cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */ cmdb[15] = mfm_info[drive].lowcurrent - 1;}static void mfm_specify (void){ unsigned char cmdb[16]; DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive); mfm_setupspecify (raw_cmd.dev, cmdb); issue_command (CMD_SPC, cmdb, 16); /* Ensure that we will do another specify if we move to the other drive */ lastspecifieddrive = raw_cmd.dev; wait_for_completion();}static void mfm_seek(void){ unsigned char cmdb[4]; DBG("seeking...\n"); if (MFM_DRV_INFO.cylinder < 0) { SET_INTR(mfm_recal_intr); DBG("mfm_seek: about to call specify\n"); mfm_specify (); /* DAG added this */ cmdb[0] = raw_cmd.dev + 1; cmdb[1] = 0; issue_command(CMD_RCLB, cmdb, 2); return; } if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) { cmdb[0] = raw_cmd.dev + 1; cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */ cmdb[2] = raw_cmd.cylinder >> 8; cmdb[3] = raw_cmd.cylinder; SET_INTR(mfm_seek_intr); issue_command(CMD_SEK, cmdb, 4); } else mfm_setup_rw();}static void mfm_initialise(void){ DBG("init...\n"); mfm_seek();}static void request_done(int uptodate){ DBG("mfm:request_done\n"); if (uptodate) { unsigned char block[2] = {0, 0}; /* Apparently worked - let's check bytes left to DMA */ if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) { printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256); end_request(0); Busy = 0; }; /* Potentially this means that we've done; but we might be doing a partial access, (over two cylinders) or we may have a number of fragments in an image file. First let's deal with partial accesss */ if (PartFragRead) { /* Yep - a partial access */ /* and issue the remainder */ issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); return; } /* ah well - perhaps there is another fragment to go */ /* Increment pointers/counts to start of next fragment */ if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n"); /* No - its the end of the line */ /* end_request's should have happened at the end of sector DMAs */ /* Turns Drive LEDs off - may slow it down? */ if (QUEUE_EMPTY) issue_command(CMD_CKV, block, 2); Busy = 0; DBG("request_done: About to mfm_request\n"); /* Next one please */ mfm_request(); /* Moved from mfm_rw_intr */ DBG("request_done: returned from mfm_request\n"); } else { printk("mfm:request_done: update=0\n"); end_request(0); Busy = 0; }}static void error_handler(void){ printk("error detected... status = "); print_status(); (*errors)++; if (*errors > MFM_DRV_INFO.errors.abort) cont->done(0); if (*errors > MFM_DRV_INFO.errors.recal) MFM_DRV_INFO.cylinder = NEED_2_RECAL;}static void rw_interrupt(void){ printk("rw_interrupt\n");}static struct cont rw_cont ={ rw_interrupt, error_handler, mfm_rerequest, request_done};/* * Actually gets round to issuing the request - note everything at this * point is in 256 byte sectors not Linux 512 byte blocks */static void issue_request(int dev, unsigned int block, unsigned int nsect, struct request *req){ int track, start_head, start_sector; int sectors_to_next_cyl; dev >>= 6; track = block / mfm_info[dev].sectors; start_sector = block % mfm_info[dev].sectors; start_head = track % mfm_info[dev].heads; /* First get the number of whole tracks which are free before the next track */ sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors; /* Then add in the number of sectors left on this track */ sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector); DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track); raw_cmd.dev = dev; raw_cmd.sector = start_sector; raw_cmd.head = start_head; raw_cmd.cylinder = track / mfm_info[dev].heads; raw_cmd.cmdtype = CURRENT->cmd; raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ raw_cmd.cmddata[1] = raw_cmd.head; raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; raw_cmd.cmddata[3] = raw_cmd.cylinder; raw_cmd.cmddata[4] = raw_cmd.head; raw_cmd.cmddata[5] = raw_cmd.sector; /* Was == and worked - how the heck??? */ if (lastspecifieddrive != raw_cmd.dev) mfm_specify (); if (nsect <= sectors_to_next_cyl) { raw_cmd.cmddata[6] = nsect >> 8; raw_cmd.cmddata[7] = nsect; PartFragRead = 0; /* All in one */ PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */ } else { raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8; raw_cmd.cmddata[7] = sectors_to_next_cyl; PartFragRead = sectors_to_next_cyl; /* only do this many this time */ PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */ PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl; } raw_cmd.cmdlen = 8; /* Setup DMA pointers */ hdc63463_dataptr = (unsigned int) Copy_buffer; hdc63463_dataleft = nsect * 256; /* Better way? */ DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ", raw_cmd.cylinder, raw_cmd.head, raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); cont = &rw_cont; errors = &(CURRENT->errors);#if 0 mfm_tq.routine = (void (*)(void *)) mfm_initialise; queue_task(&mfm_tq, &tq_immediate); mark_bh(IMMEDIATE_BH);#else mfm_initialise();#endif} /* issue_request *//* * Called when an error has just happened - need to trick mfm_request * into thinking we weren't busy * * Turn off ints - mfm_request expects them this way */static void mfm_rerequest(void){ DBG("mfm_rerequest\n"); cli(); Busy = 0; mfm_request();}static void mfm_request(void){ DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy); if (QUEUE_EMPTY) { DBG("mfm_request: Exited due to NULL Current 1\n"); return; } if (CURRENT->rq_status == RQ_INACTIVE) { /* Hmm - seems to be happening a lot on 1.3.45 */ /*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */ return; } /* If we are still processing then return; we will get called again */ if (Busy) { /* Again seems to be common in 1.3.45 */ /*DBG*/printk("mfm_request: Exiting due to busy\n"); return; } Busy = 1; while (1) { unsigned int dev, block, nsect; DBG("mfm_request: loop start\n"); sti(); DBG("mfm_request: before INIT_REQUEST\n"); if (QUEUE_EMPTY) { printk("mfm_request: Exiting due to !CURRENT (pre)\n"); CLEAR_INTR; Busy = 0; return; }; INIT_REQUEST; DBG("mfm_request: before arg extraction\n"); dev = MINOR(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors;#ifdef DEBUG /*if ((dev>>6)==1) */ console_printf("mfm_request: raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect);#endif if (dev >= (mfm_drives << 6) || block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) { if (dev >= (mfm_drives << 6)) printk("mfm: bad minor number: device=%s\n", kdevname(CURRENT->rq_dev)); else printk("mfm%c: bad access: block=%d, count=%d, nr_sects=%ld\n", (dev >> 6)+'a', block, nsect, mfm[dev].nr_sects); printk("mfm: continue 1\n"); end_request(0); Busy = 0; continue; } block += mfm[dev].start_sect; /* DAG: Linux doesn't cope with this - even though it has an array telling it the hardware block size - silly */ block <<= 1; /* Now in 256 byte sectors */ nsect <<= 1; /* Ditto */ SectorsLeftInRequest = nsect >> 1; Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; Copy_buffer = CURRENT->buffer; Copy_Sector = CURRENT->sector << 1; DBG("mfm_request: block after offset=%d\n", block); if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) { printk("unknown mfm-command %d\n", CURRENT->cmd); end_request(0); Busy = 0; printk("mfm: continue 4\n"); continue; } issue_request(dev, block, nsect, CURRENT); break; } DBG("mfm_request: Dropping out bottom\n");}static void do_mfm_request(request_queue_t *q){ DBG("do_mfm_request: about to mfm_request\n"); mfm_request();}static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs){ void (*handler) (void) = DEVICE_INTR; CLEAR_INTR; DBG("mfm_interrupt_handler (handler=0x%p)\n", handler); mfm_status = inw(MFM_STATUS); /* If CPR (Command Parameter Reject) and not busy it means that the command has some return message to give us */ if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) { int len = 0; while (len < 16) { int in; in = inw(MFM_DATAIN); result[len++] = in >> 8; result[len++] = in; } } if (handler) { handler(); return; } outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ printk ("mfm: unexpected interrupt - status = "); print_status (); while (1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -