|
|
1.1 root 1: /*
2: * QEMU Floppy disk emulator (Intel 82078)
3: *
4: * Copyright (c) 2003 Jocelyn Mayer
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: /*
25: * The controller is used in Sun4m systems in a slightly different
26: * way. There are changes in DOR register and DMA is not available.
27: */
28: #include "vl.h"
29:
30: /********************************************************/
31: /* debug Floppy devices */
32: //#define DEBUG_FLOPPY
33:
34: #ifdef DEBUG_FLOPPY
35: #define FLOPPY_DPRINTF(fmt, args...) \
36: do { printf("FLOPPY: " fmt , ##args); } while (0)
37: #else
38: #define FLOPPY_DPRINTF(fmt, args...)
39: #endif
40:
41: #define FLOPPY_ERROR(fmt, args...) \
42: do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
43:
44: /********************************************************/
45: /* Floppy drive emulation */
46:
47: /* Will always be a fixed parameter for us */
48: #define FD_SECTOR_LEN 512
49: #define FD_SECTOR_SC 2 /* Sector size code */
50:
51: /* Floppy disk drive emulation */
52: typedef enum fdisk_type_t {
53: FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */
54: FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */
55: FDRIVE_DISK_720 = 0x03, /* 720 kB disk */
56: FDRIVE_DISK_USER = 0x04, /* User defined geometry */
57: FDRIVE_DISK_NONE = 0x05, /* No disk */
58: } fdisk_type_t;
59:
60: typedef enum fdrive_type_t {
61: FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
62: FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
63: FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
64: FDRIVE_DRV_NONE = 0x03, /* No drive connected */
65: } fdrive_type_t;
66:
67: typedef enum fdrive_flags_t {
68: FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
69: } fdrive_flags_t;
70:
71: typedef enum fdisk_flags_t {
72: FDISK_DBL_SIDES = 0x01,
73: } fdisk_flags_t;
74:
75: typedef struct fdrive_t {
76: BlockDriverState *bs;
77: /* Drive status */
78: fdrive_type_t drive;
79: fdrive_flags_t drflags;
80: uint8_t perpendicular; /* 2.88 MB access mode */
81: /* Position */
82: uint8_t head;
83: uint8_t track;
84: uint8_t sect;
85: /* Last operation status */
86: uint8_t dir; /* Direction */
87: uint8_t rw; /* Read/write */
88: /* Media */
89: fdisk_flags_t flags;
90: uint8_t last_sect; /* Nb sector per track */
91: uint8_t max_track; /* Nb of tracks */
92: uint16_t bps; /* Bytes per sector */
93: uint8_t ro; /* Is read-only */
94: } fdrive_t;
95:
96: static void fd_init (fdrive_t *drv, BlockDriverState *bs)
97: {
98: /* Drive */
99: drv->bs = bs;
100: drv->drive = FDRIVE_DRV_NONE;
101: drv->drflags = 0;
102: drv->perpendicular = 0;
103: /* Disk */
104: drv->last_sect = 0;
105: drv->max_track = 0;
106: }
107:
108: static int _fd_sector (uint8_t head, uint8_t track,
109: uint8_t sect, uint8_t last_sect)
110: {
111: return (((track * 2) + head) * last_sect) + sect - 1;
112: }
113:
114: /* Returns current position, in sectors, for given drive */
115: static int fd_sector (fdrive_t *drv)
116: {
117: return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
118: }
119:
120: static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
121: int enable_seek)
122: {
123: uint32_t sector;
124: int ret;
125:
126: if (track > drv->max_track ||
127: (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
128: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
129: head, track, sect, 1,
130: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
131: drv->max_track, drv->last_sect);
132: return 2;
133: }
134: if (sect > drv->last_sect) {
135: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
136: head, track, sect, 1,
137: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
138: drv->max_track, drv->last_sect);
139: return 3;
140: }
141: sector = _fd_sector(head, track, sect, drv->last_sect);
142: ret = 0;
143: if (sector != fd_sector(drv)) {
144: #if 0
145: if (!enable_seek) {
146: FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
147: head, track, sect, 1, drv->max_track, drv->last_sect);
148: return 4;
149: }
150: #endif
151: drv->head = head;
152: if (drv->track != track)
153: ret = 1;
154: drv->track = track;
155: drv->sect = sect;
156: }
157:
158: return ret;
159: }
160:
161: /* Set drive back to track 0 */
162: static void fd_recalibrate (fdrive_t *drv)
163: {
164: FLOPPY_DPRINTF("recalibrate\n");
165: drv->head = 0;
166: drv->track = 0;
167: drv->sect = 1;
168: drv->dir = 1;
169: drv->rw = 0;
170: }
171:
172: /* Recognize floppy formats */
173: typedef struct fd_format_t {
174: fdrive_type_t drive;
175: fdisk_type_t disk;
176: uint8_t last_sect;
177: uint8_t max_track;
178: uint8_t max_head;
179: const unsigned char *str;
180: } fd_format_t;
181:
182: static fd_format_t fd_formats[] = {
183: /* First entry is default format */
184: /* 1.44 MB 3"1/2 floppy disks */
185: { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
186: { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", },
187: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
188: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
189: { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
190: { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
191: { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
192: { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
193: /* 2.88 MB 3"1/2 floppy disks */
194: { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
195: { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
196: { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", },
197: { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
198: { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
199: /* 720 kB 3"1/2 floppy disks */
200: { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", },
201: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", },
202: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", },
203: { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", },
204: { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
205: { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
206: /* 1.2 MB 5"1/4 floppy disks */
207: { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", },
208: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
209: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
210: { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
211: { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", },
212: /* 720 kB 5"1/4 floppy disks */
213: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", },
214: { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", },
215: /* 360 kB 5"1/4 floppy disks */
216: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", },
217: { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", },
218: { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", },
219: { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", },
220: /* 320 kB 5"1/4 floppy disks */
221: { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", },
222: { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", },
223: /* 360 kB must match 5"1/4 better than 3"1/2... */
224: { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", },
225: /* end */
226: { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
227: };
228:
229: /* Revalidate a disk drive after a disk change */
230: static void fd_revalidate (fdrive_t *drv)
231: {
232: fd_format_t *parse;
233: int64_t nb_sectors, size;
234: int i, first_match, match;
235: int nb_heads, max_track, last_sect, ro;
236:
237: FLOPPY_DPRINTF("revalidate\n");
238: if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
239: ro = bdrv_is_read_only(drv->bs);
240: bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
241: if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
242: FLOPPY_DPRINTF("User defined disk (%d %d %d)",
243: nb_heads - 1, max_track, last_sect);
244: } else {
245: bdrv_get_geometry(drv->bs, &nb_sectors);
246: match = -1;
247: first_match = -1;
248: for (i = 0;; i++) {
249: parse = &fd_formats[i];
250: if (parse->drive == FDRIVE_DRV_NONE)
251: break;
252: if (drv->drive == parse->drive ||
253: drv->drive == FDRIVE_DRV_NONE) {
254: size = (parse->max_head + 1) * parse->max_track *
255: parse->last_sect;
256: if (nb_sectors == size) {
257: match = i;
258: break;
259: }
260: if (first_match == -1)
261: first_match = i;
262: }
263: }
264: if (match == -1) {
265: if (first_match == -1)
266: match = 1;
267: else
268: match = first_match;
269: parse = &fd_formats[match];
270: }
271: nb_heads = parse->max_head + 1;
272: max_track = parse->max_track;
273: last_sect = parse->last_sect;
274: drv->drive = parse->drive;
275: FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
276: nb_heads, max_track, last_sect, ro ? "ro" : "rw");
277: }
278: if (nb_heads == 1) {
279: drv->flags &= ~FDISK_DBL_SIDES;
280: } else {
281: drv->flags |= FDISK_DBL_SIDES;
282: }
283: drv->max_track = max_track;
284: drv->last_sect = last_sect;
285: drv->ro = ro;
286: } else {
287: FLOPPY_DPRINTF("No disk in drive\n");
288: drv->last_sect = 0;
289: drv->max_track = 0;
290: drv->flags &= ~FDISK_DBL_SIDES;
291: }
292: }
293:
294: /* Motor control */
295: static void fd_start (fdrive_t *drv)
296: {
297: drv->drflags |= FDRIVE_MOTOR_ON;
298: }
299:
300: static void fd_stop (fdrive_t *drv)
301: {
302: drv->drflags &= ~FDRIVE_MOTOR_ON;
303: }
304:
305: /* Re-initialise a drives (motor off, repositioned) */
306: static void fd_reset (fdrive_t *drv)
307: {
308: fd_stop(drv);
309: fd_recalibrate(drv);
310: }
311:
312: /********************************************************/
313: /* Intel 82078 floppy disk controller emulation */
314:
315: static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
316: static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
317: static int fdctrl_transfer_handler (void *opaque, int nchan,
318: int dma_pos, int dma_len);
319: static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
320: static void fdctrl_result_timer(void *opaque);
321:
322: static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
323: static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
324: static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
325: static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
326: static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
327: static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
328: static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
329: static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
330: static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
331: static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
332:
333: enum {
334: FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
335: FD_CTRL_RESET = 0x02,
336: FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */
337: FD_CTRL_BUSY = 0x08, /* dma transfer in progress */
338: FD_CTRL_INTR = 0x10,
339: };
340:
341: enum {
342: FD_DIR_WRITE = 0,
343: FD_DIR_READ = 1,
344: FD_DIR_SCANE = 2,
345: FD_DIR_SCANL = 3,
346: FD_DIR_SCANH = 4,
347: };
348:
349: enum {
350: FD_STATE_CMD = 0x00,
351: FD_STATE_STATUS = 0x01,
352: FD_STATE_DATA = 0x02,
353: FD_STATE_STATE = 0x03,
354: FD_STATE_MULTI = 0x10,
355: FD_STATE_SEEK = 0x20,
356: FD_STATE_FORMAT = 0x40,
357: };
358:
359: #define FD_STATE(state) ((state) & FD_STATE_STATE)
360: #define FD_SET_STATE(state, new_state) \
361: do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
362: #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
363: #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
364: #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
365:
366: struct fdctrl_t {
367: fdctrl_t *fdctrl;
368: /* Controller's identification */
369: uint8_t version;
370: /* HW */
371: int irq_lvl;
372: int dma_chann;
373: uint32_t io_base;
374: /* Controller state */
375: QEMUTimer *result_timer;
376: uint8_t state;
377: uint8_t dma_en;
378: uint8_t cur_drv;
379: uint8_t bootsel;
380: /* Command FIFO */
381: uint8_t fifo[FD_SECTOR_LEN];
382: uint32_t data_pos;
383: uint32_t data_len;
384: uint8_t data_state;
385: uint8_t data_dir;
386: uint8_t int_status;
387: uint8_t eot; /* last wanted sector */
388: /* States kept only to be returned back */
389: /* Timers state */
390: uint8_t timer0;
391: uint8_t timer1;
392: /* precompensation */
393: uint8_t precomp_trk;
394: uint8_t config;
395: uint8_t lock;
396: /* Power down config (also with status regB access mode */
397: uint8_t pwrd;
398: /* Floppy drives */
399: fdrive_t drives[2];
400: };
401:
402: static uint32_t fdctrl_read (void *opaque, uint32_t reg)
403: {
404: fdctrl_t *fdctrl = opaque;
405: uint32_t retval;
406:
407: switch (reg & 0x07) {
408: #ifdef TARGET_SPARC
409: case 0x00:
410: // Identify to Linux as S82078B
411: retval = fdctrl_read_statusB(fdctrl);
412: break;
413: #endif
414: case 0x01:
415: retval = fdctrl_read_statusB(fdctrl);
416: break;
417: case 0x02:
418: retval = fdctrl_read_dor(fdctrl);
419: break;
420: case 0x03:
421: retval = fdctrl_read_tape(fdctrl);
422: break;
423: case 0x04:
424: retval = fdctrl_read_main_status(fdctrl);
425: break;
426: case 0x05:
427: retval = fdctrl_read_data(fdctrl);
428: break;
429: case 0x07:
430: retval = fdctrl_read_dir(fdctrl);
431: break;
432: default:
433: retval = (uint32_t)(-1);
434: break;
435: }
436: FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
437:
438: return retval;
439: }
440:
441: static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
442: {
443: fdctrl_t *fdctrl = opaque;
444:
445: FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
446:
447: switch (reg & 0x07) {
448: case 0x02:
449: fdctrl_write_dor(fdctrl, value);
450: break;
451: case 0x03:
452: fdctrl_write_tape(fdctrl, value);
453: break;
454: case 0x04:
455: fdctrl_write_rate(fdctrl, value);
456: break;
457: case 0x05:
458: fdctrl_write_data(fdctrl, value);
459: break;
460: default:
461: break;
462: }
463: }
464:
465: static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
466: {
467: return fdctrl_read(opaque, reg);
468: }
469:
470: static void fdctrl_write_mem (void *opaque,
471: target_phys_addr_t reg, uint32_t value)
472: {
473: fdctrl_write(opaque, reg, value);
474: }
475:
476: static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
477: fdctrl_read_mem,
478: fdctrl_read_mem,
479: fdctrl_read_mem,
480: };
481:
482: static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
483: fdctrl_write_mem,
484: fdctrl_write_mem,
485: fdctrl_write_mem,
486: };
487:
488: fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
489: uint32_t io_base,
490: BlockDriverState **fds)
491: {
492: fdctrl_t *fdctrl;
493: int io_mem;
494: int i;
495:
496: FLOPPY_DPRINTF("init controller\n");
497: fdctrl = qemu_mallocz(sizeof(fdctrl_t));
498: if (!fdctrl)
499: return NULL;
500: fdctrl->result_timer = qemu_new_timer(vm_clock,
501: fdctrl_result_timer, fdctrl);
502:
503: fdctrl->version = 0x90; /* Intel 82078 controller */
504: fdctrl->irq_lvl = irq_lvl;
505: fdctrl->dma_chann = dma_chann;
506: fdctrl->io_base = io_base;
507: fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
508: if (fdctrl->dma_chann != -1) {
509: fdctrl->dma_en = 1;
510: DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
511: } else {
512: fdctrl->dma_en = 0;
513: }
514: for (i = 0; i < 2; i++) {
515: fd_init(&fdctrl->drives[i], fds[i]);
516: }
517: fdctrl_reset(fdctrl, 0);
518: fdctrl->state = FD_CTRL_ACTIVE;
519: if (mem_mapped) {
520: io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
521: cpu_register_physical_memory(io_base, 0x08, io_mem);
522: } else {
523: register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
524: register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
525: register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
526: register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
527: }
528: for (i = 0; i < 2; i++) {
529: fd_revalidate(&fdctrl->drives[i]);
530: }
531:
532: return fdctrl;
533: }
534:
535: /* XXX: may change if moved to bdrv */
536: int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
537: {
538: return fdctrl->drives[drive_num].drive;
539: }
540:
541: /* Change IRQ state */
542: static void fdctrl_reset_irq (fdctrl_t *fdctrl)
543: {
544: FLOPPY_DPRINTF("Reset interrupt\n");
545: pic_set_irq(fdctrl->irq_lvl, 0);
546: fdctrl->state &= ~FD_CTRL_INTR;
547: }
548:
549: static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
550: {
551: #ifdef TARGET_SPARC
552: // Sparc mutation
553: if (!fdctrl->dma_en) {
554: fdctrl->state &= ~FD_CTRL_BUSY;
555: fdctrl->int_status = status;
556: return;
557: }
558: #endif
559: if (~(fdctrl->state & FD_CTRL_INTR)) {
560: pic_set_irq(fdctrl->irq_lvl, 1);
561: fdctrl->state |= FD_CTRL_INTR;
562: }
563: FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
564: fdctrl->int_status = status;
565: }
566:
567: /* Reset controller */
568: static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
569: {
570: int i;
571:
572: FLOPPY_DPRINTF("reset controller\n");
573: fdctrl_reset_irq(fdctrl);
574: /* Initialise controller */
575: fdctrl->cur_drv = 0;
576: /* FIFO state */
577: fdctrl->data_pos = 0;
578: fdctrl->data_len = 0;
579: fdctrl->data_state = FD_STATE_CMD;
580: fdctrl->data_dir = FD_DIR_WRITE;
581: for (i = 0; i < MAX_FD; i++)
582: fd_reset(&fdctrl->drives[i]);
583: fdctrl_reset_fifo(fdctrl);
584: if (do_irq)
585: fdctrl_raise_irq(fdctrl, 0xc0);
586: }
587:
588: static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
589: {
590: return &fdctrl->drives[fdctrl->bootsel];
591: }
592:
593: static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
594: {
595: return &fdctrl->drives[1 - fdctrl->bootsel];
596: }
597:
598: static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
599: {
600: return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
601: }
602:
603: /* Status B register : 0x01 (read-only) */
604: static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
605: {
606: FLOPPY_DPRINTF("status register: 0x00\n");
607: return 0;
608: }
609:
610: /* Digital output register : 0x02 */
611: static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
612: {
613: uint32_t retval = 0;
614:
615: /* Drive motors state indicators */
616: if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
617: retval |= 1 << 5;
618: if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
619: retval |= 1 << 4;
620: /* DMA enable */
621: retval |= fdctrl->dma_en << 3;
622: /* Reset indicator */
623: retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
624: /* Selected drive */
625: retval |= fdctrl->cur_drv;
626: FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
627:
628: return retval;
629: }
630:
631: static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
632: {
633: /* Reset mode */
634: if (fdctrl->state & FD_CTRL_RESET) {
635: if (!(value & 0x04)) {
636: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
637: return;
638: }
639: }
640: FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
641: /* Drive motors state indicators */
642: if (value & 0x20)
643: fd_start(drv1(fdctrl));
644: else
645: fd_stop(drv1(fdctrl));
646: if (value & 0x10)
647: fd_start(drv0(fdctrl));
648: else
649: fd_stop(drv0(fdctrl));
650: /* DMA enable */
651: #if 0
652: if (fdctrl->dma_chann != -1)
653: fdctrl->dma_en = 1 - ((value >> 3) & 1);
654: #endif
655: /* Reset */
656: if (!(value & 0x04)) {
657: if (!(fdctrl->state & FD_CTRL_RESET)) {
658: FLOPPY_DPRINTF("controller enter RESET state\n");
659: fdctrl->state |= FD_CTRL_RESET;
660: }
661: } else {
662: if (fdctrl->state & FD_CTRL_RESET) {
663: FLOPPY_DPRINTF("controller out of RESET state\n");
664: fdctrl_reset(fdctrl, 1);
665: fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
666: }
667: }
668: /* Selected drive */
669: fdctrl->cur_drv = value & 1;
670: }
671:
672: /* Tape drive register : 0x03 */
673: static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
674: {
675: uint32_t retval = 0;
676:
677: /* Disk boot selection indicator */
678: retval |= fdctrl->bootsel << 2;
679: /* Tape indicators: never allowed */
680: FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
681:
682: return retval;
683: }
684:
685: static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
686: {
687: /* Reset mode */
688: if (fdctrl->state & FD_CTRL_RESET) {
689: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
690: return;
691: }
692: FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
693: /* Disk boot selection indicator */
694: fdctrl->bootsel = (value >> 2) & 1;
695: /* Tape indicators: never allow */
696: }
697:
698: /* Main status register : 0x04 (read) */
699: static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
700: {
701: uint32_t retval = 0;
702:
703: fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
704: if (!(fdctrl->state & FD_CTRL_BUSY)) {
705: /* Data transfer allowed */
706: retval |= 0x80;
707: /* Data transfer direction indicator */
708: if (fdctrl->data_dir == FD_DIR_READ)
709: retval |= 0x40;
710: }
711: /* Should handle 0x20 for SPECIFY command */
712: /* Command busy indicator */
713: if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
714: FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
715: retval |= 0x10;
716: FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
717:
718: return retval;
719: }
720:
721: /* Data select rate register : 0x04 (write) */
722: static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
723: {
724: /* Reset mode */
725: if (fdctrl->state & FD_CTRL_RESET) {
726: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
727: return;
728: }
729: FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
730: /* Reset: autoclear */
731: if (value & 0x80) {
732: fdctrl->state |= FD_CTRL_RESET;
733: fdctrl_reset(fdctrl, 1);
734: fdctrl->state &= ~FD_CTRL_RESET;
735: }
736: if (value & 0x40) {
737: fdctrl->state |= FD_CTRL_SLEEP;
738: fdctrl_reset(fdctrl, 1);
739: }
740: // fdctrl.precomp = (value >> 2) & 0x07;
741: }
742:
1.1.1.2 ! root 743: static int fdctrl_media_changed(fdrive_t *drv)
! 744: {
! 745: int ret;
! 746: if (!drv->bs)
! 747: return 0;
! 748: ret = bdrv_media_changed(drv->bs);
! 749: if (ret) {
! 750: fd_revalidate(drv);
! 751: }
! 752: return ret;
! 753: }
! 754:
1.1 root 755: /* Digital input register : 0x07 (read-only) */
756: static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
757: {
758: uint32_t retval = 0;
759:
1.1.1.2 ! root 760: if (fdctrl_media_changed(drv0(fdctrl)) ||
! 761: fdctrl_media_changed(drv1(fdctrl)))
1.1 root 762: retval |= 0x80;
763: if (retval != 0)
764: FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
765:
766: return retval;
767: }
768:
769: /* FIFO state control */
770: static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
771: {
772: fdctrl->data_dir = FD_DIR_WRITE;
773: fdctrl->data_pos = 0;
774: FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
775: }
776:
777: /* Set FIFO status for the host to read */
778: static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
779: {
780: fdctrl->data_dir = FD_DIR_READ;
781: fdctrl->data_len = fifo_len;
782: fdctrl->data_pos = 0;
783: FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
784: if (do_irq)
785: fdctrl_raise_irq(fdctrl, 0x00);
786: }
787:
788: /* Set an error: unimplemented/unknown command */
789: static void fdctrl_unimplemented (fdctrl_t *fdctrl)
790: {
791: #if 0
792: fdrive_t *cur_drv;
793:
794: cur_drv = get_cur_drv(fdctrl);
795: fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
796: fdctrl->fifo[1] = 0x00;
797: fdctrl->fifo[2] = 0x00;
798: fdctrl_set_fifo(fdctrl, 3, 1);
799: #else
800: // fdctrl_reset_fifo(fdctrl);
801: fdctrl->fifo[0] = 0x80;
802: fdctrl_set_fifo(fdctrl, 1, 0);
803: #endif
804: }
805:
806: /* Callback for transfer end (stop or abort) */
807: static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
808: uint8_t status1, uint8_t status2)
809: {
810: fdrive_t *cur_drv;
811:
812: cur_drv = get_cur_drv(fdctrl);
813: FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
814: status0, status1, status2,
815: status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
816: fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
817: fdctrl->fifo[1] = status1;
818: fdctrl->fifo[2] = status2;
819: fdctrl->fifo[3] = cur_drv->track;
820: fdctrl->fifo[4] = cur_drv->head;
821: fdctrl->fifo[5] = cur_drv->sect;
822: fdctrl->fifo[6] = FD_SECTOR_SC;
823: fdctrl->data_dir = FD_DIR_READ;
824: if (fdctrl->state & FD_CTRL_BUSY) {
825: DMA_release_DREQ(fdctrl->dma_chann);
826: fdctrl->state &= ~FD_CTRL_BUSY;
827: }
828: fdctrl_set_fifo(fdctrl, 7, 1);
829: }
830:
831: /* Prepare a data transfer (either DMA or FIFO) */
832: static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
833: {
834: fdrive_t *cur_drv;
835: uint8_t kh, kt, ks;
836: int did_seek;
837:
838: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
839: cur_drv = get_cur_drv(fdctrl);
840: kt = fdctrl->fifo[2];
841: kh = fdctrl->fifo[3];
842: ks = fdctrl->fifo[4];
843: FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
844: fdctrl->cur_drv, kh, kt, ks,
845: _fd_sector(kh, kt, ks, cur_drv->last_sect));
846: did_seek = 0;
847: switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
848: case 2:
849: /* sect too big */
850: fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
851: fdctrl->fifo[3] = kt;
852: fdctrl->fifo[4] = kh;
853: fdctrl->fifo[5] = ks;
854: return;
855: case 3:
856: /* track too big */
857: fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
858: fdctrl->fifo[3] = kt;
859: fdctrl->fifo[4] = kh;
860: fdctrl->fifo[5] = ks;
861: return;
862: case 4:
863: /* No seek enabled */
864: fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
865: fdctrl->fifo[3] = kt;
866: fdctrl->fifo[4] = kh;
867: fdctrl->fifo[5] = ks;
868: return;
869: case 1:
870: did_seek = 1;
871: break;
872: default:
873: break;
874: }
875: /* Set the FIFO state */
876: fdctrl->data_dir = direction;
877: fdctrl->data_pos = 0;
878: FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
879: if (fdctrl->fifo[0] & 0x80)
880: fdctrl->data_state |= FD_STATE_MULTI;
881: else
882: fdctrl->data_state &= ~FD_STATE_MULTI;
883: if (did_seek)
884: fdctrl->data_state |= FD_STATE_SEEK;
885: else
886: fdctrl->data_state &= ~FD_STATE_SEEK;
887: if (fdctrl->fifo[5] == 00) {
888: fdctrl->data_len = fdctrl->fifo[8];
889: } else {
890: int tmp;
1.1.1.2 ! root 891: fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1.1 root 892: tmp = (cur_drv->last_sect - ks + 1);
893: if (fdctrl->fifo[0] & 0x80)
894: tmp += cur_drv->last_sect;
895: fdctrl->data_len *= tmp;
896: }
897: fdctrl->eot = fdctrl->fifo[6];
898: if (fdctrl->dma_en) {
899: int dma_mode;
900: /* DMA transfer are enabled. Check if DMA channel is well programmed */
901: dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
902: dma_mode = (dma_mode >> 2) & 3;
903: FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
904: dma_mode, direction,
905: (128 << fdctrl->fifo[5]) *
906: (cur_drv->last_sect - ks + 1), fdctrl->data_len);
907: if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
908: direction == FD_DIR_SCANH) && dma_mode == 0) ||
909: (direction == FD_DIR_WRITE && dma_mode == 2) ||
910: (direction == FD_DIR_READ && dma_mode == 1)) {
911: /* No access is allowed until DMA transfer has completed */
912: fdctrl->state |= FD_CTRL_BUSY;
913: /* Now, we just have to wait for the DMA controller to
914: * recall us...
915: */
916: DMA_hold_DREQ(fdctrl->dma_chann);
917: DMA_schedule(fdctrl->dma_chann);
918: return;
919: } else {
920: FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
921: }
922: }
923: FLOPPY_DPRINTF("start non-DMA transfer\n");
924: /* IO based transfer: calculate len */
925: fdctrl_raise_irq(fdctrl, 0x00);
926:
927: return;
928: }
929:
930: /* Prepare a transfer of deleted data */
931: static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
932: {
933: /* We don't handle deleted data,
934: * so we don't return *ANYTHING*
935: */
936: fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
937: }
938:
939: /* handlers for DMA transfers */
940: static int fdctrl_transfer_handler (void *opaque, int nchan,
941: int dma_pos, int dma_len)
942: {
943: fdctrl_t *fdctrl;
944: fdrive_t *cur_drv;
945: int len, start_pos, rel_pos;
946: uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
947:
948: fdctrl = opaque;
949: if (!(fdctrl->state & FD_CTRL_BUSY)) {
950: FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
951: return 0;
952: }
953: cur_drv = get_cur_drv(fdctrl);
954: if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
955: fdctrl->data_dir == FD_DIR_SCANH)
956: status2 = 0x04;
957: if (dma_len > fdctrl->data_len)
958: dma_len = fdctrl->data_len;
959: if (cur_drv->bs == NULL) {
960: if (fdctrl->data_dir == FD_DIR_WRITE)
961: fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
962: else
963: fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
964: len = 0;
965: goto transfer_error;
966: }
967: rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
968: for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
969: len = dma_len - fdctrl->data_pos;
970: if (len + rel_pos > FD_SECTOR_LEN)
971: len = FD_SECTOR_LEN - rel_pos;
972: FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
973: "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
974: fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
975: cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
976: fd_sector(cur_drv) * 512);
977: if (fdctrl->data_dir != FD_DIR_WRITE ||
978: len < FD_SECTOR_LEN || rel_pos != 0) {
979: /* READ & SCAN commands and realign to a sector for WRITE */
980: if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
981: fdctrl->fifo, 1) < 0) {
982: FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
983: fd_sector(cur_drv));
984: /* Sure, image size is too small... */
985: memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
986: }
987: }
988: switch (fdctrl->data_dir) {
989: case FD_DIR_READ:
990: /* READ commands */
991: DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
992: fdctrl->data_pos, len);
993: /* cpu_physical_memory_write(addr + fdctrl->data_pos, */
994: /* fdctrl->fifo + rel_pos, len); */
995: break;
996: case FD_DIR_WRITE:
997: /* WRITE commands */
998: DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
999: fdctrl->data_pos, len);
1000: /* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1001: /* fdctrl->fifo + rel_pos, len); */
1002: if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1003: fdctrl->fifo, 1) < 0) {
1004: FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1005: fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1006: goto transfer_error;
1007: }
1008: break;
1009: default:
1010: /* SCAN commands */
1011: {
1012: uint8_t tmpbuf[FD_SECTOR_LEN];
1013: int ret;
1014: DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1015: /* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1016: /* tmpbuf, len); */
1017: ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1018: if (ret == 0) {
1019: status2 = 0x08;
1020: goto end_transfer;
1021: }
1022: if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1023: (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1024: status2 = 0x00;
1025: goto end_transfer;
1026: }
1027: }
1028: break;
1029: }
1030: fdctrl->data_pos += len;
1031: rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1032: if (rel_pos == 0) {
1033: /* Seek to next sector */
1034: FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1035: cur_drv->head, cur_drv->track, cur_drv->sect,
1036: fd_sector(cur_drv),
1037: fdctrl->data_pos - len);
1038: /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1039: error in fact */
1040: if (cur_drv->sect >= cur_drv->last_sect ||
1041: cur_drv->sect == fdctrl->eot) {
1042: cur_drv->sect = 1;
1043: if (FD_MULTI_TRACK(fdctrl->data_state)) {
1044: if (cur_drv->head == 0 &&
1045: (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1046: cur_drv->head = 1;
1047: } else {
1048: cur_drv->head = 0;
1049: cur_drv->track++;
1050: if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1051: break;
1052: }
1053: } else {
1054: cur_drv->track++;
1055: break;
1056: }
1057: FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1058: cur_drv->head, cur_drv->track,
1059: cur_drv->sect, fd_sector(cur_drv));
1060: } else {
1061: cur_drv->sect++;
1062: }
1063: }
1064: }
1065: end_transfer:
1066: len = fdctrl->data_pos - start_pos;
1067: FLOPPY_DPRINTF("end transfer %d %d %d\n",
1068: fdctrl->data_pos, len, fdctrl->data_len);
1069: if (fdctrl->data_dir == FD_DIR_SCANE ||
1070: fdctrl->data_dir == FD_DIR_SCANL ||
1071: fdctrl->data_dir == FD_DIR_SCANH)
1072: status2 = 0x08;
1073: if (FD_DID_SEEK(fdctrl->data_state))
1074: status0 |= 0x20;
1075: fdctrl->data_len -= len;
1076: // if (fdctrl->data_len == 0)
1077: fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1078: transfer_error:
1079:
1080: return len;
1081: }
1082:
1083: /* Data register : 0x05 */
1084: static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
1085: {
1086: fdrive_t *cur_drv;
1087: uint32_t retval = 0;
1088: int pos, len;
1089:
1090: cur_drv = get_cur_drv(fdctrl);
1091: fdctrl->state &= ~FD_CTRL_SLEEP;
1092: if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
1093: FLOPPY_ERROR("can't read data in CMD state\n");
1094: return 0;
1095: }
1096: pos = fdctrl->data_pos;
1097: if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1098: pos %= FD_SECTOR_LEN;
1099: if (pos == 0) {
1100: len = fdctrl->data_len - fdctrl->data_pos;
1101: if (len > FD_SECTOR_LEN)
1102: len = FD_SECTOR_LEN;
1103: bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1104: fdctrl->fifo, len);
1105: }
1106: }
1107: retval = fdctrl->fifo[pos];
1108: if (++fdctrl->data_pos == fdctrl->data_len) {
1109: fdctrl->data_pos = 0;
1110: /* Switch from transfer mode to status mode
1111: * then from status mode to command mode
1112: */
1113: if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1114: fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1115: } else {
1116: fdctrl_reset_fifo(fdctrl);
1117: fdctrl_reset_irq(fdctrl);
1118: }
1119: }
1120: FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1121:
1122: return retval;
1123: }
1124:
1125: static void fdctrl_format_sector (fdctrl_t *fdctrl)
1126: {
1127: fdrive_t *cur_drv;
1128: uint8_t kh, kt, ks;
1129: int did_seek;
1130:
1131: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1132: cur_drv = get_cur_drv(fdctrl);
1133: kt = fdctrl->fifo[6];
1134: kh = fdctrl->fifo[7];
1135: ks = fdctrl->fifo[8];
1136: FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1137: fdctrl->cur_drv, kh, kt, ks,
1138: _fd_sector(kh, kt, ks, cur_drv->last_sect));
1139: did_seek = 0;
1140: switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1141: case 2:
1142: /* sect too big */
1143: fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1144: fdctrl->fifo[3] = kt;
1145: fdctrl->fifo[4] = kh;
1146: fdctrl->fifo[5] = ks;
1147: return;
1148: case 3:
1149: /* track too big */
1150: fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1151: fdctrl->fifo[3] = kt;
1152: fdctrl->fifo[4] = kh;
1153: fdctrl->fifo[5] = ks;
1154: return;
1155: case 4:
1156: /* No seek enabled */
1157: fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1158: fdctrl->fifo[3] = kt;
1159: fdctrl->fifo[4] = kh;
1160: fdctrl->fifo[5] = ks;
1161: return;
1162: case 1:
1163: did_seek = 1;
1164: fdctrl->data_state |= FD_STATE_SEEK;
1165: break;
1166: default:
1167: break;
1168: }
1169: memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1170: if (cur_drv->bs == NULL ||
1171: bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1172: FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));
1173: fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1174: } else {
1175: if (cur_drv->sect == cur_drv->last_sect) {
1176: fdctrl->data_state &= ~FD_STATE_FORMAT;
1177: /* Last sector done */
1178: if (FD_DID_SEEK(fdctrl->data_state))
1179: fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1180: else
1181: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1182: } else {
1183: /* More to do */
1184: fdctrl->data_pos = 0;
1185: fdctrl->data_len = 4;
1186: }
1187: }
1188: }
1189:
1190: static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1191: {
1192: fdrive_t *cur_drv;
1193:
1194: cur_drv = get_cur_drv(fdctrl);
1195: /* Reset mode */
1196: if (fdctrl->state & FD_CTRL_RESET) {
1197: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1198: return;
1199: }
1200: fdctrl->state &= ~FD_CTRL_SLEEP;
1201: if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1202: FLOPPY_ERROR("can't write data in status mode\n");
1203: return;
1204: }
1205: /* Is it write command time ? */
1206: if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1207: /* FIFO data write */
1208: fdctrl->fifo[fdctrl->data_pos++] = value;
1209: if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1210: fdctrl->data_pos == fdctrl->data_len) {
1211: bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1212: fdctrl->fifo, FD_SECTOR_LEN);
1213: }
1214: /* Switch from transfer mode to status mode
1215: * then from status mode to command mode
1216: */
1217: if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1218: fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1219: return;
1220: }
1221: if (fdctrl->data_pos == 0) {
1222: /* Command */
1223: switch (value & 0x5F) {
1224: case 0x46:
1225: /* READ variants */
1226: FLOPPY_DPRINTF("READ command\n");
1227: /* 8 parameters cmd */
1228: fdctrl->data_len = 9;
1229: goto enqueue;
1230: case 0x4C:
1231: /* READ_DELETED variants */
1232: FLOPPY_DPRINTF("READ_DELETED command\n");
1233: /* 8 parameters cmd */
1234: fdctrl->data_len = 9;
1235: goto enqueue;
1236: case 0x50:
1237: /* SCAN_EQUAL variants */
1238: FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1239: /* 8 parameters cmd */
1240: fdctrl->data_len = 9;
1241: goto enqueue;
1242: case 0x56:
1243: /* VERIFY variants */
1244: FLOPPY_DPRINTF("VERIFY command\n");
1245: /* 8 parameters cmd */
1246: fdctrl->data_len = 9;
1247: goto enqueue;
1248: case 0x59:
1249: /* SCAN_LOW_OR_EQUAL variants */
1250: FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1251: /* 8 parameters cmd */
1252: fdctrl->data_len = 9;
1253: goto enqueue;
1254: case 0x5D:
1255: /* SCAN_HIGH_OR_EQUAL variants */
1256: FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1257: /* 8 parameters cmd */
1258: fdctrl->data_len = 9;
1259: goto enqueue;
1260: default:
1261: break;
1262: }
1263: switch (value & 0x7F) {
1264: case 0x45:
1265: /* WRITE variants */
1266: FLOPPY_DPRINTF("WRITE command\n");
1267: /* 8 parameters cmd */
1268: fdctrl->data_len = 9;
1269: goto enqueue;
1270: case 0x49:
1271: /* WRITE_DELETED variants */
1272: FLOPPY_DPRINTF("WRITE_DELETED command\n");
1273: /* 8 parameters cmd */
1274: fdctrl->data_len = 9;
1275: goto enqueue;
1276: default:
1277: break;
1278: }
1279: switch (value) {
1280: case 0x03:
1281: /* SPECIFY */
1282: FLOPPY_DPRINTF("SPECIFY command\n");
1283: /* 1 parameter cmd */
1284: fdctrl->data_len = 3;
1285: goto enqueue;
1286: case 0x04:
1287: /* SENSE_DRIVE_STATUS */
1288: FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1289: /* 1 parameter cmd */
1290: fdctrl->data_len = 2;
1291: goto enqueue;
1292: case 0x07:
1293: /* RECALIBRATE */
1294: FLOPPY_DPRINTF("RECALIBRATE command\n");
1295: /* 1 parameter cmd */
1296: fdctrl->data_len = 2;
1297: goto enqueue;
1298: case 0x08:
1299: /* SENSE_INTERRUPT_STATUS */
1300: FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1301: fdctrl->int_status);
1302: /* No parameters cmd: returns status if no interrupt */
1303: #if 0
1304: fdctrl->fifo[0] =
1305: fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1306: #else
1307: /* XXX: int_status handling is broken for read/write
1308: commands, so we do this hack. It should be suppressed
1309: ASAP */
1310: fdctrl->fifo[0] =
1311: 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1312: #endif
1313: fdctrl->fifo[1] = cur_drv->track;
1314: fdctrl_set_fifo(fdctrl, 2, 0);
1315: fdctrl_reset_irq(fdctrl);
1316: fdctrl->int_status = 0xC0;
1317: return;
1318: case 0x0E:
1319: /* DUMPREG */
1320: FLOPPY_DPRINTF("DUMPREG command\n");
1321: /* Drives position */
1322: fdctrl->fifo[0] = drv0(fdctrl)->track;
1323: fdctrl->fifo[1] = drv1(fdctrl)->track;
1324: fdctrl->fifo[2] = 0;
1325: fdctrl->fifo[3] = 0;
1326: /* timers */
1327: fdctrl->fifo[4] = fdctrl->timer0;
1328: fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1329: fdctrl->fifo[6] = cur_drv->last_sect;
1330: fdctrl->fifo[7] = (fdctrl->lock << 7) |
1331: (cur_drv->perpendicular << 2);
1332: fdctrl->fifo[8] = fdctrl->config;
1333: fdctrl->fifo[9] = fdctrl->precomp_trk;
1334: fdctrl_set_fifo(fdctrl, 10, 0);
1335: return;
1336: case 0x0F:
1337: /* SEEK */
1338: FLOPPY_DPRINTF("SEEK command\n");
1339: /* 2 parameters cmd */
1340: fdctrl->data_len = 3;
1341: goto enqueue;
1342: case 0x10:
1343: /* VERSION */
1344: FLOPPY_DPRINTF("VERSION command\n");
1345: /* No parameters cmd */
1346: /* Controller's version */
1347: fdctrl->fifo[0] = fdctrl->version;
1348: fdctrl_set_fifo(fdctrl, 1, 1);
1349: return;
1350: case 0x12:
1351: /* PERPENDICULAR_MODE */
1352: FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1353: /* 1 parameter cmd */
1354: fdctrl->data_len = 2;
1355: goto enqueue;
1356: case 0x13:
1357: /* CONFIGURE */
1358: FLOPPY_DPRINTF("CONFIGURE command\n");
1359: /* 3 parameters cmd */
1360: fdctrl->data_len = 4;
1361: goto enqueue;
1362: case 0x14:
1363: /* UNLOCK */
1364: FLOPPY_DPRINTF("UNLOCK command\n");
1365: /* No parameters cmd */
1366: fdctrl->lock = 0;
1367: fdctrl->fifo[0] = 0;
1368: fdctrl_set_fifo(fdctrl, 1, 0);
1369: return;
1370: case 0x17:
1371: /* POWERDOWN_MODE */
1372: FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1373: /* 2 parameters cmd */
1374: fdctrl->data_len = 3;
1375: goto enqueue;
1376: case 0x18:
1377: /* PART_ID */
1378: FLOPPY_DPRINTF("PART_ID command\n");
1379: /* No parameters cmd */
1380: fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1381: fdctrl_set_fifo(fdctrl, 1, 0);
1382: return;
1383: case 0x2C:
1384: /* SAVE */
1385: FLOPPY_DPRINTF("SAVE command\n");
1386: /* No parameters cmd */
1387: fdctrl->fifo[0] = 0;
1388: fdctrl->fifo[1] = 0;
1389: /* Drives position */
1390: fdctrl->fifo[2] = drv0(fdctrl)->track;
1391: fdctrl->fifo[3] = drv1(fdctrl)->track;
1392: fdctrl->fifo[4] = 0;
1393: fdctrl->fifo[5] = 0;
1394: /* timers */
1395: fdctrl->fifo[6] = fdctrl->timer0;
1396: fdctrl->fifo[7] = fdctrl->timer1;
1397: fdctrl->fifo[8] = cur_drv->last_sect;
1398: fdctrl->fifo[9] = (fdctrl->lock << 7) |
1399: (cur_drv->perpendicular << 2);
1400: fdctrl->fifo[10] = fdctrl->config;
1401: fdctrl->fifo[11] = fdctrl->precomp_trk;
1402: fdctrl->fifo[12] = fdctrl->pwrd;
1403: fdctrl->fifo[13] = 0;
1404: fdctrl->fifo[14] = 0;
1405: fdctrl_set_fifo(fdctrl, 15, 1);
1406: return;
1407: case 0x33:
1408: /* OPTION */
1409: FLOPPY_DPRINTF("OPTION command\n");
1410: /* 1 parameter cmd */
1411: fdctrl->data_len = 2;
1412: goto enqueue;
1413: case 0x42:
1414: /* READ_TRACK */
1415: FLOPPY_DPRINTF("READ_TRACK command\n");
1416: /* 8 parameters cmd */
1417: fdctrl->data_len = 9;
1418: goto enqueue;
1419: case 0x4A:
1420: /* READ_ID */
1421: FLOPPY_DPRINTF("READ_ID command\n");
1422: /* 1 parameter cmd */
1423: fdctrl->data_len = 2;
1424: goto enqueue;
1425: case 0x4C:
1426: /* RESTORE */
1427: FLOPPY_DPRINTF("RESTORE command\n");
1428: /* 17 parameters cmd */
1429: fdctrl->data_len = 18;
1430: goto enqueue;
1431: case 0x4D:
1432: /* FORMAT_TRACK */
1433: FLOPPY_DPRINTF("FORMAT_TRACK command\n");
1434: /* 5 parameters cmd */
1435: fdctrl->data_len = 6;
1436: goto enqueue;
1437: case 0x8E:
1438: /* DRIVE_SPECIFICATION_COMMAND */
1439: FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
1440: /* 5 parameters cmd */
1441: fdctrl->data_len = 6;
1442: goto enqueue;
1443: case 0x8F:
1444: /* RELATIVE_SEEK_OUT */
1445: FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
1446: /* 2 parameters cmd */
1447: fdctrl->data_len = 3;
1448: goto enqueue;
1449: case 0x94:
1450: /* LOCK */
1451: FLOPPY_DPRINTF("LOCK command\n");
1452: /* No parameters cmd */
1453: fdctrl->lock = 1;
1454: fdctrl->fifo[0] = 0x10;
1455: fdctrl_set_fifo(fdctrl, 1, 1);
1456: return;
1457: case 0xCD:
1458: /* FORMAT_AND_WRITE */
1459: FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
1460: /* 10 parameters cmd */
1461: fdctrl->data_len = 11;
1462: goto enqueue;
1463: case 0xCF:
1464: /* RELATIVE_SEEK_IN */
1465: FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
1466: /* 2 parameters cmd */
1467: fdctrl->data_len = 3;
1468: goto enqueue;
1469: default:
1470: /* Unknown command */
1471: FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1472: fdctrl_unimplemented(fdctrl);
1473: return;
1474: }
1475: }
1476: enqueue:
1477: FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1478: fdctrl->fifo[fdctrl->data_pos] = value;
1479: if (++fdctrl->data_pos == fdctrl->data_len) {
1480: /* We now have all parameters
1481: * and will be able to treat the command
1482: */
1483: if (fdctrl->data_state & FD_STATE_FORMAT) {
1484: fdctrl_format_sector(fdctrl);
1485: return;
1486: }
1487: switch (fdctrl->fifo[0] & 0x1F) {
1488: case 0x06:
1489: {
1490: /* READ variants */
1491: FLOPPY_DPRINTF("treat READ command\n");
1492: fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1493: return;
1494: }
1495: case 0x0C:
1496: /* READ_DELETED variants */
1497: // FLOPPY_DPRINTF("treat READ_DELETED command\n");
1498: FLOPPY_ERROR("treat READ_DELETED command\n");
1499: fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
1500: return;
1501: case 0x16:
1502: /* VERIFY variants */
1503: // FLOPPY_DPRINTF("treat VERIFY command\n");
1504: FLOPPY_ERROR("treat VERIFY command\n");
1505: fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1506: return;
1507: case 0x10:
1508: /* SCAN_EQUAL variants */
1509: // FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
1510: FLOPPY_ERROR("treat SCAN_EQUAL command\n");
1511: fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
1512: return;
1513: case 0x19:
1514: /* SCAN_LOW_OR_EQUAL variants */
1515: // FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
1516: FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
1517: fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
1518: return;
1519: case 0x1D:
1520: /* SCAN_HIGH_OR_EQUAL variants */
1521: // FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
1522: FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
1523: fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
1524: return;
1525: default:
1526: break;
1527: }
1528: switch (fdctrl->fifo[0] & 0x3F) {
1529: case 0x05:
1530: /* WRITE variants */
1531: FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
1532: fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
1533: return;
1534: case 0x09:
1535: /* WRITE_DELETED variants */
1536: // FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
1537: FLOPPY_ERROR("treat WRITE_DELETED command\n");
1538: fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
1539: return;
1540: default:
1541: break;
1542: }
1543: switch (fdctrl->fifo[0]) {
1544: case 0x03:
1545: /* SPECIFY */
1546: FLOPPY_DPRINTF("treat SPECIFY command\n");
1547: fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1548: fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1549: fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
1550: /* No result back */
1551: fdctrl_reset_fifo(fdctrl);
1552: break;
1553: case 0x04:
1554: /* SENSE_DRIVE_STATUS */
1555: FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
1556: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1557: cur_drv = get_cur_drv(fdctrl);
1558: cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1559: /* 1 Byte status back */
1560: fdctrl->fifo[0] = (cur_drv->ro << 6) |
1561: (cur_drv->track == 0 ? 0x10 : 0x00) |
1562: (cur_drv->head << 2) |
1563: fdctrl->cur_drv |
1564: 0x28;
1565: fdctrl_set_fifo(fdctrl, 1, 0);
1566: break;
1567: case 0x07:
1568: /* RECALIBRATE */
1569: FLOPPY_DPRINTF("treat RECALIBRATE command\n");
1570: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1571: cur_drv = get_cur_drv(fdctrl);
1572: fd_recalibrate(cur_drv);
1573: fdctrl_reset_fifo(fdctrl);
1574: /* Raise Interrupt */
1575: fdctrl_raise_irq(fdctrl, 0x20);
1576: break;
1577: case 0x0F:
1578: /* SEEK */
1579: FLOPPY_DPRINTF("treat SEEK command\n");
1580: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1581: cur_drv = get_cur_drv(fdctrl);
1582: fd_start(cur_drv);
1583: if (fdctrl->fifo[2] <= cur_drv->track)
1584: cur_drv->dir = 1;
1585: else
1586: cur_drv->dir = 0;
1587: fdctrl_reset_fifo(fdctrl);
1588: if (fdctrl->fifo[2] > cur_drv->max_track) {
1589: fdctrl_raise_irq(fdctrl, 0x60);
1590: } else {
1591: cur_drv->track = fdctrl->fifo[2];
1592: /* Raise Interrupt */
1593: fdctrl_raise_irq(fdctrl, 0x20);
1594: }
1595: break;
1596: case 0x12:
1597: /* PERPENDICULAR_MODE */
1598: FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
1599: if (fdctrl->fifo[1] & 0x80)
1600: cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1601: /* No result back */
1602: fdctrl_reset_fifo(fdctrl);
1603: break;
1604: case 0x13:
1605: /* CONFIGURE */
1606: FLOPPY_DPRINTF("treat CONFIGURE command\n");
1607: fdctrl->config = fdctrl->fifo[2];
1608: fdctrl->precomp_trk = fdctrl->fifo[3];
1609: /* No result back */
1610: fdctrl_reset_fifo(fdctrl);
1611: break;
1612: case 0x17:
1613: /* POWERDOWN_MODE */
1614: FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
1615: fdctrl->pwrd = fdctrl->fifo[1];
1616: fdctrl->fifo[0] = fdctrl->fifo[1];
1617: fdctrl_set_fifo(fdctrl, 1, 1);
1618: break;
1619: case 0x33:
1620: /* OPTION */
1621: FLOPPY_DPRINTF("treat OPTION command\n");
1622: /* No result back */
1623: fdctrl_reset_fifo(fdctrl);
1624: break;
1625: case 0x42:
1626: /* READ_TRACK */
1627: // FLOPPY_DPRINTF("treat READ_TRACK command\n");
1628: FLOPPY_ERROR("treat READ_TRACK command\n");
1629: fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1630: break;
1631: case 0x4A:
1632: /* READ_ID */
1633: FLOPPY_DPRINTF("treat READ_ID command\n");
1634: /* XXX: should set main status register to busy */
1635: cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1636: qemu_mod_timer(fdctrl->result_timer,
1637: qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1638: break;
1639: case 0x4C:
1640: /* RESTORE */
1641: FLOPPY_DPRINTF("treat RESTORE command\n");
1642: /* Drives position */
1643: drv0(fdctrl)->track = fdctrl->fifo[3];
1644: drv1(fdctrl)->track = fdctrl->fifo[4];
1645: /* timers */
1646: fdctrl->timer0 = fdctrl->fifo[7];
1647: fdctrl->timer1 = fdctrl->fifo[8];
1648: cur_drv->last_sect = fdctrl->fifo[9];
1649: fdctrl->lock = fdctrl->fifo[10] >> 7;
1650: cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1651: fdctrl->config = fdctrl->fifo[11];
1652: fdctrl->precomp_trk = fdctrl->fifo[12];
1653: fdctrl->pwrd = fdctrl->fifo[13];
1654: fdctrl_reset_fifo(fdctrl);
1655: break;
1656: case 0x4D:
1657: /* FORMAT_TRACK */
1658: FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
1659: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1660: cur_drv = get_cur_drv(fdctrl);
1661: fdctrl->data_state |= FD_STATE_FORMAT;
1662: if (fdctrl->fifo[0] & 0x80)
1663: fdctrl->data_state |= FD_STATE_MULTI;
1664: else
1665: fdctrl->data_state &= ~FD_STATE_MULTI;
1666: fdctrl->data_state &= ~FD_STATE_SEEK;
1667: cur_drv->bps =
1668: fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1669: #if 0
1670: cur_drv->last_sect =
1671: cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1672: fdctrl->fifo[3] / 2;
1673: #else
1674: cur_drv->last_sect = fdctrl->fifo[3];
1675: #endif
1.1.1.2 ! root 1676: /* TODO: implement format using DMA expected by the Bochs BIOS
! 1677: * and Linux fdformat (read 3 bytes per sector via DMA and fill
! 1678: * the sector with the specified fill byte
1.1 root 1679: */
1680: fdctrl->data_state &= ~FD_STATE_FORMAT;
1681: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1682: break;
1683: case 0x8E:
1684: /* DRIVE_SPECIFICATION_COMMAND */
1685: FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
1686: if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1687: /* Command parameters done */
1688: if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1689: fdctrl->fifo[0] = fdctrl->fifo[1];
1690: fdctrl->fifo[2] = 0;
1691: fdctrl->fifo[3] = 0;
1692: fdctrl_set_fifo(fdctrl, 4, 1);
1693: } else {
1694: fdctrl_reset_fifo(fdctrl);
1695: }
1696: } else if (fdctrl->data_len > 7) {
1697: /* ERROR */
1698: fdctrl->fifo[0] = 0x80 |
1699: (cur_drv->head << 2) | fdctrl->cur_drv;
1700: fdctrl_set_fifo(fdctrl, 1, 1);
1701: }
1702: break;
1703: case 0x8F:
1704: /* RELATIVE_SEEK_OUT */
1705: FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
1706: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1707: cur_drv = get_cur_drv(fdctrl);
1708: fd_start(cur_drv);
1709: cur_drv->dir = 0;
1710: if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1711: cur_drv->track = cur_drv->max_track - 1;
1712: } else {
1713: cur_drv->track += fdctrl->fifo[2];
1714: }
1715: fdctrl_reset_fifo(fdctrl);
1716: fdctrl_raise_irq(fdctrl, 0x20);
1717: break;
1718: case 0xCD:
1719: /* FORMAT_AND_WRITE */
1720: // FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
1721: FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
1722: fdctrl_unimplemented(fdctrl);
1723: break;
1724: case 0xCF:
1725: /* RELATIVE_SEEK_IN */
1726: FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
1727: fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1728: cur_drv = get_cur_drv(fdctrl);
1729: fd_start(cur_drv);
1730: cur_drv->dir = 1;
1731: if (fdctrl->fifo[2] > cur_drv->track) {
1732: cur_drv->track = 0;
1733: } else {
1734: cur_drv->track -= fdctrl->fifo[2];
1735: }
1736: fdctrl_reset_fifo(fdctrl);
1737: /* Raise Interrupt */
1738: fdctrl_raise_irq(fdctrl, 0x20);
1739: break;
1740: }
1741: }
1742: }
1743:
1744: static void fdctrl_result_timer(void *opaque)
1745: {
1746: fdctrl_t *fdctrl = opaque;
1747: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1748: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.