2 * IDE Emulation Layer for retro-style PIO interfaces
4 * (c) Copyright Alan Cox, 2015-2019
6 * IDE-emu is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * IDE-emu is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with IDE-emu. If not, see <http://www.gnu.org/licenses/>.
27 #include <arpa/inet.h>
29 #include "config_file/config_file.h"
35 #define IDE_DATA_OUT 3
64 #define IDE_CMD_CALIB 0x10
65 #define IDE_CMD_READ 0x20
66 #define IDE_CMD_READ_NR 0x21
67 #define IDE_CMD_WRITE 0x30
68 #define IDE_CMD_WRITE_NR 0x31
69 #define IDE_CMD_VERIFY 0x40
70 #define IDE_CMD_VERIFY_NR 0x41
71 #define IDE_CMD_SEEK 0x70
72 #define IDE_CMD_EDD 0x90
73 #define IDE_CMD_INTPARAMS 0x91
74 #define IDE_CMD_IDENTIFY 0xEC
75 #define IDE_CMD_SETFEATURES 0xEF
77 const uint8_t ide_magic[9] = {
78 '1','D','E','D','1','5','C','0',0x00
81 static char *charmap(uint8_t v)
85 sprintf(cbuf, "^%c", '@'+v);
87 sprintf(cbuf, " %c", v);
91 sprintf(cbuf, ":%c", '@' + v - 128);
93 sprintf(cbuf, "~%c", v - 128);
99 static void hexdump(uint8_t *bp)
102 for (i = 0; i < 512; i+= 16) {
103 for(j = 0; j < 16; j++)
104 fprintf(stderr, "%02X ", bp[i+j]);
105 fprintf(stderr, "|");
106 for(j = 0; j < 16; j++)
107 fprintf(stderr, "%2s", charmap(bp[i+j]));
108 fprintf(stderr, "\n");
112 /* FIXME: use proper endian convertors! */
113 static uint16_t le16(uint16_t v)
115 uint8_t *p = (uint8_t *)&v;
116 return p[0] | (p[1] << 8);
119 static void ide_xlate_errno(struct ide_taskfile *t, int len)
131 static void ide_fault(struct ide_drive *d, const char *p)
133 fprintf(stderr, "ide: %s: %d: %s\n", d->controller->name,
134 (int)(d - d->controller->drive), p);
137 /* Disk translation */
138 static off_t xlate_block(struct ide_taskfile *t)
140 struct ide_drive *d = t->drive;
143 if (d->controller->lba4 & DEVH_LBA) {
144 /* fprintf(stderr, "XLATE LBA %02X:%02X:%02X:%02X\n",
145 t->lba4, t->lba3, t->lba2, t->lba1);*/
147 return ((d->header_present) ? 2 : 0) + (((t->drive->controller->lba4 & DEVH_HEAD) << 24) | (t->drive->controller->lba3 << 16) | (t->drive->controller->lba2 << 8) | t->drive->controller->lba1);
148 ide_fault(d, "LBA on non LBA drive");
151 /* Some well known software asks for 0/0/0 when it means 0/0/1. Drives appear
152 to interpret sector 0 as sector 1 */
153 if (t->drive->controller->lba1 == 0) {
154 fprintf(stderr, "[Bug: request for sector offset 0].\n");
155 t->drive->controller->lba1 = 1;
157 cyl = (t->drive->controller->lba3 << 8) | t->drive->controller->lba2;
158 /* fprintf(stderr, "(H %d C %d S %d)\n", t->lba4 & DEVH_HEAD, cyl, t->lba1); */
159 if (t->drive->controller->lba1 == 0 || t->drive->controller->lba1 > d->sectors || t->drive->controller->lba4 >= d->heads || cyl >= d->cylinders) {
162 /* Sector 1 is first */
163 /* Images generally go cylinder/head/sector. This also matters if we ever
164 implement more advanced geometry setting */
165 //off_t ret = ((d->header_present) ? 1 : -1) + ((cyl * d->heads) + (t->drive->controller->lba4 & DEVH_HEAD)) * d->sectors + t->drive->controller->lba1;
166 //printf("Non-LBA xlate block %lX.\n", ret);
167 //printf("Cyl: %d Heads: %d Sectors: %d\n", cyl, d->heads, d->sectors);
168 //printf("LBA1: %.2X LBA2: %.2X LBA3: %.2X LBA4: %.2X\n", t->drive->controller->lba1, t->drive->controller->lba2, t->drive->controller->lba3, t->drive->controller->lba4);
170 return ((d->header_present) ? 1 : -1) + ((cyl * d->heads) + (t->drive->controller->lba4 & DEVH_HEAD)) * d->sectors + t->drive->controller->lba1;
173 /* Indicate the drive is ready */
174 static void ready(struct ide_taskfile *tf)
176 tf->status &= ~(ST_BSY|ST_DRQ);
177 tf->status |= ST_DRDY;
178 tf->drive->state = IDE_IDLE;
181 /* Return to idle state, completing a command */
182 static void completed(struct ide_taskfile *tf)
185 tf->drive->intrq = 1;
188 static void drive_failed(struct ide_taskfile *tf)
190 tf->status |= ST_ERR;
191 tf->error = ERR_IDNF;
195 static void data_in_state(struct ide_taskfile *tf)
197 struct ide_drive *d = tf->drive;
198 d->state = IDE_DATA_IN;
199 d->dptr = d->data + 512;
200 /* We don't clear DRDY here, drives may well accept a command at this
201 point and at least one firmware for RC2014 assumes this */
202 tf->status &= ~ST_BSY;
203 tf->status |= ST_DRQ;
204 d->intrq = 1; /* Double check */
207 static void data_out_state(struct ide_taskfile *tf)
209 struct ide_drive *d = tf->drive;
210 d->state = IDE_DATA_OUT;
212 tf->status &= ~ (ST_BSY|ST_DRDY);
213 tf->status |= ST_DRQ;
214 d->intrq = 1; /* Double check */
217 static void edd_setup(struct ide_taskfile *tf)
219 tf->error = 0x01; /* All good */
220 tf->drive->controller->lba1 = 0x01; /* EDD always updates drive 0 */
221 tf->drive->controller->lba2 = 0x00;
222 tf->drive->controller->lba3 = 0x00;
223 tf->drive->controller->lba4 = 0x00;
228 void ide_reset(struct ide_controller *c)
230 if (c->drive[0].present) {
231 edd_setup(&c->drive[0].taskfile);
232 /* A drive could clear busy then set DRDY up to 2 minutes later if its
233 mindnumbingly slow to start up ! We don't emulate any of that */
234 c->drive[0].taskfile.status = ST_DRDY;
235 c->drive[0].eightbit = 0;
237 if (c->drive[1].present) {
238 edd_setup(&c->drive[1].taskfile);
239 c->drive[1].taskfile.status = ST_DRDY;
240 c->drive[1].eightbit = 0;
242 if (c->selected != 0) {
247 void ide_reset_begin(struct ide_controller *c)
249 if (c->drive[0].present)
250 c->drive[0].taskfile.status |= ST_BSY;
251 if (c->drive[1].present)
252 c->drive[1].taskfile.status |= ST_BSY;
253 /* Ought to be a time delay relative to reset or power on */
257 static void ide_srst_begin(struct ide_controller *c)
260 if (c->drive[0].present)
261 c->drive[0].taskfile.status |= ST_BSY;
262 if (c->drive[1].present)
263 c->drive[1].taskfile.status |= ST_BSY;
266 static void ide_srst_end(struct ide_controller *c)
268 /* Could be time delays here */
269 ready(&c->drive[0].taskfile);
270 ready(&c->drive[1].taskfile);
273 static void cmd_edd_complete(struct ide_taskfile *tf)
275 struct ide_controller *c = tf->drive->controller;
276 if (c->drive[0].present)
277 edd_setup(&c->drive[0].taskfile);
278 if (c->drive[1].present)
279 edd_setup(&c->drive[1].taskfile);
283 static void cmd_identify_complete(struct ide_taskfile *tf)
285 struct ide_drive *d = tf->drive;
286 memcpy(d->data, d->identify, 512);
288 /* Arrange to copy just the identify buffer */
293 static void cmd_initparam_complete(struct ide_taskfile *tf)
295 struct ide_drive *d = tf->drive;
296 /* We only support the current mapping */
297 if (tf->count != d->sectors || (tf->drive->controller->lba4 & DEVH_HEAD) + 1 != d->heads) {
298 tf->status |= ST_ERR;
299 tf->error |= ERR_ABRT;
300 tf->drive->failed = 1; /* Report ID NF until fixed */
301 /* fprintf(stderr, "geo is %d %d, asked for %d %d\n",
302 d->sectors, d->heads, tf->count, (tf->lba4 & DEVH_HEAD) + 1); */
303 ide_fault(d, "invalid geometry");
304 } else if (tf->drive->failed == 1)
305 tf->drive->failed = 0; /* Valid translation */
309 static void cmd_readsectors_complete(struct ide_taskfile *tf)
311 struct ide_drive *d = tf->drive;
312 /* Move to data xfer */
317 d->offset = xlate_block(tf);
318 /* DRDY is not guaranteed here but at least one buggy RC2014 firmware
320 tf->status |= ST_DRQ | ST_DSC | ST_DRDY;
321 tf->status &= ~ST_BSY;
322 /* 0 = 256 sectors */
323 d->length = tf->count ? tf->count : 256;
324 /* fprintf(stderr, "READ %d SECTORS @ %ld\n", d->length, d->offset); */
325 if (d->offset == -1 || lseek(d->fd, 512 * d->offset, SEEK_SET) == -1) {
326 tf->status |= ST_ERR;
327 tf->status &= ~ST_DSC;
328 tf->error |= ERR_IDNF;
329 /* return null data */
337 static void cmd_verifysectors_complete(struct ide_taskfile *tf)
339 struct ide_drive *d = tf->drive;
340 /* Move to data xfer */
345 d->offset = xlate_block(tf);
346 /* 0 = 256 sectors */
347 d->length = tf->count ? tf->count : 256;
348 if (d->offset == -1 || lseek(d->fd, 512 * (d->offset + d->length - 1), SEEK_SET) == -1) {
349 tf->status &= ~ST_DSC;
350 tf->status |= ST_ERR;
351 tf->error |= ERR_IDNF;
353 tf->status |= ST_DSC;
357 static void cmd_recalibrate_complete(struct ide_taskfile *tf)
359 struct ide_drive *d = tf->drive;
362 if (d->offset == -1 || xlate_block(tf) != 0L) {
363 tf->status &= ~ST_DSC;
364 tf->status |= ST_ERR;
365 tf->error |= ERR_ABRT;
367 tf->status |= ST_DSC;
371 static void cmd_seek_complete(struct ide_taskfile *tf)
373 struct ide_drive *d = tf->drive;
376 d->offset = xlate_block(tf);
377 if (d->offset == -1 || lseek(d->fd, 512 * d->offset, SEEK_SET) == -1) {
378 tf->status &= ~ST_DSC;
379 tf->status |= ST_ERR;
380 tf->error |= ERR_IDNF;
382 tf->status |= ST_DSC;
386 static void cmd_setfeatures_complete(struct ide_taskfile *tf)
388 struct ide_drive *d = tf->drive;
389 switch(tf->feature) {
394 if ((tf->count & 0xF0) >= 0x20) {
395 tf->status |= ST_ERR;
396 tf->error |= ERR_ABRT;
398 /* Silently accept PIO mode settings */
404 tf->status |= ST_ERR;
405 tf->error |= ERR_ABRT;
410 static void cmd_writesectors_complete(struct ide_taskfile *tf)
412 struct ide_drive *d = tf->drive;
413 /* Move to data xfer */
418 d->offset = xlate_block(tf);
419 tf->status |= ST_DRQ;
420 /* 0 = 256 sectors */
421 d->length = tf->count ? tf->count : 256;
422 /* fprintf(stderr, "WRITE %d SECTORS @ %ld\n", d->length, d->offset); */
423 if (d->offset == -1 || lseek(d->fd, 512 * d->offset, SEEK_SET) == -1) {
424 tf->status |= ST_ERR;
425 tf->error |= ERR_IDNF;
426 tf->status &= ~ST_DSC;
427 /* return null data */
435 static void ide_set_error(struct ide_drive *d)
437 d->controller->lba4 &= ~DEVH_HEAD;
439 if (d->controller->lba4 & DEVH_LBA) {
440 d->controller->lba1 = d->offset & 0xFF;
441 d->controller->lba2 = (d->offset >> 8) & 0xFF;
442 d->controller->lba3 = (d->offset >> 16) & 0xFF;
443 d->controller->lba4 |= (d->offset >> 24) & DEVH_HEAD;
445 d->controller->lba1 = d->offset % d->sectors + 1;
446 d->offset /= d->sectors;
447 d->controller->lba4 |= d->offset / (d->cylinders * d->sectors);
448 d->offset %= (d->cylinders * d->sectors);
449 d->controller->lba2 = d->offset & 0xFF;
450 d->controller->lba3 = (d->offset >> 8) & 0xFF;
452 d->taskfile.count = d->length;
453 d->taskfile.status |= ST_ERR;
455 completed(&d->taskfile);
458 static int ide_read_sector(struct ide_drive *d)
463 if ((len = read(d->fd, d->data, 512)) != 512) {
464 perror("ide_read_sector");
465 d->taskfile.status |= ST_ERR;
466 d->taskfile.status &= ~ST_DSC;
467 ide_xlate_errno(&d->taskfile, len);
475 static int ide_write_sector(struct ide_drive *d)
480 if ((len = write(d->fd, d->data, 512)) != 512) {
481 d->taskfile.status |= ST_ERR;
482 d->taskfile.status &= ~ST_DSC;
483 ide_xlate_errno(&d->taskfile, len);
491 static uint16_t ide_data_in(struct ide_drive *d, int len)
494 if (d->state == IDE_DATA_IN) {
495 if (d->dptr == d->data + 512) {
496 if (ide_read_sector(d) < 0) {
497 ide_set_error(d); /* Set the LBA or CHS etc */
498 return 0xFFFF; /* and error bits set by read_sector */
504 v |= (d->dptr[1] << 8);
508 d->taskfile.data = v;
509 if (d->dptr == d->data + 512) {
511 d->intrq = 1; /* we don't yet emulate multimode */
512 if (d->length == 0) {
514 completed(&d->taskfile);
518 ide_fault(d, "bad data read");
521 return d->taskfile.data & 0xFF;
522 return d->taskfile.data;
525 static void ide_data_out(struct ide_drive *d, uint16_t v, int len)
528 if (d->state != IDE_DATA_OUT) {
529 ide_fault(d, "bad data write");
530 d->taskfile.data = v;
535 d->taskfile.data = v;
538 d->taskfile.data = v >> 8;
540 if (d->dptr == d->data + 512) {
541 if (ide_write_sector(d) < 0) {
547 if (d->length == 0) {
549 d->taskfile.status |= ST_DSC;
550 completed(&d->taskfile);
556 static void ide_issue_command(struct ide_taskfile *t)
558 t->status &= ~(ST_ERR|ST_DRDY);
561 t->drive->state = IDE_CMD;
563 /* We could complete with delays but don't do so yet */
565 case IDE_CMD_EDD: /* 0x90 */
568 case IDE_CMD_IDENTIFY: /* 0xEC */
569 cmd_identify_complete(t);
571 case IDE_CMD_INTPARAMS: /* 0x91 */
572 cmd_initparam_complete(t);
574 case IDE_CMD_READ: /* 0x20 */
575 case IDE_CMD_READ_NR: /* 0x21 */
576 cmd_readsectors_complete(t);
578 case IDE_CMD_SETFEATURES: /* 0xEF */
579 cmd_setfeatures_complete(t);
581 case IDE_CMD_VERIFY: /* 0x40 */
582 case IDE_CMD_VERIFY_NR: /* 0x41 */
583 cmd_verifysectors_complete(t);
585 case IDE_CMD_WRITE: /* 0x30 */
586 case IDE_CMD_WRITE_NR: /* 0x31 */
587 cmd_writesectors_complete(t);
590 if ((t->command & 0xF0) == IDE_CMD_CALIB) /* 1x */
591 cmd_recalibrate_complete(t);
592 else if ((t->command & 0xF0) == IDE_CMD_SEEK) /* 7x */
593 cmd_seek_complete(t);
597 t->error |= ERR_ABRT;
604 * 8bit IDE controller emulation
607 uint8_t ide_read8(struct ide_controller *c, uint8_t r)
609 struct ide_drive *d = &c->drive[c->selected];
610 struct ide_taskfile *t = &d->taskfile;
613 return ide_data_in(d, 1);
625 return c->lba4 | ((c->selected) ? 0x10 : 0x00);
627 d->intrq = 0; /* Acked */
633 ide_fault(d, "bogus register");
638 void ide_write8(struct ide_controller *c, uint8_t r, uint8_t v)
640 struct ide_drive *d = &c->drive[c->selected];
641 struct ide_taskfile *t = &d->taskfile;
643 if (r != ide_devctrl_w) {
644 if (t->status & ST_BSY) {
645 ide_fault(d, "command written while busy");
648 /* Not clear this is the right emulation */
649 if (d->present == 0 && r != ide_lba_top) {
650 ide_fault(d, "not present");
659 ide_data_out(d, v, 1);
677 c->selected = (v & DEVH_DEV) ? 1 : 0;
678 c->lba4 = v & (DEVH_HEAD|/*DEVH_DEV|*/DEVH_LBA);
682 ide_issue_command(t);
685 /* ATA: "When the Device Control register is written, both devices
686 respond to the write regardless of which device is selected" */
687 if ((v ^ t->devctrl) & DCL_SRST) {
693 c->drive[0].taskfile.devctrl = v; /* Check versus real h/w does this end up cleared */
694 c->drive[1].taskfile.devctrl = v;
700 * 16bit IDE controller emulation
703 uint16_t ide_read16(struct ide_controller *c, uint8_t r)
705 struct ide_drive *d = &c->drive[c->selected];
707 return htons(ide_data_in(d,2));
708 return ide_read8(c, r);
711 void ide_write16(struct ide_controller *c, uint8_t r, uint16_t v)
713 struct ide_drive *d = &c->drive[c->selected];
714 struct ide_taskfile *t = &d->taskfile;
716 if (r != ide_devctrl_w && (t->status & ST_BSY)) {
717 ide_fault(d, "command written while busy");
721 ide_data_out(d, ntohs(v), 2);
727 * Allocate a new IDE controller emulation
729 struct ide_controller *ide_allocate(const char *name)
731 struct ide_controller *c = calloc(1, sizeof(*c));
734 c->name = strdup(name);
735 if (c->name == NULL) {
739 c->drive[0].controller = c;
740 c->drive[1].controller = c;
741 c->drive[0].taskfile.drive = &c->drive[0];
742 c->drive[1].taskfile.drive = &c->drive[1];
747 * Attach a file to a device on the controller
749 int ide_attach(struct ide_controller *c, int drive, int fd)
751 struct ide_drive *d = &c->drive[drive];
753 ide_fault(d, "double attach");
757 if (read(d->fd, d->data, 512) != 512 ||
758 read(d->fd, d->identify, 512) != 512) {
759 ide_fault(d, "i/o error on attach");
762 if (memcmp(d->data, ide_magic, 8)) {
763 ide_fault(d, "bad magic");
768 d->heads = d->identify[3];
769 d->sectors = d->identify[6];
770 d->cylinders = le16(d->identify[1]);
771 d->header_present = 1;
772 if (d->identify[49] & le16(1 << 9))
779 // Attach a headerless HDD image to the controller
780 int ide_attach_hdf(struct ide_controller *c, int drive, int fd)
782 struct ide_drive *d = &c->drive[drive];
784 printf("[IDE/HDL] Drive already attached.\n");
794 d->header_present = 0;
796 uint64_t file_size = lseek(fd, 0, SEEK_END);
797 lseek(fd, 1024, SEEK_SET);
799 if (file_size < 504 * SIZE_MEGA) {
802 else if (file_size < 1008 * SIZE_MEGA) {
805 else if (file_size < 2016 * SIZE_MEGA) {
808 else if (file_size < (uint64_t)4032 * SIZE_MEGA) {
812 d->cylinders = (file_size / 512) / (d->sectors * d->heads);
814 printf("[IDE/HDL] Cylinders: %d Heads: %d Sectors: %d\n", d->cylinders, d->heads, d->sectors);
816 if (file_size >= 4 * 1000 * 1000) {
820 ide_make_ident(d->cylinders, d->heads, d->sectors, "PISTORM HDD IMAGE v0.1", d->identify);
826 * Detach an IDE device from the interface (not hot pluggable)
828 void ide_detach(struct ide_drive *d)
836 * Free up and release and IDE controller
838 void ide_free(struct ide_controller *c)
840 if (c->drive[0].present)
841 ide_detach(&c->drive[0]);
842 if (c->drive[1].present)
843 ide_detach(&c->drive[1]);
844 free((void *)c->name);
849 * Emulation interface for an 8bit controller using latches on the
852 uint8_t ide_read_latched(struct ide_controller *c, uint8_t reg)
855 if (reg == ide_data_latch)
856 return c->data_latch;
857 v = ide_read16(c, reg);
858 if (reg == ide_data) {
859 c->data_latch = v >> 8;
865 void ide_write_latched(struct ide_controller *c, uint8_t reg, uint8_t v)
869 if (reg == ide_data_latch) {
874 d |= (c->data_latch << 8);
875 ide_write16(c, reg, d);
878 static void make_ascii(uint16_t *p, const char *t, int len)
882 // strncpy(d, t, len);
883 #pragma GCC diagnostic push
884 #pragma GCC diagnostic ignored "-Wstringop-truncation"
886 #pragma GCC diagnostic pop
888 for (i = 0; i < len; i += 2) {
896 static void make_serial(uint16_t *p)
899 srand(getpid()^time(NULL));
900 snprintf(buf, 21, "%08d%08d%04d", rand(), rand(), rand());
901 make_ascii(p, buf, 20);
904 int ide_make_ident(uint16_t c, uint8_t h, uint8_t s, char *name, uint16_t *target)
906 uint16_t *ident = target;
909 memset(ident, 0, 512);
910 memcpy(ident, ide_magic, 8);
913 ident[0] = le16((1 << 15) | (1 << 6)); /* Non removable */
914 make_serial(ident + 10);
915 ident[47] = 0; /* no read multi for now */
916 ident[51] = le16(240 /* PIO2 */ << 8); /* PIO cycle time */
917 ident[53] = le16(1); /* Geometry words are valid */
919 make_ascii(ident + 23, "A001.001", 8);
920 make_ascii(ident + 27, name, 40);
921 ident[49] = le16(1 << 9); /* LBA */
926 ident[54] = ident[1];
927 ident[55] = ident[3];
928 ident[56] = ident[6];
930 ident[57] = le16(sectors & 0xFFFF);
931 ident[58] = le16(sectors >> 16);
932 ident[60] = ident[57];
933 ident[61] = ident[58];
938 int ide_make_drive(uint8_t type, int fd)
945 if (type < 1 || type > MAX_DRIVE_TYPE)
948 memset(ident, 0, 512);
949 memcpy(ident, ide_magic, 8);
950 if (write(fd, ident, 512) != 512)
954 ident[0] = le16((1 << 15) | (1 << 6)); /* Non removable */
955 make_serial(ident + 10);
956 ident[47] = 0; /* no read multi for now */
957 ident[51] = le16(240 /* PIO2 */ << 8); /* PIO cycle time */
958 ident[53] = le16(1); /* Geometry words are valid */
961 case ACME_ROADRUNNER:
962 /* 504MB drive with LBA support */
966 make_ascii(ident + 23, "A001.001", 8);
967 make_ascii(ident + 27, "ACME ROADRUNNER v0.1", 40);
968 ident[49] = le16(1 << 9); /* LBA */
970 case ACME_ULTRASONICUS:
971 /* 40MB drive with LBA support */
975 ident[49] = le16(1 << 9); /* LBA */
976 make_ascii(ident + 23, "A001.001", 8);
977 make_ascii(ident + 27, "ACME ULTRASONICUS AD INFINITUM v0.1", 40);
980 /* 20MB drive with LBA support */
984 ident[49] = le16(1 << 9); /* LBA */
985 make_ascii(ident + 23, "A001.001", 8);
986 make_ascii(ident + 27, "ACME NEMESIS RIDICULII v0.1", 40);
989 /* 20MB drive without LBA support */
993 make_ascii(ident + 23, "A001.001", 8);
994 make_ascii(ident + 27, "ACME COYOTE v0.1", 40);
996 case ACME_ACCELLERATTI:
1000 ident[49] = le16(1 << 9); /* LBA */
1001 make_ascii(ident + 23, "A001.001", 8);
1002 make_ascii(ident + 27, "ACME ACCELLERATTI INCREDIBILUS v0.1", 40);
1008 ident[49] = le16(1 << 9); /* LBA */
1009 make_ascii(ident + 23, "A001.001", 8);
1010 make_ascii(ident + 27, "ACME ZIPPIBUS v0.1", 40);
1016 ident[54] = ident[1];
1017 ident[55] = ident[3];
1018 ident[56] = ident[6];
1019 sectors = c * h * s;
1020 ident[57] = le16(sectors & 0xFFFF);
1021 ident[58] = le16(sectors >> 16);
1022 ident[60] = ident[57];
1023 ident[61] = ident[58];
1024 if (write(fd, ident, 512) != 512)
1027 memset(ident, 0xE5, 512);
1029 if (write(fd, ident, 512) != 512)