📄 amiflop.c
字号:
return 0; } } unit[drive].track = 0; ms_delay(unit[drive].type->settle_time); rel_fdc(); fd_deselect(drive); return 1;}static int fd_seek(int drive, int track){ unsigned char prb; int cnt;#ifdef DEBUG printk("seeking drive %d to track %d\n",drive,track);#endif drive &= 3; get_fdc(drive); if (unit[drive].track == track) { rel_fdc(); return 1; } if (!fd_motor_on(drive)) { rel_fdc(); return 0; } if (unit[drive].track < 0 && !fd_calibrate(drive)) { rel_fdc(); return 0; } fd_select (drive); cnt = unit[drive].track/2 - track/2; prb = ciab.prb; prb |= DSKSIDE | DSKDIREC; if (track % 2 != 0) prb &= ~DSKSIDE; if (cnt < 0) { cnt = - cnt; prb &= ~DSKDIREC; } ciab.prb = prb; if (track % 2 != unit[drive].track % 2) ms_delay (unit[drive].type->side_time); unit[drive].track = track; if (cnt == 0) { rel_fdc(); fd_deselect(drive); return 1; } do { prb &= ~DSKSTEP; ciab.prb = prb; prb |= DSKSTEP; udelay (1); ciab.prb = prb; ms_delay (unit[drive].type->step_delay); } while (--cnt != 0); ms_delay (unit[drive].type->settle_time); rel_fdc(); fd_deselect(drive); return 1;}static unsigned long fd_get_drive_id(int drive){ int i; ulong id = 0; drive&=3; get_fdc(drive); /* set up for ID */ MOTOR_ON; udelay(2); SELECT(SELMASK(drive)); udelay(2); DESELECT(SELMASK(drive)); udelay(2); MOTOR_OFF; udelay(2); SELECT(SELMASK(drive)); udelay(2); DESELECT(SELMASK(drive)); udelay(2); /* loop and read disk ID */ for (i=0; i<32; i++) { SELECT(SELMASK(drive)); udelay(2); /* read and store value of DSKRDY */ id <<= 1; id |= (ciaa.pra & DSKRDY) ? 0 : 1; /* cia regs are low-active! */ DESELECT(SELMASK(drive)); } rel_fdc(); /* * RB: At least A500/A2000's df0: don't identify themselves. * As every (real) Amiga has at least a 3.5" DD drive as df0: * we default to that if df0: doesn't identify as a certain * type. */ if(drive == 0 && id == FD_NODRIVE) { id = fd_def_df0; printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0); } /* return the ID value */ return (id);}static void fd_block_done(int irq, void *dummy, struct pt_regs *fp){ if (block_flag) custom.dsklen = 0x4000; if (block_flag == 2) { /* writing */ writepending = 2; post_write_timer.expires = jiffies + 1; /* at least 2 ms */ post_write_timer.data = selected; add_timer(&post_write_timer); } else { /* reading */ block_flag = 0; wake_up (&wait_fd_block); }}static void raw_read(int drive){ drive&=3; get_fdc(drive); while (block_flag) sleep_on(&wait_fd_block); fd_select(drive); /* setup adkcon bits correctly */ custom.adkcon = ADK_MSBSYNC; custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST; custom.dsksync = MFM_SYNC; custom.dsklen = 0; custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf); custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN; custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN; block_flag = 1; while (block_flag) sleep_on (&wait_fd_block); custom.dsklen = 0; fd_deselect(drive); rel_fdc();}static int raw_write(int drive){ ushort adk; drive&=3; get_fdc(drive); /* corresponds to rel_fdc() in post_write() */ if ((ciaa.pra & DSKPROT) == 0) { rel_fdc(); return 0; } while (block_flag) sleep_on(&wait_fd_block); fd_select(drive); /* clear adkcon bits */ custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC; /* set appropriate adkcon bits */ adk = ADK_SETCLR|ADK_FAST; if ((ulong)unit[drive].track >= unit[drive].type->precomp2) adk |= ADK_PRECOMP1; else if ((ulong)unit[drive].track >= unit[drive].type->precomp1) adk |= ADK_PRECOMP0; custom.adkcon = adk; custom.dsklen = DSKLEN_WRITE; custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf); custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE; custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE; block_flag = 2; return 1;}/* * to be called at least 2ms after the write has finished but before any * other access to the hardware. */static void post_write (unsigned long drive){#ifdef DEBUG printk("post_write for drive %ld\n",drive);#endif drive &= 3; custom.dsklen = 0; block_flag = 0; writepending = 0; writefromint = 0; unit[drive].dirty = 0; wake_up(&wait_fd_block); fd_deselect(drive); rel_fdc(); /* corresponds to get_fdc() in raw_write */}/* * The following functions are to convert the block contents into raw data * written to disk and vice versa. * (Add other formats here ;-)) */static unsigned long scan_sync(unsigned long raw, unsigned long end){ ushort *ptr = (ushort *)raw, *endp = (ushort *)end; while (ptr < endp && *ptr++ != 0x4489) ; if (ptr < endp) { while (*ptr == 0x4489 && ptr < endp) ptr++; return (ulong)ptr; } return 0;}static inline unsigned long checksum(unsigned long *addr, int len){ unsigned long csum = 0; len /= sizeof(*addr); while (len-- > 0) csum ^= *addr++; csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555); return csum;}static unsigned long decode (unsigned long *data, unsigned long *raw, int len){ ulong *odd, *even; /* convert length from bytes to longwords */ len >>= 2; odd = raw; even = odd + len; /* prepare return pointer */ raw += len * 2; do { *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555); } while (--len != 0); return (ulong)raw;}struct header { unsigned char magic; unsigned char track; unsigned char sect; unsigned char ord; unsigned char labels[16]; unsigned long hdrchk; unsigned long datachk;};static int amiga_read(int drive){ unsigned long raw; unsigned long end; int scnt; unsigned long csum; struct header hdr; drive&=3; raw = (long) raw_buf; end = raw + unit[drive].type->read_size; for (scnt = 0;scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) { if (!(raw = scan_sync(raw, end))) { printk (KERN_INFO "can't find sync for sector %d\n", scnt); return MFM_NOSYNC; } raw = decode ((ulong *)&hdr.magic, (ulong *)raw, 4); raw = decode ((ulong *)&hdr.labels, (ulong *)raw, 16); raw = decode ((ulong *)&hdr.hdrchk, (ulong *)raw, 4); raw = decode ((ulong *)&hdr.datachk, (ulong *)raw, 4); csum = checksum((ulong *)&hdr, (char *)&hdr.hdrchk-(char *)&hdr);#ifdef DEBUG printk ("(%x,%d,%d,%d) (%lx,%lx,%lx,%lx) %lx %lx\n", hdr.magic, hdr.track, hdr.sect, hdr.ord, *(ulong *)&hdr.labels[0], *(ulong *)&hdr.labels[4], *(ulong *)&hdr.labels[8], *(ulong *)&hdr.labels[12], hdr.hdrchk, hdr.datachk);#endif if (hdr.hdrchk != csum) { printk(KERN_INFO "MFM_HEADER: %08lx,%08lx\n", hdr.hdrchk, csum); return MFM_HEADER; } /* verify track */ if (hdr.track != unit[drive].track) { printk(KERN_INFO "MFM_TRACK: %d, %d\n", hdr.track, unit[drive].track); return MFM_TRACK; } raw = decode ((ulong *)(unit[drive].trackbuf + hdr.sect*512), (ulong *)raw, 512); csum = checksum((ulong *)(unit[drive].trackbuf + hdr.sect*512), 512); if (hdr.datachk != csum) { printk(KERN_INFO "MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n", hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt, hdr.datachk, csum); printk (KERN_INFO "data=(%lx,%lx,%lx,%lx)\n", ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[0], ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[1], ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[2], ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[3]); return MFM_DATA; } } return 0;}static void encode(unsigned long data, unsigned long *dest){ unsigned long data2; data &= 0x55555555; data2 = data ^ 0x55555555; data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); if (*(dest - 1) & 0x00000001) data &= 0x7FFFFFFF; *dest = data;}static void encode_block(unsigned long *dest, unsigned long *src, int len){ int cnt, to_cnt = 0; unsigned long data; /* odd bits */ for (cnt = 0; cnt < len / 4; cnt++) { data = src[cnt] >> 1; encode(data, dest + to_cnt++); } /* even bits */ for (cnt = 0; cnt < len / 4; cnt++) { data = src[cnt]; encode(data, dest + to_cnt++); }}static unsigned long *putsec(int disk, unsigned long *raw, int cnt){ struct header hdr; int i; disk&=3; *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA; raw++; *raw++ = 0x44894489; hdr.magic = 0xFF; hdr.track = unit[disk].track; hdr.sect = cnt; hdr.ord = unit[disk].dtype->sects * unit[disk].type->sect_mult - cnt; for (i = 0; i < 16; i++) hdr.labels[i] = 0; hdr.hdrchk = checksum((ulong *)&hdr, (char *)&hdr.hdrchk-(char *)&hdr); hdr.datachk = checksum((ulong *)(unit[disk].trackbuf+cnt*512), 512); encode_block(raw, (ulong *)&hdr.magic, 4); raw += 2; encode_block(raw, (ulong *)&hdr.labels, 16); raw += 8; encode_block(raw, (ulong *)&hdr.hdrchk, 4); raw += 2; encode_block(raw, (ulong *)&hdr.datachk, 4); raw += 2; encode_block(raw, (ulong *)(unit[disk].trackbuf+cnt*512), 512); raw += 256; return raw;}static void amiga_write(int disk){ unsigned int cnt; unsigned long *ptr = (unsigned long *)raw_buf; disk&=3; /* gap space */ for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++) *ptr++ = 0xaaaaaaaa; /* sectors */ for (cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++) ptr = putsec (disk, ptr, cnt); *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;}struct dos_header { unsigned char track, /* 0-80 */ side, /* 0-1 */ sec, /* 0-...*/ len_desc;/* 2 */ unsigned short crc; /* on 68000 we got an alignment problem, but this compiler solves it by adding silently adding a pad byte so data won't fit and this took about 3h to discover.... */ unsigned char gap1[22]; /* for longword-alignedness (0x4e) */};/* crc routines are borrowed from the messydos-handler *//* excerpt from the messydos-device ; The CRC is computed not only over the actual data, but including; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).; As we don't read or encode these fields into our buffers, we have to; preload the registers containing the CRC with the values they would have; after stepping over these fields.;; How CRCs "really" work:;; First, you should regard a bitstring as a series of coefficients of; polynomials. We calculate with these polynomials in modulo-2; arithmetic, in which both add and subtract are done the same as; exclusive-or. Now, we modify our data (a very long polynomial) in; such a way that it becomes divisible by the CCITT-standard 16-bit; 16 12 5; polynomial: x + x + x + 1, represented by $11021. The easiest; way to do this would be to multiply (using proper arithmetic) our; datablock with $11021. So we have:; data * $11021 =; data * ($10000 + $1021) =; data * $10000 + data * $1021; The left part of this is simple: Just add two 0 bytes. But then; the right part (data $1021) remains difficult and even could have; a carry into the left part. The solution is to use a modified; multiplication, which has a result that is not correct, but with; a difference of any multiple of $11021. We then only need to keep; the 16 least significant bits of the result.;; The following algorithm does this for us:;; unsigned char *data, c, crclo, crchi;; while (not done) {; c = *data++ + crchi;; crchi = (@ c) >> 8 + crclo;; crclo = @ c;; };; Remember, + is done with EOR, the @ operator is in two tables (high
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -