📄 ataflop.c
字号:
}static void fd_rwsec_done( int status ){ DPRINT(("fd_rwsec_done()\n")); if (read_track) { del_timer(&readtrack_timer); if (!MultReadInProgress) return; MultReadInProgress = 0; } fd_rwsec_done1(status);}static void fd_rwsec_done1(int status){ unsigned int track; stop_timeout(); /* Correct the track if stretch != 0 */ if (SUDT->stretch) { track = FDC_READ( FDCREG_TRACK); MFPDELAY(); FDC_WRITE( FDCREG_TRACK, track << SUDT->stretch); } if (!UseTrackbuffer) { dma_wd.dma_mode_status = 0x90; MFPDELAY(); if (!(dma_wd.dma_mode_status & 0x01)) { printk(KERN_ERR "fd%d: DMA error\n", SelectedDrive ); goto err_end; } } MFPDELAY(); if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) { printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive ); goto err_end; } if ((status & FDCSTAT_RECNF) && /* RECNF is no error after a multiple read when the FDC searched for a non-existent sector! */ !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) { if (Probing) { if (SUDT > disk_type) { if (SUDT[-1].blocks > ReqBlock) { /* try another disk type */ SUDT--; floppy_sizes[SelectedDrive] = SUDT->blocks >> 1; } else Probing = 0; } else { if (SUD.flags & FTD_MSG) printk(KERN_INFO "fd%d: Auto-detected floppy type %s\n", SelectedDrive, SUDT->name ); Probing=0; } } else { /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ if (SUD.autoprobe) { SUDT = disk_type + StartDiskType[DriveType]; floppy_sizes[SelectedDrive] = SUDT->blocks >> 1; Probing = 1; } } if (Probing) { if (ATARIHW_PRESENT(FDCSPEED)) { dma_wd.fdc_speed = SUDT->fdc_speed; MFPDELAY(); } setup_req_params( SelectedDrive ); BufferDrive = -1; do_fd_action( SelectedDrive ); return; } printk(KERN_ERR "fd%d: sector %d not found (side %d, track %d)\n", SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack ); goto err_end; } if (status & FDCSTAT_CRC) { printk(KERN_ERR "fd%d: CRC error (side %d, track %d, sector %d)\n", SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) ); goto err_end; } if (status & FDCSTAT_LOST) { printk(KERN_ERR "fd%d: lost data (side %d, track %d, sector %d)\n", SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) ); goto err_end; } Probing = 0; if (ReqCmd == READ) { if (!read_track) { void *addr; addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer; dma_cache_maintenance( virt_to_phys(addr), 512, 0 ); if (!ATARIHW_PRESENT( EXTD_DMA )) copy_buffer (addr, ReqData); } else { dma_cache_maintenance( PhysTrackBuffer, MaxSectors[DriveType] * 512, 0 ); BufferDrive = SelectedDrive; BufferSide = ReqSide; BufferTrack = ReqTrack; copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); } } if (++ReqCnt < CURRENT->current_nr_sectors) { /* read next sector */ setup_req_params( SelectedDrive ); do_fd_action( SelectedDrive ); } else { /* all sectors finished */ CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; end_request( 1 ); redo_fd_request(); } return; err_end: BufferDrive = -1; fd_error();}static void fd_writetrack( void ){ unsigned long paddr, flags; unsigned int track; DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide )); paddr = PhysTrackBuffer; dma_cache_maintenance( paddr, BUFFER_SIZE, 1 ); fd_select_side( ReqSide ); /* Cheat for track if stretch != 0 */ if (SUDT->stretch) { track = FDC_READ( FDCREG_TRACK); MFPDELAY(); FDC_WRITE(FDCREG_TRACK,track >> SUDT->stretch); } udelay(40); /* Setup DMA */ save_flags(flags); cli(); dma_wd.dma_lo = (unsigned char)paddr; MFPDELAY(); paddr >>= 8; dma_wd.dma_md = (unsigned char)paddr; MFPDELAY(); paddr >>= 8; if (ATARIHW_PRESENT( EXTD_DMA )) st_dma_ext_dmahi = (unsigned short)paddr; else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); restore_flags(flags); /* Clear FIFO and switch DMA to correct mode */ dma_wd.dma_mode_status = 0x190; MFPDELAY(); dma_wd.dma_mode_status = 0x90; MFPDELAY(); dma_wd.dma_mode_status = 0x190; MFPDELAY(); /* How many sectors for DMA */ dma_wd.fdc_acces_seccount = BUFFER_SIZE/512; udelay(40); /* Start operation */ dma_wd.dma_mode_status = FDCSELREG_STP | 0x100; udelay(40); SET_IRQ_HANDLER( fd_writetrack_done ); dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); MotorOn = 1; start_timeout(); /* wait for interrupt */}static void fd_writetrack_done( int status ){ DPRINT(("fd_writetrack_done()\n")); stop_timeout(); if (status & FDCSTAT_WPROT) { printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive ); goto err_end; } if (status & FDCSTAT_LOST) { printk(KERN_ERR "fd%d: lost data (side %d, track %d)\n", SelectedDrive, ReqSide, ReqTrack ); goto err_end; } wake_up( &format_wait ); return; err_end: fd_error();}static void fd_times_out( unsigned long dummy ){ atari_disable_irq( IRQ_MFP_FDC ); if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but * before we came here... */ SET_IRQ_HANDLER( NULL ); /* If the timeout occurred while the readtrack_check timer was * active, we need to cancel it, else bad things will happen */ if (UseTrackbuffer) del_timer( &readtrack_timer ); FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); udelay( 25 ); printk(KERN_ERR "floppy timeout\n" ); fd_error(); end: atari_enable_irq( IRQ_MFP_FDC );}/* The (noop) seek operation here is needed to make the WP bit in the * FDC status register accessible for check_change. If the last disk * operation would have been a RDSEC, this bit would always read as 0 * no matter what :-( To save time, the seek goes to the track we're * already on. */static void finish_fdc( void ){ if (!NeedSeek) { finish_fdc_done( 0 ); } else { DPRINT(("finish_fdc: dummy seek started\n")); FDC_WRITE (FDCREG_DATA, SUD.track); SET_IRQ_HANDLER( finish_fdc_done ); FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK); MotorOn = 1; start_timeout(); /* we must wait for the IRQ here, because the ST-DMA is released immediately afterwards and the interrupt may be delivered to the wrong driver. */ }}static void finish_fdc_done( int dummy ){ unsigned long flags; DPRINT(("finish_fdc_done entered\n")); stop_timeout(); NeedSeek = 0; if (timer_pending(&fd_timer) && time_before(fd_timer.expires, jiffies + 5)) /* If the check for a disk change is done too early after this * last seek command, the WP bit still reads wrong :-(( */ mod_timer(&fd_timer, jiffies + 5); else start_check_change_timer(); start_motor_off_timer(); save_flags(flags); cli(); stdma_release(); fdc_busy = 0; wake_up( &fdc_wait ); restore_flags(flags); DPRINT(("finish_fdc() finished\n"));}/* Prevent "aliased" accesses. */static int fd_ref[4] = { 0,0,0,0 };static int fd_device[4] = { 0,0,0,0 };/* * Current device number. Taken either from the block header or from the * format request descriptor. */#define CURRENT_DEVICE (CURRENT->rq_dev)/* Current error count. */#define CURRENT_ERRORS (CURRENT->errors)/* dummy for blk.h */static void floppy_off( unsigned int nr) {}/* The detection of disk changes is a dark chapter in Atari history :-( * Because the "Drive ready" signal isn't present in the Atari * hardware, one has to rely on the "Write Protect". This works fine, * as long as no write protected disks are used. TOS solves this * problem by introducing tri-state logic ("maybe changed") and * looking at the serial number in block 0. This isn't possible for * Linux, since the floppy driver can't make assumptions about the * filesystem used on the disk and thus the contents of block 0. I've * chosen the method to always say "The disk was changed" if it is * unsure whether it was. This implies that every open or mount * invalidates the disk buffers if you work with write protected * disks. But at least this is better than working with incorrect data * due to unrecognised disk changes. */static int check_floppy_change (kdev_t dev){ unsigned int drive = MINOR(dev) & 0x03; if (MAJOR(dev) != MAJOR_NR) { printk(KERN_ERR "floppy_changed: not a floppy\n"); return 0; } if (test_bit (drive, &fake_change)) { /* simulated change (e.g. after formatting) */ return 1; } if (test_bit (drive, &changed_floppies)) { /* surely changed (the WP signal changed at least once) */ return 1; } if (UD.wpstat) { /* WP is on -> could be changed: to be sure, buffers should be * invalidated... */ return 1; } return 0;}static int floppy_revalidate (kdev_t dev){ int drive = MINOR(dev) & 3; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || unit[drive].disktype == 0) { if (UD.flags & FTD_MSG) printk(KERN_ERR "floppy: clear format %p!\n", UDT); BufferDrive = -1; clear_bit(drive, &fake_change); clear_bit(drive, &changed_floppies); /* MSch: clearing geometry makes sense only for autoprobe formats, for 'permanent user-defined' parameter: restore default_params[] here if flagged valid! */ if (default_params[drive].blocks == 0) UDT = 0; else UDT = &default_params[drive]; } return 0;}static __inline__ void copy_buffer(void *from, void *to){ ulong *p1 = (ulong *)from, *p2 = (ulong *)to; int cnt; for( cnt = 512/4; cnt; cnt-- ) *p2++ = *p1++;}/* This sets up the global variables describing the current request. */static void setup_req_params( int drive ){ int block = ReqBlock + ReqCnt; ReqTrack = block / UDT->spt; ReqSector = block - ReqTrack * UDT->spt + 1; ReqSide = ReqTrack & 1; ReqTrack >>= 1; ReqData = ReqBuffer + 512 * ReqCnt; if (UseTrackbuffer) read_track = (ReqCmd == READ && CURRENT_ERRORS == 0); else read_track = 0; DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n",ReqSide, ReqTrack, ReqSector, (unsigned long)ReqData ));}static void redo_fd_request(void){ int device, drive, type; DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->dev=%04x CURRENT->sector=%ld\n", (unsigned long)CURRENT, !QUEUE_EMPTY ? CURRENT->rq_dev : 0, !QUEUE_EMPTY ? CURRENT->sector : 0 )); IsFormatting = 0; if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE){ return; }repeat: if (QUEUE_EMPTY) goto the_end; if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh && !buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); device = MINOR(CURRENT_DEVICE); drive = device & 3; type = device >> 2; if (!UD.connected) { /* drive not connected */ printk(KERN_ERR "Unknown Device: fd%d\n", drive ); end_request(0); goto repeat; } if (type == 0) { if (!UDT) { Probing = 1; UDT = disk_type + StartDiskType[DriveType]; floppy_sizes[drive] = UDT->blocks >> 1; UD.autoprobe = 1; } } else { /* user supplied disk type */ if (--type >= NUM_DISK_MINORS) { printk(KERN_WARNING "fd%d: invalid disk format", drive ); end_request( 0 ); goto repeat; } if (minor2disktype[type].drive_types > DriveType) { printk(KERN_WARNING "fd%d: unsupported disk format", drive ); end_request( 0 ); goto repeat; } type = minor2disktype[type].index; UDT = &disk_type[type]; floppy_sizes[drive] = UDT->blocks >> 1; UD.autoprobe = 0; } if (CURRENT->sector + 1 > UDT->blocks) { end_request(0); goto repeat; } /* stop deselect timer */ del_timer( &motor_off_timer ); ReqCnt = 0; ReqCmd = CURRENT->cmd; ReqBlock = CURRENT->sector; ReqBuffer = CURRENT->buffer; setup_req_params( drive ); do_fd_action( drive ); return; the_end: finish_fdc();}void do_fd_request(request_queue_t * q){ unsigned long flags; DPRINT(("do_fd_request for pid %d\n",current->pid)); while( fdc_busy ) sleep_on( &fdc_wait ); fdc_busy = 1; stdma_lock(floppy_irq, NULL); atari_disable_irq( IRQ_MFP_FDC ); save_flags(flags); /* The request function is called with ints sti(); * disabled... so must save the IPL for later */ redo_fd_request(); restore_flags(flags); atari_enable_irq( IRQ_MFP_FDC );}static int invalidate_drive(kdev_t rdev){ /* invalidate the buffer track to force a reread */ BufferDrive = -1; set_bit(MINOR(rdev) & 3, &fake_change); check_disk_change(rdev); return 0;}static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -