ide: Workaround for CD-ROM boot
[openhackware.git] / src / bloc.c
blobb171ed6e35feee68bb22bbb8328bf003c45deaba
1 /*
2 * <bloc.c>
4 * Open Hack'Ware BIOS bloc devices management
5 *
6 * Copyright (c) 2004-2005 Jocelyn Mayer
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
26 #undef DPRINTF
27 #define DPRINTF(fmt, args...) do { } while (0)
29 struct bloc_device_t {
30 int device;
31 /* Hardware */
32 uint32_t io_base;
33 int drv;
34 /* Geometry */
35 int heads;
36 int trks;
37 int sects;
38 int seclen;
39 /* Position */
40 int bloc;
41 int vbloc;
42 int vpos;
43 /* Access */
44 int (*init)(bloc_device_t *bd, int device);
45 int (*read_sector)(bloc_device_t *bd, void *buffer, int secnum);
46 int (*ioctl)(bloc_device_t *bd, int func, void *args);
47 /* buffer */
48 char *buffer;
49 /* Private data */
50 int tmp;
51 void *private;
52 #ifdef USE_OPENFIRMWARE
53 void *OF_private;
54 #endif
55 /* Partitions */
56 part_t *parts, *bparts;
57 part_t *boot_part;
58 int bpartnum;
59 /* Chain */
60 bloc_device_t *next;
63 static bloc_device_t *bd_list;
65 static int fdc_initialize (bloc_device_t *bd, int device);
66 static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum);
68 static int ide_initialize (bloc_device_t *bd, int device);
69 static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum);
70 static int ide_reset (bloc_device_t *bd);
72 static int mem_initialize (bloc_device_t *bd, int device);
73 static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum);
74 static int mem_ioctl (bloc_device_t *bd, int func, void *args);
76 bloc_device_t *bd_open (int device)
78 bloc_device_t *bd;
79 int num;
81 bd = bd_get(device);
82 if (bd != NULL)
83 return bd;
84 bd = malloc(sizeof(bloc_device_t));
85 if (bd == NULL)
86 return NULL;
87 bd->ioctl = NULL;
88 switch (device) {
89 case 'a':
90 num = 0;
91 bd->init = &fdc_initialize;
92 bd->read_sector = &fdc_read_sector;
93 break;
94 case 'b':
95 num = 1;
96 bd->init = &fdc_initialize;
97 bd->read_sector = &fdc_read_sector;
98 break;
99 case 'c':
100 num = 0;
101 bd->init = &ide_initialize;
102 bd->read_sector = &ide_read_sector;
103 break;
104 case 'd':
105 num = 1;
106 bd->init = &ide_initialize;
107 bd->read_sector = &ide_read_sector;
108 break;
109 case 'e':
110 num = 2;
111 bd->init = &ide_initialize;
112 bd->read_sector = &ide_read_sector;
113 break;
114 case 'f':
115 num = 3;
116 bd->init = &ide_initialize;
117 bd->read_sector = &ide_read_sector;
118 break;
119 case 'm':
120 num = 0;
121 bd->init = &mem_initialize;
122 bd->read_sector = &mem_read_sector;
123 bd->ioctl = &mem_ioctl;
124 break;
125 default:
126 return NULL;
128 bd->bloc = -1;
129 if ((*bd->init)(bd, num) < 0) {
130 free(bd);
131 return NULL;
133 bd->buffer = malloc(bd->seclen);
134 if (bd->buffer == NULL) {
135 free(bd);
136 return NULL;
138 bd->device = device;
140 return bd;
143 int bd_seek (bloc_device_t *bd, uint32_t bloc, uint32_t pos)
145 uint32_t maxbloc;
147 maxbloc = bd_maxbloc(bd);
148 if (bloc > maxbloc) {
149 DPRINTF("%p bloc: %d maxbloc: %d C: %d H: %d S: %d\n",
150 bd, bloc, maxbloc, bd->trks, bd->heads, bd->sects);
151 return -1;
153 bd->vbloc = bloc;
154 bd->vpos = pos;
155 DPRINTF("%s: %p %08x %08x %08x %08x %08x\n", __func__, bd, bloc, pos,
156 bd->bloc, bd->vbloc, bd->vpos);
158 return 0;
161 int bd_read (bloc_device_t *bd, void *buffer, int len)
163 int clen, total;
165 for (total = 0; len > 0; total += clen) {
166 if (bd->vbloc != bd->bloc) {
167 /* Do physical seek */
168 #if 0
169 DPRINTF("Read sector %d\n", bd->vbloc);
170 #endif
171 if ((*bd->read_sector)(bd, bd->buffer, bd->vbloc) < 0) {
172 printf("Error reading bloc %d\n", bd->vbloc);
173 return -1;
175 bd->bloc = bd->vbloc;
177 clen = bd->seclen - bd->vpos;
178 if (clen > len)
179 clen = len;
180 memcpy(buffer, bd->buffer + bd->vpos, clen);
181 #if 0
182 DPRINTF("%s: %p copy %d bytes (%08x %08x %08x) %08x %08x %08x %08x\n",
183 __func__, bd, clen, bd->bloc, bd->vbloc, bd->vpos,
184 ((uint32_t *)buffer)[0], ((uint32_t *)buffer)[1],
185 ((uint32_t *)buffer)[2], ((uint32_t *)buffer)[3]);
186 #endif
187 bd->vpos += clen;
188 if (bd->vpos == bd->seclen) {
189 bd->vbloc++;
190 bd->vpos = 0;
192 buffer += clen;
193 len -= clen;
196 return total;
199 int bd_write (unused bloc_device_t *bd,
200 unused const void *buffer, unused int len)
202 return -1;
205 int bd_ioctl (bloc_device_t *bd, int func, void *args)
207 if (bd->ioctl == NULL)
208 return -1;
210 return (*bd->ioctl)(bd, func, args);
213 void bd_close (unused bloc_device_t *bd)
217 void bd_reset_all(void)
219 bloc_device_t *bd;
220 for (bd = bd_list; bd != NULL; bd = bd->next) {
221 if (bd->init == &ide_initialize) {
222 /* reset IDE drive because Darwin wants all IDE devices to be reset */
223 ide_reset(bd);
228 uint32_t bd_seclen (bloc_device_t *bd)
230 return bd->seclen;
233 uint32_t bd_maxbloc (bloc_device_t *bd)
235 return bd_CHS2sect(bd, bd->trks, 0, 1);
238 /* XXX: to be suppressed */
239 void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum)
241 dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum);
242 if (bd->boot_part == NULL) {
243 bd->boot_part = partition;
244 bd->bpartnum = partnum;
248 part_t **_bd_parts (bloc_device_t *bd)
250 return &bd->parts;
253 part_t **_bd_bparts (bloc_device_t *bd)
255 return &bd->bparts;
258 void bd_set_boot_device (bloc_device_t *bd)
260 #if defined (USE_OPENFIRMWARE)
261 OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot");
262 #endif
265 part_t *bd_probe (int boot_device)
267 char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', };
268 bloc_device_t *bd, **cur;
269 part_t *boot_part, *tmp;
270 int i, force_raw;
272 boot_part = NULL;
273 /* Probe bloc devices */
274 for (i = 0; devices[i] != '\0'; i++) {
275 if (devices[i] == 'm' && boot_device != 'm')
276 break;
277 bd = bd_open(devices[i]);
278 if (bd != NULL) {
279 DPRINTF("New bloc device %c: %p\n", devices[i], bd);
280 for (cur = &bd_list; *cur != NULL; cur = &(*cur)->next)
281 continue;
282 *cur = bd;
283 } else {
284 DPRINTF("No bloc device %c\n", devices[i]);
287 /* Probe partitions for each bloc device found */
288 for (bd = bd_list; bd != NULL; bd = bd->next) {
289 dprintf("Probe partitions for device %c\n", bd->device);
290 if (bd->device == 'm')
291 force_raw = 1;
292 else
293 force_raw = 0;
294 tmp = part_probe(bd, force_raw);
295 if (boot_device == bd->device) {
296 boot_part = tmp;
297 bd_set_boot_device(bd);
301 return boot_part;
304 bloc_device_t *bd_get (int device)
306 bloc_device_t *cur;
308 for (cur = bd_list; cur != NULL; cur = cur->next) {
309 if (cur->device == device) {
310 DPRINTF("%s: found device %c: %p\n", __func__, device, cur);
311 return cur;
315 return NULL;
318 void bd_put (unused bloc_device_t *bd)
322 void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum,
323 int *cyl, int *head, int *sect)
325 uint32_t tmp;
327 tmp = secnum / bd->sects;
328 *sect = secnum - (tmp * bd->sects) + 1;
329 *cyl = tmp / bd->heads;
330 *head = tmp - (*cyl * bd->heads);
333 uint32_t bd_CHS2sect (bloc_device_t *bd,
334 int cyl, int head, int sect)
336 return (((cyl * bd->heads) + head) * bd->sects) + sect - 1;
339 /* Floppy driver */
340 #define FDC_OUT_BASE (0x03F0)
341 #define FDC_DOR_PORT (FDC_OUT_BASE + 0x0002)
342 #define FDC_TAPE_PORT (FDC_OUT_BASE + 0x0003)
343 #define FDC_MAIN_STATUS (FDC_OUT_BASE + 0x0004)
344 #define FDC_WRITE_PORT (FDC_OUT_BASE + 0x0005)
345 #define FDC_READ_PORT (FDC_OUT_BASE + 0x0005)
347 static int fdc_read_data (uint8_t *addr, int len)
349 uint8_t status;
350 int i;
352 for (i = 0; i < len; i++) {
353 status = inb(FDC_MAIN_STATUS);
354 if ((status & 0xD0) != 0xD0) {
355 #if 0
356 ERROR("fdc_read_data: read data status != READ_DATA: %0x\n",
357 status);
358 #endif
359 return -1;
361 addr[i] = inb(FDC_READ_PORT);
364 return 0;
367 static inline int fdc_write_cmd (uint8_t cmd)
369 uint8_t status;
371 status = inb(FDC_MAIN_STATUS);
372 if ((status & 0xC0) != 0x80) {
373 #if 0
374 ERROR("fdc_write_cmd: read data status != WRITE_CMD: %0x\n",
375 status);
376 #endif
377 return -1;
379 outb(FDC_WRITE_PORT, cmd);
381 return 0;
384 static int fdc_reset (void)
386 uint8_t dor;
388 dor = inb(FDC_DOR_PORT);
389 /* Stop motors & enter reset */
390 dor &= ~0x34;
391 outb(FDC_DOR_PORT, dor);
392 usleep(1000);
393 /* leave reset state */
394 dor |= 0x04;
395 outb(FDC_DOR_PORT, dor);
396 usleep(1000);
398 return 0;
401 static int fdc_recalibrate (int drv)
403 uint8_t data[2];
405 if (drv == 0)
406 data[0] = 0;
407 else
408 data[0] = 1;
409 if (fdc_write_cmd(0x07) < 0) {
410 ERROR("fdc_recalibrate != WRITE_CMD\n");
411 return -1;
413 if (fdc_write_cmd(data[0]) < 0) {
414 ERROR("fdc_recalibrate data\n");
415 return -1;
417 /* Wait for drive to go out of busy state */
418 while ((inb(FDC_MAIN_STATUS) & 0x0F) != 0x00)
419 continue;
420 /* Check command status */
421 if (fdc_write_cmd(0x08) < 0) {
422 ERROR("fdc_recalibrate != SENSE_INTERRUPT_STATUS\n");
423 return -1;
425 data[0] = inb(FDC_READ_PORT);
426 data[1] = inb(FDC_READ_PORT);
427 if (data[0] & 0xD0) {
428 /* recalibrate / seek failed */
429 return -1;
431 /* Status should be WRITE_CMD right now */
432 if ((inb(FDC_MAIN_STATUS) & 0xD0) != 0x80) {
433 ERROR("fdc_recalibrate status\n");
434 return -1;
437 return 0;
440 static int fdc_start_read (int drv, uint8_t hd, uint8_t trk, uint8_t sect,
441 int mt)
443 uint8_t fdc_cmd[9], status;
444 int i;
446 fdc_cmd[0] = 0x66;
447 if (mt)
448 fdc_cmd[0] |= 0x80;
449 fdc_cmd[1] = 0x00;
450 if (hd)
451 fdc_cmd[1] |= 0x04;
452 if (drv)
453 fdc_cmd[1] |= 0x01;
454 fdc_cmd[2] = trk;
455 fdc_cmd[3] = hd;
456 fdc_cmd[4] = sect;
457 fdc_cmd[5] = 0x02;
458 fdc_cmd[6] = 0x12;
459 fdc_cmd[7] = 0x00;
460 fdc_cmd[8] = 0x00;
461 for (i = 0; i < (int)sizeof(fdc_cmd); i++) {
462 status = inb(FDC_MAIN_STATUS);
463 if ((status & 0xC0) != 0x80) {
464 ERROR("fdc_start_read: write command status != WRITE_CMD: %0x\n",
465 status);
466 return -1;
468 outb(FDC_WRITE_PORT, fdc_cmd[i]);
470 status = inb(FDC_MAIN_STATUS);
471 if ((status & 0xD0) != 0xD0) {
472 ERROR("fdc_read_sector: status != READ_DATA: %0x\n", status);
473 return -1;
476 return 0;
479 /* FDC driver entry points */
480 static int fdc_initialize (bloc_device_t *bd, int device)
482 uint8_t fifo[10];
483 #if 0
484 uint32_t tape;
485 #endif
486 int status;
488 if (device > 1)
489 return -1;
490 DPRINTF("Init FDC drive %d\n", device);
491 /* Manage 1.44 MB disks only, for now */
492 bd->drv = device;
493 bd->heads = 2;
494 bd->trks = 80;
495 bd->sects = 18;
496 bd->seclen = 512;
497 bd->tmp = -1;
498 fdc_reset();
499 /* Dump registers */
500 if (fdc_write_cmd(0x0E) < 0) {
501 #if 0
502 ERROR("fdc_reset: DUMP_REGISTER != WRITE_CMD\n");
503 #endif
504 return -1;
506 if (fdc_read_data(fifo, 10) < 0) {
507 ERROR("fdc_reset: DUMP_REGISTER data\n");
508 return -1;
510 /* SPECIFY: be sure we're not in DMA mode */
511 if (fdc_write_cmd(0x03) < 0) {
512 ERROR("fdc_reset: SPECIFY != WRITE_CMD\n");
513 return -1;
515 if (fdc_write_cmd(fifo[4]) < 0 || fdc_write_cmd(fifo[5] | 0x01)) {
516 ERROR("fdc_reset: SPECIFY data\n");
517 return -1;
519 /* Status should be WRITE_CMD right now */
520 status = inb(FDC_MAIN_STATUS);
521 if ((status & 0xD0) != 0x80) {
522 ERROR("fdc_initialise: read data status != WRITE_CMD: %0x\n",
523 status);
524 return -1;
526 /* RECALIBRATE */
527 if (fdc_recalibrate(device) < 0) {
528 printf("fd%c: no floppy inserted\n", 'a' + device);
529 return -1;
531 printf("fd%c initialized\n", 'a' + device);
533 return 0;
536 static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum)
538 int head, cyl, sect;
539 int need_restart;
541 #if DEBUG_BIOS > 1
542 printf("Read fdc sector: %d at: %0x\n", secnum, (uint32_t)buffer);
543 bd_sect2CHS(bd, secnum, &cyl, &head, &sect);
544 printf("cur: %d hd: %d trk: %d sect: %d\n", bd->bloc, head, cyl, sect);
545 #endif
546 if (secnum != bd->tmp) {
547 if (fdc_reset() < 0 || fdc_recalibrate(bd->drv) < 0)
548 return -1;
549 need_restart = 1;
550 } else {
551 need_restart = 0;
553 bd_sect2CHS(bd, secnum, &cyl, &head, &sect);
554 if (need_restart == 1 || (head == 0 && sect == 1)) {
555 if (need_restart == 0) {
556 /* Read the status */
557 uint8_t tmp[7];
559 while (fdc_read_data(tmp, 1) == 0)
560 continue;
562 #if !defined (DEBUG_BIOS)
563 printf(".");
564 #endif
565 if (fdc_start_read(bd->drv, head, cyl, sect, 1) < 0)
566 return -1;
567 bd->bloc = secnum;
568 bd->tmp = secnum;
570 if (fdc_read_data(buffer, bd->seclen) < 0)
571 return -1;
572 bd->tmp++;
574 return bd->seclen;
577 /* SCSI subset */
578 /* SPC: primary commands, common to all devices */
579 static int spc_inquiry_req (void *buffer, int maxlen)
581 uint8_t *p;
583 p = buffer;
584 p[0] = 0x12;
585 /* No page code */
586 p[1] = 0x00;
587 p[2] = 0x00;
588 p[3] = maxlen >> 8;
589 p[4] = maxlen;
590 p[5] = 0x00;
592 return 6;
595 static int spc_inquiry_treat (void *buffer, int len)
597 const uint8_t *p;
599 if (len < 36)
600 return -1;
601 p = buffer;
602 if ((p[0] >> 5) != 0) {
603 ERROR("Logical unit not ready\n");
604 return -1;
607 return p[0] & 0x1F;
610 static int spc_test_unit_ready_req (void *buffer)
612 uint8_t *p;
614 p = buffer;
615 p[0] = 0x00;
616 p[1] = 0x00;
617 p[2] = 0x00;
618 p[3] = 0x00;
619 p[4] = 0x00;
620 p[5] = 0x00;
622 return 6;
625 /* MMC: multimedia commands */
626 static int mmc_read_capacity_req (void *buffer)
628 uint8_t *p;
630 p = buffer;
631 p[0] = 0x25;
632 p[1] = 0x00;
633 p[2] = 0x00;
634 p[3] = 0x00;
635 p[4] = 0x00;
636 p[5] = 0x00;
637 p[6] = 0x00;
638 p[7] = 0x00;
639 p[8] = 0x00;
640 p[9] = 0x00;
642 return 10;
645 static int mmc_read_capacity_treat (uint32_t *size, uint32_t *ssize,
646 const void *buffer, int len)
648 const uint8_t *p;
650 if (len != 8)
651 return -1;
652 p = buffer;
653 /* Only handle CDROM address mode for now */
654 *size = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + 1;
655 *ssize = ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
657 return 0;
660 static int mmc_read12_req (void *buffer, uint32_t LBA, uint32_t size)
662 uint8_t *p;
664 p = buffer;
665 p[0] = 0xA8;
666 p[1] = 0x00;
667 p[2] = LBA >> 24;
668 p[3] = LBA >> 16;
669 p[4] = LBA >> 8;
670 p[5] = LBA;
671 p[6] = size >> 24;
672 p[7] = size >> 16;
673 p[8] = size >> 8;
674 p[9] = size;
675 p[10] = 0x00;
676 p[11] = 0x00;
678 return 12;
681 /* IDE disk driver */
682 static uint32_t ide_base[2] = { 0x1F0, 0x170, };
683 static uint32_t ide_base2[2] = { 0x3F6, 0x376, };
685 typedef struct ide_ops_t {
686 uint8_t (*port_read)(bloc_device_t *bd, int port);
687 void (*port_write)(bloc_device_t *bd, int port, uint8_t value);
688 uint32_t (*data_readl)(bloc_device_t *bd);
689 void (*data_writel)(bloc_device_t *bd, uint32_t val);
690 void (*control_write)(bloc_device_t *bd, uint32_t val);
691 uint32_t base[4];
692 #ifdef USE_OPENFIRMWARE
693 void *OF_private[2];
694 #endif
695 } ide_ops_t;
697 /* IDE ISA access */
698 static uint8_t ide_isa_port_read (bloc_device_t *bd, int port)
700 return inb(bd->io_base + port);
703 static void ide_isa_port_write (bloc_device_t *bd, int port, uint8_t value)
705 outb(bd->io_base + port, value);
708 static uint32_t ide_isa_data_readl (bloc_device_t *bd)
710 return inl(bd->io_base);
713 static void ide_isa_data_writel (bloc_device_t *bd, uint32_t val)
715 return outl(bd->io_base, val);
718 static void ide_isa_control_write (bloc_device_t *bd, uint32_t val)
720 outb(bd->tmp, val);
723 static ide_ops_t ide_isa_ops = {
724 &ide_isa_port_read,
725 &ide_isa_port_write,
726 &ide_isa_data_readl,
727 &ide_isa_data_writel,
728 &ide_isa_control_write,
729 { 0, },
730 #ifdef USE_OPENFIRMWARE
731 { NULL, },
732 #endif
735 static ide_ops_t *ide_pci_ops;
737 /* IDE PCI access for pc */
738 static uint8_t ide_pci_port_read (bloc_device_t *bd, int port)
740 uint8_t value;
741 value = inb(bd->io_base + port);
742 return value;
745 static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value)
747 outb(bd->io_base + port, value);
750 static uint32_t ide_pci_data_readl (bloc_device_t *bd)
752 return inl(bd->io_base);
755 static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val)
757 outl(bd->io_base, val);
760 static void ide_pci_control_write (bloc_device_t *bd, uint32_t val)
762 outb(bd->tmp + 2, val);
765 static ide_ops_t ide_pci_pc_ops = {
766 &ide_pci_port_read,
767 &ide_pci_port_write,
768 &ide_pci_data_readl,
769 &ide_pci_data_writel,
770 &ide_pci_control_write,
771 { 0, },
772 #ifdef USE_OPENFIRMWARE
773 { NULL, },
774 #endif
777 void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
778 uint32_t io_base2, uint32_t io_base3,
779 void *OF_private0, void *OF_private1)
781 if (ide_pci_ops == NULL) {
782 ide_pci_ops = malloc(sizeof(ide_ops_t));
783 if (ide_pci_ops == NULL)
784 return;
785 memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t));
787 if ((io_base0 != 0 || io_base1 != 0) &&
788 ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) {
789 ide_pci_ops->base[0] = io_base0;
790 ide_pci_ops->base[2] = io_base1;
791 #ifdef USE_OPENFIRMWARE
792 ide_pci_ops->OF_private[0] = OF_private0;
793 #endif
795 if ((io_base2 != 0 || io_base3 != 0) &&
796 ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) {
797 ide_pci_ops->base[1] = io_base2;
798 ide_pci_ops->base[3] = io_base3;
799 #ifdef USE_OPENFIRMWARE
800 ide_pci_ops->OF_private[1] = OF_private1;
801 #endif
805 /* IDE PCI access for pmac */
806 static uint8_t ide_pmac_port_read (bloc_device_t *bd, int port)
808 uint32_t addr;
810 if (port != 8)
811 addr = bd->io_base + (port << 4);
812 else
813 addr = bd->io_base + 0x160;
814 eieio();
816 return *((uint8_t *)addr);
819 static void ide_pmac_port_write (bloc_device_t *bd, int port, uint8_t value)
821 uint32_t addr;
823 if (port != 8)
824 addr = bd->io_base + (port << 4);
825 else
826 addr = bd->io_base + 0x160;
827 *((uint8_t *)addr) = value;
828 eieio();
831 static uint32_t ide_pmac_data_readl (bloc_device_t *bd)
833 eieio();
834 return ldswap32((uint32_t *)bd->io_base);
835 // return *((uint32_t *)bd->io_base);
838 static void ide_pmac_data_writel (bloc_device_t *bd, uint32_t val)
840 // *((uint32_t *)bd->io_base) = val;
841 stswap32((uint32_t *)bd->io_base, val);
842 eieio();
845 static void ide_pmac_control_write (bloc_device_t *bd, uint32_t val)
847 ide_pmac_port_write(bd, 8, val);
850 static ide_ops_t ide_pmac_ops = {
851 &ide_pmac_port_read,
852 &ide_pmac_port_write,
853 &ide_pmac_data_readl,
854 &ide_pmac_data_writel,
855 &ide_pmac_control_write,
856 { 0, },
857 #ifdef USE_OPENFIRMWARE
858 { NULL, },
859 #endif
862 void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1,
863 unused void *OF_private)
865 if (ide_pci_ops == NULL) {
866 ide_pci_ops = malloc(sizeof(ide_ops_t));
867 if (ide_pci_ops == NULL)
868 return;
869 memcpy(ide_pci_ops, &ide_pmac_ops, sizeof(ide_ops_t));
871 if (io_base0 != 0 && ide_pci_ops->base[0] == 0) {
872 ide_pci_ops->base[0] = io_base0;
873 #ifdef USE_OPENFIRMWARE
874 ide_pci_ops->OF_private[0] = OF_private;
875 #endif
877 if (io_base1 != 0 && ide_pci_ops->base[1] == 0) {
878 ide_pci_ops->base[1] = io_base1;
879 #ifdef USE_OPENFIRMWARE
880 ide_pci_ops->OF_private[1] = OF_private;
881 #endif
885 static inline uint8_t ide_port_read (bloc_device_t *bd, int port)
887 ide_ops_t *ops = bd->private;
889 return ops->port_read(bd, port);
892 static inline void ide_port_write (bloc_device_t *bd, int port, uint8_t value)
894 ide_ops_t *ops = bd->private;
896 ops->port_write(bd, port, value);
899 static inline uint32_t ide_data_readl (bloc_device_t *bd)
901 ide_ops_t *ops = bd->private;
903 return ops->data_readl(bd);
906 static inline void ide_data_writel (bloc_device_t *bd, uint32_t val)
908 ide_ops_t *ops = bd->private;
910 return ops->data_writel(bd, val);
913 static inline void ide_control_write (bloc_device_t *bd, uint32_t val)
915 ide_ops_t *ops = bd->private;
917 return ops->control_write(bd, val);
920 static int ide_reset (bloc_device_t *bd)
922 int status, is_cdrom, lcyl;
924 ide_control_write(bd, 0x04);
925 status = ide_port_read(bd, 0x07);
926 if (status != 0x90) {
927 return -1;
929 ide_control_write(bd, 0x00);
930 if (bd->drv == 0)
931 ide_port_write(bd, 0x06, 0xa0);
932 else
933 ide_port_write(bd, 0x06, 0xb0);
935 lcyl = ide_port_read(bd, 0x04);
936 switch (lcyl) {
937 case 0x00:
938 /* IDE drive */
939 is_cdrom = 0;
940 break;
941 case 0x14:
942 /* ATAPI device */
943 is_cdrom = 1;
944 break;
945 default:
946 return -1;
949 return is_cdrom;
952 static void atapi_pad_req (void *buffer, int len);
953 static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
954 int maxlen);
955 static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum);
957 static int ide_initialize (bloc_device_t *bd, int device)
959 #ifdef USE_OPENFIRMWARE
960 void *OF_parent;
961 #endif
962 const unsigned char *devname, *devtype, *alias;
963 uint32_t atapi_buffer[9];
964 uint32_t size;
965 int status, base, is_cdrom, len, i;
967 if (device > 1)
968 base = 1;
969 else
970 base = 0;
971 if (ide_pci_ops != NULL) {
972 bd->private = ide_pci_ops;
973 bd->io_base = ide_pci_ops->base[base];
974 bd->tmp = ide_pci_ops->base[2 + base];
975 if (bd->io_base == 0x00000000 || bd->io_base == 0xFFFFFFFF) {
976 ERROR("No IDE drive %c\n", device);
977 return -1;
979 } else {
980 bd->private = &ide_isa_ops;
981 bd->io_base = ide_base[base];
982 bd->tmp = ide_base2[base];
984 bd->drv = device & 1;
985 DPRINTF("Init IDE drive %d-%d (%d)\n", base, bd->drv, device);
986 is_cdrom = ide_reset(bd);
987 printf("ide%d: drive %d: ",
988 (device >> 1), bd->drv);
989 switch(is_cdrom) {
990 case 0:
991 printf("Hard Disk\n");
992 devname = "disk";
993 devtype = "hd";
994 alias = "hd";
995 break;
996 case 1:
997 printf("CD-ROM\n");
998 devname = "cdrom";
999 devtype = "cdrom";
1000 alias = "cd";
1001 break;
1002 default:
1003 printf("none\n");
1004 devname = NULL;
1005 devtype = NULL;
1006 alias = NULL;
1007 break;
1009 if (is_cdrom < 0)
1010 return -1;
1011 #ifdef USE_OPENFIRMWARE
1012 /* Register disk into OF tree */
1013 OF_parent = ide_pci_ops->OF_private[base];
1014 if (OF_parent != NULL) {
1015 bd->OF_private = OF_blockdev_register(OF_parent, bd, devtype,
1016 devname, bd->drv, alias);
1018 #endif
1019 /* Select drive */
1020 if (bd->drv == 0)
1021 ide_port_write(bd, 0x06, 0x40);
1022 else
1023 ide_port_write(bd, 0x06, 0x50);
1024 /* WIN_DEVICE_RESET */
1025 ide_port_write(bd, 0x07, 0x08);
1026 status = ide_port_read(bd, 0x07);
1027 if (is_cdrom) {
1028 if (status != 0x00) {
1029 ERROR("WIN_DEVICE_RESET : status %0x != 0x00 (is_cdrom: %d)\n",
1030 status, is_cdrom);
1031 return -1;
1033 /* TEST_UNIT_READY */
1034 DPRINTF("TEST_UNIT_READY\n");
1035 len = spc_test_unit_ready_req(&atapi_buffer);
1036 atapi_pad_req(&atapi_buffer, len);
1037 ide_port_write(bd, 0x07, 0xA0);
1038 status = ide_port_read(bd, 0x07);
1039 if (status != 0x08) {
1040 ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x08\n", status);
1041 /*return -1;*/ /* fails to boot from cdrom? */
1043 for (i = 0; i < 3; i++) {
1044 ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
1046 status = ide_port_read(bd, 0x07);
1047 if (status != 0x40) {
1048 ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x40\n", status);
1049 return -1;
1051 /* INQUIRY */
1052 DPRINTF("INQUIRY\n");
1053 len = spc_inquiry_req(&atapi_buffer, 36);
1054 atapi_pad_req(&atapi_buffer, len);
1055 atapi_make_req(bd, atapi_buffer, 36);
1056 status = ide_port_read(bd, 0x07);
1057 if (status != 0x48) {
1058 ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status);
1059 return -1;
1061 for (i = 0; i < 9; i++)
1062 stswap32(&atapi_buffer[i], ide_data_readl(bd));
1063 if (spc_inquiry_treat(&atapi_buffer, 36) != 0x05) {
1064 ERROR("Only ATAPI CDROMs are handled for now\n");
1065 return -1;
1067 /* READ_CAPACITY */
1068 DPRINTF("READ_CAPACITY\n");
1069 len = mmc_read_capacity_req(&atapi_buffer);
1070 atapi_pad_req(&atapi_buffer, len);
1071 atapi_make_req(bd, atapi_buffer, 8);
1072 status = ide_port_read(bd, 0x07);
1073 if (status != 0x48) {
1074 ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status);
1075 return -1;
1077 for (i = 0; i < 2; i++)
1078 stswap32(&atapi_buffer[i], ide_data_readl(bd));
1079 if (mmc_read_capacity_treat(&size, &bd->seclen,
1080 &atapi_buffer, 8) != 0) {
1081 ERROR("Error retrieving ATAPI CDROM capacity\n");
1082 return -1;
1084 bd->read_sector = &atapi_read_sector;
1085 DPRINTF("ATAPI: size=%d ssize=%d\n", size, bd->seclen);
1086 } else {
1087 if (status != 0x41) {
1088 ERROR("WIN_DEVICE_RESET : status %0x != 0x41 (is_cdrom: %d)\n",
1089 status, is_cdrom);
1090 return -1;
1092 /* WIN_READ_NATIVE_MAX */
1093 ide_port_write(bd, 0x07, 0xF8);
1094 status = ide_port_read(bd, 0x07);
1095 if (status != 0x40) {
1096 ERROR("WIN_READ_NATIVE_MAX : status %0x != 0x40\n", status);
1097 return -1;
1099 /* Retrieve parameters */
1100 size = (ide_port_read(bd, 0x06) & ~0xF0) << 24;
1101 size |= ide_port_read(bd, 0x05) << 16;
1102 size |= ide_port_read(bd, 0x04) << 8;
1103 size |= ide_port_read(bd, 0x03);
1104 bd->seclen = 512;
1106 bd->heads = 16;
1107 bd->sects = 64;
1108 bd->trks = (size + (16 * 64 - 1)) >> 10;
1110 return 0;
1113 static void atapi_pad_req (void *buffer, int len)
1115 uint8_t *p;
1117 p = buffer;
1118 memset(p + len, 0, 12 - len);
1121 static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
1122 int maxlen)
1124 int i;
1125 /* select drive */
1126 if (bd->drv == 0)
1127 ide_port_write(bd, 0x06, 0x40);
1128 else
1129 ide_port_write(bd, 0x06, 0x50);
1130 ide_port_write(bd, 0x04, maxlen & 0xff);
1131 ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff);
1132 ide_port_write(bd, 0x07, 0xA0);
1133 for (i = 0; i < 3; i++)
1134 ide_data_writel(bd, ldswap32(&buffer[i]));
1137 static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum)
1139 uint32_t atapi_buffer[4];
1140 uint8_t *p;
1141 uint32_t status, value;
1142 int i, len;
1144 len = mmc_read12_req(atapi_buffer, secnum, 1);
1145 atapi_pad_req(&atapi_buffer, len);
1146 atapi_make_req(bd, atapi_buffer, bd->seclen);
1147 status = ide_port_read(bd, 0x07);
1148 if (status != 0x48) {
1149 ERROR("ATAPI READ12 : status %0x != 0x48\n", status);
1150 return -1;
1152 p = buffer;
1153 for (i = 0; i < bd->seclen; i += 4) {
1154 value = ide_data_readl(bd);
1155 *p++ = value;
1156 *p++ = value >> 8;
1157 *p++ = value >> 16;
1158 *p++ = value >> 24;
1160 status = ide_port_read(bd, 0x07);
1161 if (status != 0x40) {
1162 ERROR("ATAPI READ12 done : status %0x != 0x48\n", status);
1163 return -1;
1166 return 0;
1169 static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum)
1171 uint32_t value;
1172 uint8_t *p;
1173 int status;
1174 int i;
1176 bd->drv &= 1;
1177 // printf("ide_read_sector: drv %d secnum %d buf %p\n", bd->drv, secnum, buffer);
1178 /* select drive & set highest bytes */
1179 if (bd->drv == 0)
1180 ide_port_write(bd, 0x06, 0x40 | (secnum >> 24));
1181 else
1182 ide_port_write(bd, 0x06, 0x50 | (secnum >> 24));
1183 /* Set hcyl */
1184 ide_port_write(bd, 0x05, secnum >> 16);
1185 /* Set lcyl */
1186 ide_port_write(bd, 0x04, secnum >> 8);
1187 /* Set sect */
1188 ide_port_write(bd, 0x03, secnum);
1189 /* Read 1 sector */
1190 ide_port_write(bd, 0x02, 1);
1191 /* WIN_READ */
1192 ide_port_write(bd, 0x07, 0x20);
1193 status = ide_port_read(bd, 0x07);
1194 // DPRINTF("ide_read_sector: try %d\n", secnum);
1195 if (status != 0x58) {
1196 ERROR("ide_read_sector: %d status %0x != 0x58\n", secnum, status);
1197 return -1;
1199 /* Get data */
1200 p = buffer;
1201 for (i = 0; i < bd->seclen; i += 4) {
1202 value = ide_data_readl(bd);
1203 *p++ = value;
1204 *p++ = value >> 8;
1205 *p++ = value >> 16;
1206 *p++ = value >> 24;
1208 status = ide_port_read(bd, 0x07);
1209 if (status != 0x50) {
1210 ERROR("ide_read_sector 6: status %0x != 0x50\n", status);
1211 return -1;
1214 return bd->seclen;
1217 /* Memory image access driver */
1218 static int mem_initialize (bloc_device_t *bd, int device)
1220 bd->seclen = 512;
1221 bd->private = NULL;
1222 bd->heads = 1;
1223 bd->sects = 1;
1224 bd->trks = 1;
1226 return device == 'm';
1229 static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum)
1231 if (buffer != (char *)bd->private + (bd->seclen * secnum)) {
1232 memmove(buffer,
1233 (char *)bd->private + (bd->seclen * secnum), bd->seclen);
1236 return bd->seclen;
1239 static int mem_ioctl (bloc_device_t *bd, int func, void *args)
1241 uint32_t *u32;
1242 int ret;
1244 switch (func) {
1245 case MEM_SET_ADDR:
1246 bd->private = args;
1247 ret = 0;
1248 break;
1249 case MEM_SET_SIZE:
1250 u32 = args;
1251 bd->trks = (*u32 + bd->seclen - 1) / bd->seclen + 1;
1252 default:
1253 ret = -1;
1254 break;
1257 return ret;