?? floppy.c
字號:
output_byte(1);}static void floppy_ready(void){ if (inb(FD_DIR) & 0x80) { changed_floppies |= 1<<current_drive; buffer_track = -1; if (keep_data[current_drive]) { if (keep_data[current_drive] > 0) keep_data[current_drive]--; } else { if (ftd_msg[current_drive] && current_type[current_drive] != NULL) printk("Disk type is undefined after disk " "change in fd%d\n",current_drive); current_type[current_drive] = NULL; floppy_sizes[current_drive] = MAX_DISK_SIZE; }/* Forcing the drive to seek makes the "media changed" condition go away. * There should be a cleaner solution for that ... */ if (!reset && !recalibrate) { if (current_track && current_track != NO_TRACK) do_floppy = shake_zero; else do_floppy = shake_one; output_byte(FD_RECALIBRATE); output_byte(head<<2 | current_drive); return; } } if (reset) { reset_floppy(); return; } if (recalibrate) { recalibrate_floppy(); return; } transfer();}static void setup_format_params(void){ unsigned char *here = (unsigned char *) tmp_floppy_area; int count,head_shift,track_shift,total_shift; /* allow for about 30ms for data transport per track */ head_shift = floppy->sect / 6; /* a ``cylinder'' is two tracks plus a little stepping time */ track_shift = 2 * head_shift + 1; /* count backwards */ total_shift = floppy->sect - ((track_shift * track + head_shift * head) % floppy->sect); /* XXX: should do a check to see this fits in tmp_floppy_area!! */ for (count = 0; count < floppy->sect; count++) { *here++ = track; *here++ = head; *here++ = 1 + (( count + total_shift ) % floppy->sect); *here++ = 2; /* 512 bytes */ }}static void redo_fd_request(void){ unsigned int block; char * buffer_area; int device; if (CURRENT && CURRENT->dev < 0) return;repeat: if (format_status == FORMAT_WAIT) format_status = FORMAT_BUSY; if (format_status != FORMAT_BUSY) { if (!CURRENT) { if (!fdc_busy) printk("FDC access conflict!"); fdc_busy = 0; wake_up(&fdc_wait); CLEAR_INTR; return; } if (MAJOR(CURRENT->dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); \ if (CURRENT->bh) { if (!CURRENT->bh->b_lock) panic(DEVICE_NAME ": block not locked"); } } seek = 0; probing = 0; device = MINOR(CURRENT_DEVICE); if (device > 3) floppy = (device >> 2) + floppy_type; else { /* Auto-detection */ floppy = current_type[device & 3]; if (!floppy) { probing = 1; floppy = base_type[device & 3]; if (!floppy) { request_done(0); goto repeat; } if (CURRENT_ERRORS & 1) floppy++; } } if (format_status != FORMAT_BUSY) { if (current_drive != CURRENT_DEV) { current_track = NO_TRACK; current_drive = CURRENT_DEV; } block = CURRENT->sector; if (block+2 > floppy->size) { request_done(0); goto repeat; } sector = block % floppy->sect; block /= floppy->sect; head = block % floppy->head; track = block / floppy->head; seek_track = track << floppy->stretch; if (CURRENT->cmd == READ) command = FD_READ; else if (CURRENT->cmd == WRITE) command = FD_WRITE; else { printk("do_fd_request: unknown command\n"); request_done(0); goto repeat; } } else { if (current_drive != (format_req.device & 3)) current_track = NO_TRACK; current_drive = format_req.device & 3; if (((unsigned) format_req.track) >= floppy->track || (format_req.head & 0xfffe) || probing) { request_done(0); goto repeat; } head = format_req.head; track = format_req.track; seek_track = track << floppy->stretch; if (seek_track == buffer_track) buffer_track = -1; command = FD_FORMAT; setup_format_params(); } timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ; timer_active |= 1 << FLOPPY_TIMER; if ((seek_track == buffer_track) && (current_drive == buffer_drive)) { buffer_area = floppy_track_buffer + ((sector + head*floppy->sect)<<9); if (command == FD_READ) { copy_buffer(buffer_area,CURRENT->buffer); request_done(1); goto repeat; } else if (command == FD_WRITE) copy_buffer(CURRENT->buffer,buffer_area); } if (seek_track != current_track) seek = 1; sector++; del_timer(motor_off_timer + current_drive); floppy_on(current_drive);}void do_fd_request(void){ cli(); while (fdc_busy) sleep_on(&fdc_wait); fdc_busy = 1; sti(); redo_fd_request();}static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param){ int i,drive,cnt,okay; struct floppy_struct *this_floppy; switch (cmd) { RO_IOCTLS(inode->i_rdev,param); } drive = MINOR(inode->i_rdev); switch (cmd) { case FDFMTBEG: if (!suser()) return -EPERM; return 0; case FDFMTEND: if (!suser()) return -EPERM; cli(); fake_change |= 1 << (drive & 3); sti(); drive &= 3; cmd = FDCLRPRM; break; case FDGETPRM: if (drive > 3) this_floppy = &floppy_type[drive >> 2]; else if ((this_floppy = current_type[drive & 3]) == NULL) return -ENODEV; i = verify_area(VERIFY_WRITE,(void *) param,sizeof(struct floppy_struct)); if (i) return i; for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++) put_fs_byte(((char *) this_floppy)[cnt], (char *) param+cnt); return 0; case FDFMTTRK: if (!suser()) return -EPERM; if (fd_ref[drive & 3] != 1) return -EBUSY; cli(); while (format_status != FORMAT_NONE) sleep_on(&format_done); for (cnt = 0; cnt < sizeof(struct format_descr); cnt++) ((char *) &format_req)[cnt] = get_fs_byte( (char *) param+cnt); format_req.device = drive; format_status = FORMAT_WAIT; format_errors = 0; while (format_status != FORMAT_OKAY && format_status != FORMAT_ERROR) { if (fdc_busy) sleep_on(&fdc_wait); else { fdc_busy = 1; redo_fd_request(); } } while (format_status != FORMAT_OKAY && format_status != FORMAT_ERROR) sleep_on(&format_done); sti(); okay = format_status == FORMAT_OKAY; format_status = FORMAT_NONE; floppy_off(drive & 3); wake_up(&format_done); return okay ? 0 : -EIO; case FDFLUSH: if (!permission(inode, 2)) return -EPERM; cli(); fake_change |= 1 << (drive & 3); sti(); check_disk_change(inode->i_rdev); return 0; } if (!suser()) return -EPERM; if (drive < 0 || drive > 3) return -EINVAL; switch (cmd) { case FDCLRPRM: current_type[drive] = NULL; floppy_sizes[drive] = MAX_DISK_SIZE; keep_data[drive] = 0; break; case FDSETPRM: case FDDEFPRM: memcpy_fromfs(user_params+drive, (void *) param, sizeof(struct floppy_struct)); current_type[drive] = &user_params[drive]; floppy_sizes[drive] = user_params[drive].size >> 1; if (cmd == FDDEFPRM) keep_data[drive] = -1; else { cli(); while (fdc_busy) sleep_on(&fdc_wait); fdc_busy = 1; sti(); outb_p((current_DOR & 0xfc) | drive | (0x10 << drive),FD_DOR); for (cnt = 0; cnt < 1000; cnt++) __asm__("nop"); if (inb(FD_DIR) & 0x80) keep_data[drive] = 1; else keep_data[drive] = 0; outb_p(current_DOR,FD_DOR); fdc_busy = 0; wake_up(&fdc_wait); } break; case FDMSGON: ftd_msg[drive] = 1; break; case FDMSGOFF: ftd_msg[drive] = 0; break; case FDSETEMSGTRESH: min_report_error_cnt[drive] = (unsigned short) (param & 0x0f); break; default: return -EINVAL; } return 0;}#define CMOS_READ(addr) ({ \outb_p(addr,0x70); \inb_p(0x71); \})static struct floppy_struct *find_base(int drive,int code){ struct floppy_struct *base; if (code > 0 && code < 5) { base = &floppy_types[(code-1)*2]; printk("fd%d is %s",drive,base->name); return base; } printk("fd%d is unknown type %d",drive,code); return NULL;}static void config_types(void){ printk("Floppy drive(s): "); base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15); if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[1] = NULL; else { printk(", "); base_type[1] = find_base(1,CMOS_READ(0x10) & 15); } base_type[2] = base_type[3] = NULL; printk("\n");}/* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */static int floppy_open(struct inode * inode, struct file * filp){ int drive; int old_dev; drive = inode->i_rdev & 3; old_dev = fd_device[drive]; if (fd_ref[drive]) if (old_dev != inode->i_rdev) return -EBUSY; fd_ref[drive]++; fd_device[drive] = inode->i_rdev; buffer_drive = buffer_track = -1; if (old_dev && old_dev != inode->i_rdev) invalidate_buffers(old_dev); if (filp && filp->f_mode) check_disk_change(inode->i_rdev); return 0;}static void floppy_release(struct inode * inode, struct file * filp){ sync_dev(inode->i_rdev); if (!fd_ref[inode->i_rdev & 3]--) { printk("floppy_release with fd_ref == 0"); fd_ref[inode->i_rdev & 3] = 0; }}static struct file_operations floppy_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* select */ fd_ioctl, /* ioctl */ NULL, /* mmap */ floppy_open, /* open */ floppy_release, /* release */ block_fsync /* fsync */};/* * The version command is not supposed to generate an interrupt, but * my FDC does, except when booting in SVGA screen mode. * When it does generate an interrupt, it doesn't return any status bytes. * It appears to have something to do with the version command... * * This should never be called, because of the reset after the version check. */static void ignore_interrupt(void){ printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result()); reset = 1; CLEAR_INTR; /* ignore only once */}static void floppy_interrupt(int unused){ void (*handler)(void) = DEVICE_INTR; DEVICE_INTR = NULL; if (!handler) handler = unexpected_floppy_interrupt; handler();}/* * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags * means we run the IRQ-handler with interrupts disabled. */static struct sigaction floppy_sigaction = { floppy_interrupt, 0, SA_INTERRUPT, NULL};void floppy_init(void){ outb(current_DOR,FD_DOR); if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk("Unable to get major %d for floppy\n",MAJOR_NR); return; } blk_size[MAJOR_NR] = floppy_sizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; timer_table[FLOPPY_TIMER].fn = floppy_shutdown; timer_active &= ~(1 << FLOPPY_TIMER); config_types(); if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); if (request_dma(FLOPPY_DMA)) printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA); /* Try to determine the floppy controller type */ DEVICE_INTR = ignore_interrupt; /* don't ask ... */ output_byte(FD_VERSION); /* get FDC version code */ if (result() != 1) { printk(DEVICE_NAME ": FDC failed to return version byte\n"); fdc_version = FDC_TYPE_STD; } else fdc_version = reply_buffer[0]; if (fdc_version != FDC_TYPE_STD) printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);#ifndef FDC_FIFO_UNTESTED fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */#endif /* Not all FDCs seem to be able to handle the version command * properly, so force a reset for the standard FDC clones, * to avoid interrupt garbage. */ if (fdc_version == FDC_TYPE_STD) { initial_reset_flag = 1; reset_floppy(); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -