1 /*
2   www.freedo.org
3   The first working 3DO multiplayer emulator.
4 
5   The FreeDO licensed under modified GNU LGPL, with following notes:
6 
7   *   The owners and original authors of the FreeDO have full right to
8   *   develop closed source derivative work.
9 
10   *   Any non-commercial uses of the FreeDO sources or any knowledge
11   *   obtained by studying or reverse engineering of the sources, or
12   *   any other material published by FreeDO have to be accompanied
13   *   with full credits.
14 
15   *   Any commercial uses of FreeDO sources or any knowledge obtained
16   *   by studying or reverse engineering of the sources, or any other
17   *   material published by FreeDO is strictly forbidden without
18   *   owners approval.
19 
20   The above notes are taking precedence over GNU LGPL in conflicting
21   situations.
22 
23   Project authors:
24   *  Alexander Troosh
25   *  Maxim Grishin
26   *  Allen Wright
27   *  John Sammons
28   *  Felix Lazarev
29 */
30 
31 #include "inline.h"
32 #include "opera_cdrom.h"
33 
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #define MSF_BIAS_IN_SECONDS 2
39 #define MSF_BIAS_IN_FRAMES  150
40 #define FRAMES_PER_SECOND   75
41 #define SECONDS_PER_MINUTE  60
42 
43 /* FIXME: should not be using globals */
44 opera_cdrom_get_size_cb_t    CDROM_GET_SIZE;
45 opera_cdrom_set_sector_cb_t  CDROM_SET_SECTOR;
46 opera_cdrom_read_sector_cb_t CDROM_READ_SECTOR;
47 
48 static
49 INLINE
50 void
LBA2MSF(const uint32_t lba_,msf_t * msf_)51 LBA2MSF(const uint32_t  lba_,
52         msf_t          *msf_)
53 {
54   uint32_t mod;
55 
56   mod           = ((lba_ + MSF_BIAS_IN_FRAMES) % (SECONDS_PER_MINUTE * FRAMES_PER_SECOND));
57   msf_->minutes = ((lba_ + MSF_BIAS_IN_FRAMES) / (SECONDS_PER_MINUTE * FRAMES_PER_SECOND));
58   msf_->seconds = (mod / FRAMES_PER_SECOND);
59   msf_->frames  = (mod % FRAMES_PER_SECOND);
60 }
61 
62 static
63 INLINE
64 uint32_t
MSF2LBA(const msf_t * msf_)65 MSF2LBA(const msf_t *msf_)
66 {
67   uint32_t lba;
68 
69   lba = ((msf_->minutes * SECONDS_PER_MINUTE * FRAMES_PER_SECOND) +
70          (msf_->seconds * FRAMES_PER_SECOND) +
71          (msf_->frames) -
72          (MSF_BIAS_IN_FRAMES));
73   if(lba < 0)
74     lba = 0;
75 
76   return lba;
77 }
78 
79 void
opera_cdrom_set_callbacks(opera_cdrom_get_size_cb_t get_size_,opera_cdrom_set_sector_cb_t set_sector_,opera_cdrom_read_sector_cb_t read_sector_)80 opera_cdrom_set_callbacks(opera_cdrom_get_size_cb_t    get_size_,
81                           opera_cdrom_set_sector_cb_t  set_sector_,
82                           opera_cdrom_read_sector_cb_t read_sector_)
83 {
84   CDROM_GET_SIZE    = get_size_;
85   CDROM_SET_SECTOR  = set_sector_;
86   CDROM_READ_SECTOR = read_sector_;
87 }
88 
89 void
opera_cdrom_init(cdrom_device_t * cd_)90 opera_cdrom_init(cdrom_device_t *cd_)
91 {
92   uint32_t file_size_in_blocks;
93 
94   cd_->current_sector = 0;
95   CDROM_SET_SECTOR(cd_->current_sector);
96   file_size_in_blocks = CDROM_GET_SIZE();
97 
98   cd_->data_idx     = 0;
99   cd_->xbus_status  = 0;
100   cd_->poll         = 0x0F;
101   cd_->xbus_status |= CDST_OK;
102 
103   cd_->MEI_status = MEI_CDROM_no_error;
104 
105   cd_->disc.track_first = 1;
106   cd_->disc.track_last  = 1;
107 
108   cd_->disc.disc_id = MEI_DISC_DA_OR_CDROM;
109 
110   cd_->disc.msf_current.minutes = 0;
111   cd_->disc.msf_current.seconds = MSF_BIAS_IN_SECONDS;
112   cd_->disc.msf_current.frames  = 0;
113 
114   cd_->disc.disc_toc[1].CDCTL        = CD_CTL_DATA_TRACK|CD_CTL_Q_NONE; /* |CD_CTL_COPY_PERMITTED; */
115   cd_->disc.disc_toc[1].track_number = 1;
116   cd_->disc.disc_toc[1].minutes      = 0;
117   cd_->disc.disc_toc[1].seconds      = MSF_BIAS_IN_SECONDS;
118   cd_->disc.disc_toc[1].frames       = 0;
119 
120   LBA2MSF(file_size_in_blocks + MSF_BIAS_IN_FRAMES,&cd_->disc.msf_total);
121   LBA2MSF(file_size_in_blocks,&cd_->disc.msf_session);
122 
123   cd_->STATCYC = STATDELAY;
124 }
125 
126 uint8_t
opera_cdrom_fifo_get_status(cdrom_device_t * cd_)127 opera_cdrom_fifo_get_status(cdrom_device_t *cd_)
128 {
129   uint8_t rv;
130 
131   rv = 0;
132   if(cd_->status_len > 0)
133     {
134       rv = cd_->status[0];
135       cd_->status_len--;
136       if(cd_->status_len > 0)
137         memmove(cd_->status,cd_->status + 1,cd_->status_len);
138       else
139         cd_->poll &= ~POLST;
140     }
141 
142   return rv;
143 }
144 
145 void
opera_cdrom_do_cmd(cdrom_device_t * cd_)146 opera_cdrom_do_cmd(cdrom_device_t *cd_)
147 {
148   int i;
149 
150   cd_->status_len = 0;
151 
152   cd_->poll        &= ~POLST;
153   cd_->poll        &= ~POLDT;
154   cd_->xbus_status &= ~CDST_ERRO;
155   cd_->xbus_status &= ~CDST_RDY;
156 
157   switch(cd_->cmd[0])
158     {
159       /*
160         seek
161         not used in opera
162         01 00 ll-bb-aa 00 00.
163         01 02 mm-ss-ff 00 00.
164         status 4 bytes
165         xx xx xx XS  (xs = xbus status)
166       */
167     case CDROM_CMD_SEEK:
168       break;
169 
170       /*
171         spin up
172         opera status request = 0
173         status 4 bytes
174         xx xx xx XS (XS = xbus status)
175       */
176     case CDROM_CMD_SPIN_UP:
177       if((cd_->xbus_status & CDST_TRAY) &&
178          (cd_->xbus_status & CDST_DISC))
179         {
180           cd_->xbus_status |= CDST_SPIN;
181           cd_->xbus_status |= CDST_RDY;
182           cd_->MEI_status   = MEI_CDROM_no_error;
183         }
184       else
185         {
186           cd_->xbus_status |= CDST_ERRO;
187           cd_->xbus_status &= ~CDST_RDY;
188           cd_->MEI_status   = MEI_CDROM_recv_ecc;
189         }
190 
191       cd_->status_len = 2;
192       cd_->status[0]  = CDROM_CMD_SPIN_UP;
193       cd_->status[1]  = cd_->xbus_status;
194 
195       cd_->poll |= POLST;
196       break;
197 
198       /*
199         spin down
200         opera status request = 0 // not used in opera
201         status 4 bytes
202         xx xx xx XS  (XS = xbus status)
203       */
204     case CDROM_CMD_SPIN_DOWN:
205       cd_->xbus_status |= CDST_RDY;
206       if((cd_->xbus_status & CDST_TRAY) &&
207          (cd_->xbus_status & CDST_DISC))
208         {
209           cd_->xbus_status &= ~CDST_SPIN;
210           cd_->MEI_status   = MEI_CDROM_no_error;
211         }
212       else
213         {
214           cd_->xbus_status |= CDST_ERRO;
215           cd_->MEI_status   = MEI_CDROM_recv_ecc;
216         }
217 
218       cd_->status_len = 2;
219       cd_->status[0]  = CDROM_CMD_SPIN_DOWN;
220       cd_->status[1]  = cd_->xbus_status;
221 
222       cd_->poll |= POLST;
223       break;
224 
225       /*
226         diagnostics
227         not used in opera
228         04 00 ll-bb-aa 00 00.
229         04 02 mm-ss-ff 00 00.
230         status 4 bytes
231         xx S1 S2 XS
232       */
233     case CDROM_CMD_DIAGNOSTICS:
234       break;
235 
236       /*
237         eject disc
238         opera status request  = 0
239         status 4 bytes
240         xx xx xx XS
241         1b command of scsi
242         emulation ---
243         Execute EJECT command;
244         Check Sense, update PollRegister (if medium present)
245       */
246     case CDROM_CMD_EJECT_DISC:
247       cd_->xbus_status |= CDST_RDY;
248       cd_->xbus_status &= ~CDST_TRAY;
249       cd_->xbus_status &= ~CDST_DISC;
250       cd_->xbus_status &= ~CDST_SPIN;
251       cd_->xbus_status &= ~CDST_2X;
252       cd_->xbus_status &= ~CDST_ERRO;
253       cd_->MEI_status   = MEI_CDROM_no_error;
254 
255       cd_->status_len = 2;
256       cd_->status[0]  = CDROM_CMD_EJECT_DISC;
257       cd_->status[1]  = cd_->xbus_status;
258 
259       cd_->poll |= POLST;
260       cd_->poll &= ~POLMA;
261       break;
262 
263       /*
264         inject disc
265         opera status request = 0
266         status 4 bytes
267         xx xx xx XS
268         1b command of scsi
269       */
270     case CDROM_CMD_INJECT_DISC:
271       cd_->status_len = 2;
272       cd_->status[0]  = CDROM_CMD_INJECT_DISC;
273       cd_->status[1]  = cd_->xbus_status;
274 
275       cd_->poll |= POLST;
276       break;
277 
278       /*
279         abort !!!
280         opera status request = 31
281         status 4 bytes
282         xx xx xx XS
283       */
284     case CDROM_CMD_ABORT:
285       cd_->status_len = 33;
286       cd_->status[0]  = CDROM_CMD_ABORT;
287       for(i = 1; i < 32; i++)
288         cd_->status[i] = 0;
289       cd_->status[32] = cd_->xbus_status;
290 
291       cd_->xbus_status |= CDST_RDY;
292       cd_->MEI_status   = MEI_CDROM_no_error;
293       break;
294 
295       /*
296         mode set
297         09 MM nn 00 00 00 00    // 2048 or 2340 transfer size
298         to be checked -- wasn't called even once
299         2nd byte is type selector
300         MM = mode nn= value
301         opera status request = 0
302         status 4 bytes
303         xx xx xx XS
304       */
305     case CDROM_CMD_MODE_SET:
306       /* if((xbus_status&CDST_TRAY) && (xbus_status&CDST_disc)) */
307       /*   { */
308       cd_->xbus_status |= CDST_RDY;
309       cd_->MEI_status   = MEI_CDROM_no_error;
310 
311       /*     CDMode[cmd[1]]  = cmd[2]; */
312       /*   } */
313       /* else */
314       /* 	{ */
315       /*     xbus_status     |= CDST_ERRO; */
316       /*     xbus_status     &= ~CDST_RDY; */
317       /* 	} */
318 
319       cd_->status_len = 2;
320       cd_->status[0]  = CDROM_CMD_MODE_SET;
321       cd_->status[1]  = cd_->xbus_status;
322 
323       cd_->poll |= POLST;
324       break;
325 
326       /*
327         reset
328         not used in opera
329         status 4 bytes
330         xx xx xx XS
331       */
332     case CDROM_CMD_RESET:
333       break;
334 
335       /*
336         flush
337         opera status request  = 31
338         status 4 bytes
339         xx xx xx XS
340         returns data
341         flush all internal buffer
342         1+31+1
343       */
344     case CDROM_CMD_FLUSH:
345       cd_->xbus_status |= CDST_RDY;
346       cd_->status_len   = 33;
347       cd_->status[0]    = CDROM_CMD_FLUSH;
348       for(i = 1; i < 32; i++)
349         cd_->status[i] = 0;
350       cd_->status[32] = cd_->xbus_status;
351 
352       /* cd_->xbus_status |= CDST_RDY; */
353       cd_->MEI_status = MEI_CDROM_no_error;
354       break;
355 
356       /*
357         READ DATA
358         10 01 00 00 00 00 01
359         read 1 blocks from MSF = 1.0.0
360         10 xx-xx-xx fl nn-nn
361         00 01 02 03 04 05 06
362         reads nn blocks from xx
363         fl = 0 xx="msf" ?
364         fl = 1 xx="lba" ?
365         block = 2048 bytes
366         opera status request = 0
367         status 4 bytes
368         xx xx xx xbus_status
369         returns data
370       */
371     case CDROM_CMD_READ_DATA:
372       if((cd_->xbus_status & CDST_TRAY) &&
373          (cd_->xbus_status & CDST_DISC) &&
374          (cd_->xbus_status & CDST_SPIN))
375         {
376           cd_->xbus_status |= CDST_RDY;
377           cd_->status_len   = 2;
378           cd_->status[0]    = CDROM_CMD_READ_DATA;
379           cd_->status[1]    = cd_->xbus_status;
380 
381           cd_->disc.msf_current.minutes = cd_->cmd[1];
382           cd_->disc.msf_current.seconds = cd_->cmd[2];
383           cd_->disc.msf_current.frames  = cd_->cmd[3];
384           cd_->current_sector           = MSF2LBA(&cd_->disc.msf_current);
385           cd_->blocks_requested         = ((cd_->cmd[5] << 8) + cd_->cmd[6]);
386 
387           CDROM_SET_SECTOR(cd_->current_sector);
388           if(cd_->blocks_requested)
389             {
390               cd_->current_sector++;
391               CDROM_READ_SECTOR(cd_->data);
392               cd_->data_len = REQSIZE;
393               cd_->blocks_requested--;
394             }
395           else
396             {
397               cd_->data_len = 0;
398             }
399 
400           cd_->MEI_status  = MEI_CDROM_no_error;
401           cd_->poll       |= (POLDT | POLST);
402         }
403       else
404         {
405           cd_->xbus_status |= CDST_ERRO;
406           cd_->xbus_status &= ~CDST_RDY;
407           cd_->status_len   = 2;
408           cd_->status[0]    = CDROM_CMD_READ_DATA;
409           cd_->status[1]    = cd_->xbus_status;
410           cd_->MEI_status   = MEI_CDROM_recv_ecc;
411           cd_->poll        |= POLST;
412         }
413       break;
414 
415       /*
416         data path check
417         opera status request  = 2
418         MKE                   = 2
419         status 4 bytes
420         80 AA 55 XS
421       */
422     case CDROM_CMD_DATA_PATH_CHECK:
423       cd_->xbus_status |= CDST_RDY;
424       cd_->status_len   = 4;
425       cd_->status[0]    = CDROM_CMD_DATA_PATH_CHECK;
426       cd_->status[1]    = 0xAA;
427       cd_->status[2]    = 0x55;
428       cd_->status[3]    = cd_->xbus_status;
429       cd_->MEI_status   = MEI_CDROM_no_error;
430       cd_->poll        |= POLST;
431       break;
432 
433       /*
434         read error (get last status???)
435         opera status request  = 8 ---- tests status req=9?????
436         MKE                   = 8!!!
437         00
438         11
439         22   Current status     //MKE / Opera???
440         33
441         44
442         55
443         66
444         77
445         88   Current status     //TEST
446       */
447     case CDROM_CMD_GET_LAST_STATUS:
448       cd_->xbus_status |= CDST_RDY;
449       cd_->status_len   = 10;
450       cd_->status[0]    = CDROM_CMD_GET_LAST_STATUS;
451       cd_->status[1]    = cd_->MEI_status;
452       cd_->status[2]    = cd_->MEI_status;
453       cd_->status[3]    = cd_->MEI_status;
454       cd_->status[4]    = cd_->MEI_status;
455       cd_->status[5]    = cd_->MEI_status;
456       cd_->status[6]    = cd_->MEI_status;
457       cd_->status[7]    = cd_->MEI_status;
458       cd_->status[8]    = cd_->MEI_status;
459       cd_->status[9]    = cd_->xbus_status; /* 1 == disc present */
460       cd_->poll        |= POLST;
461       break;
462 
463       /*
464         read id
465         opera status request = 10
466         status 12 bytes (3 words)
467         MEI text + XS
468         00 M E I 1 01 00 00 00 00 00 XS
469       */
470     case CDROM_CMD_READ_ID:
471       cd_->xbus_status |= CDST_RDY;
472       cd_->status_len   = 12;
473       cd_->status[0]    = CDROM_CMD_READ_ID;
474       cd_->status[1]    = 0x00; /* manufacture id */
475       cd_->status[2]    = 0x10; /* 10 */
476       cd_->status[3]    = 0x00; /* manufacture number */
477       cd_->status[4]    = 0x01; /* 01 */
478       cd_->status[5]    = 00;
479       cd_->status[6]    = 00;
480       cd_->status[7]    = 0;    /* revision number */
481       cd_->status[8]    = 0;
482       cd_->status[9]    = 0x00; /* flag bytes */
483       cd_->status[10]   = 0x00;
484       cd_->status[11]   = cd_->xbus_status; /* device driver size */
485       cd_->MEI_status   = MEI_CDROM_no_error;
486       cd_->poll        |= POLST;
487       break;
488 
489       /*
490         mode sense
491         not used in opera
492         84 mm 00 00 00 00 00.
493         status 4 bytes
494         xx S1 S2 XS
495         xx xx nn XS
496       */
497     case CDROM_CMD_MODE_SENSE:
498       if((cd_->xbus_status & CDST_TRAY) &&
499          (cd_->xbus_status & CDST_DISC))
500         {
501           cd_->xbus_status |= CDST_RDY;
502         }
503       else
504         {
505           cd_->xbus_status |= CDST_ERRO;
506           cd_->xbus_status &= ~CDST_RDY;
507         }
508 
509       cd_->status_len  = 4;
510       cd_->status[0]   = 0x00;
511       cd_->status[1]   = 0x00;
512       cd_->status[2]   = 0x00;
513       cd_->status[3]   = cd_->xbus_status;
514       cd_->poll       |= POLST;
515       break;
516 
517       /*
518         read capacity
519         status 8 bytes
520         opera status request = 6
521         cc cc cc cc cc cc cc XS
522         data?
523         00 85
524         11 mm  total
525         22 ss  total
526         33 ff  total
527         44 ??
528         55 ??
529         66 ??
530       */
531     case CDROM_CMD_READ_CAPACITY:
532       if((cd_->xbus_status & CDST_TRAY) &&
533          (cd_->xbus_status & CDST_DISC) &&
534          (cd_->xbus_status & CDST_SPIN))
535         {
536           cd_->status_len   = 8; //CMD+status+DRVSTAT
537           cd_->status[0]    = CDROM_CMD_READ_CAPACITY;
538           cd_->status[1]    = 0;
539           cd_->status[2]    = cd_->disc.msf_total.minutes;
540           cd_->status[3]    = cd_->disc.msf_total.seconds;
541           cd_->status[4]    = cd_->disc.msf_total.frames;
542           cd_->status[5]    = 0x00;
543           cd_->status[6]    = 0x00;
544           cd_->xbus_status |= CDST_RDY;
545           cd_->status[7]    = cd_->xbus_status;
546           cd_->MEI_status   = MEI_CDROM_no_error;
547           cd_->poll        |= POLST;
548         }
549       else
550         {
551           cd_->xbus_status |= CDST_ERRO;
552           cd_->xbus_status &= ~CDST_RDY;
553           cd_->status_len   = 2; //CMD+status+DRVSTAT
554           cd_->status[0]    = CDROM_CMD_READ_CAPACITY;
555           cd_->status[1]    = cd_->xbus_status;
556           cd_->poll        |= POLST;
557           cd_->MEI_status   = MEI_CDROM_recv_ecc;
558         }
559       break;
560 
561       /*
562         read header
563         not used in opera
564         86 00 ll-bb-aa 00 00.
565         86 02 mm-ss-ff 00 00.
566         status 8 bytes
567         data?
568       */
569     case CDROM_CMD_READ_HEADER:
570       break;
571 
572       /*
573         read subq
574         opera status request = 10
575         87 fl 00 00 00 00 00
576         fl                   = 0 "lba"
577         fl                   = 1 "msf"
578 
579         11 00 (if != 00 then break)
580         22 Subq_ctl_adr = swapnibles(_11_)
581         33 Subq_trk = but2bcd(_22_)
582         44 Subq_pnt_idx = byt2bcd(_33_)
583         55 mm run tot
584         66 ss run tot
585         77 ff run tot
586         88 mm run trk
587         99 ss run trk
588         aa ff run trk
589       */
590     case CDROM_CMD_READ_SUBQ:
591       if((cd_->xbus_status & CDST_TRAY) &&
592          (cd_->xbus_status & CDST_DISC) &&
593          (cd_->xbus_status & CDST_SPIN))
594         {
595           cd_->xbus_status |= CDST_RDY;
596           cd_->status_len   = 12; /* CMD+status+DRVSTAT */
597           cd_->status[0]    = CDROM_CMD_READ_SUBQ;
598           cd_->status[1]    = 0; /* disc.msf_total.minutes; minutes */
599           cd_->status[2]    = 0; /* disc.msf_total.seconds; seconds */
600           cd_->status[3]    = 0; /* disc.msf_total.frames; frames  */
601           cd_->status[4]    = 0;
602           cd_->status[5]    = 0;
603           cd_->status[6]    = 0x0;
604           cd_->status[7]    = 0x0;
605           cd_->status[8]    = 0x0;
606           cd_->status[9]    = 0x0;
607           cd_->status[10]   = 0x0;
608           cd_->status[11]   = cd_->xbus_status;
609           cd_->MEI_status   = MEI_CDROM_no_error;
610           cd_->poll        |= POLST;
611         }
612       else
613         {
614           cd_->xbus_status |= CDST_ERRO;
615           cd_->xbus_status &= ~CDST_RDY;
616           cd_->status_len   = 2; /* CMD+status+DRVSTAT */
617           cd_->status[0]    = CDROM_CMD_READ_SUBQ;
618           cd_->status[1]    = cd_->xbus_status;
619           cd_->MEI_status   = MEI_CDROM_recv_ecc;
620           cd_->poll        |= POLST;
621         }
622       break;
623 
624       /*
625         read upc
626         not used in opera
627         88 00 ll-bb-aa 00 00
628         88 02 mm-ss-ff 00 00
629         status 20(16) bytes
630         data?
631       */
632     case CDROM_CMD_READ_UPC:
633       break;
634 
635       /*
636         read isrc
637         not used in opera
638         89 00 ll-bb-aa 00 00
639         89 02 mm-ss-ff 00 00
640         status 16(15) bytes
641         data?
642       */
643     case CDROM_CMD_READ_ISRC:
644       break;
645 
646       /*
647         read disc code
648         ignore it yet...
649         opera status request = 10
650         8a 00 00 00 00 00 00
651         status 10 bytes
652         ????? which code???
653       */
654     case CDROM_CMD_READ_DISC_CODE:
655       if((cd_->xbus_status & CDST_TRAY) &&
656          (cd_->xbus_status & CDST_DISC) &&
657          (cd_->xbus_status & CDST_SPIN))
658         {
659           cd_->xbus_status |= CDST_RDY;
660           cd_->status_len   = 12; /* CMD+status+DRVSTAT */
661           cd_->status[0]    = CDROM_CMD_READ_DISC_CODE;
662           cd_->status[1]    = 0; /* disc.msf_total.minutes; */
663           cd_->status[2]    = 0; /* disc.msf_total.seconds;  */
664           cd_->status[3]    = 0; /* disc.msf_total.frames; */
665           cd_->status[4]    = 0;
666           cd_->status[5]    = 0;
667           cd_->status[6]    = 0x00;
668           cd_->status[7]    = 0x00;
669           cd_->status[8]    = 0x00;
670           cd_->status[9]    = 0x00;
671           cd_->status[10]   = 0x00;
672           cd_->status[11]   = cd_->xbus_status;
673           cd_->MEI_status   = MEI_CDROM_no_error;
674           cd_->poll        |= POLST;
675         }
676       else
677         {
678           cd_->xbus_status |= CDST_ERRO;
679           cd_->xbus_status &= ~CDST_RDY;
680           cd_->status_len   = 2; /* CMD+status+DRVSTAT */
681           cd_->status[0]    = CDROM_CMD_READ_DISC_CODE;
682           cd_->status[1]    = cd_->xbus_status;
683           cd_->MEI_status   = MEI_CDROM_recv_ecc;
684           cd_->poll        |= POLST;
685         }
686       break;
687 
688       /*
689         MKE !!!v the same
690         read disc information
691         opera status request = 6
692         8b 00 00 00 00 00 00
693         status 8(6) bytes
694         read the toc descritor
695         00 11 22 33 44 55 XS
696         00 = 8b                 // command code
697         11 = Disc ID            // XA_BYTE
698         22 = 1st track#
699         33 = last track#
700         44 = minutes
701         55 = seconds
702         66 = frames
703       */
704     case CDROM_CMD_READ_DISC_INFO:
705       if((cd_->xbus_status & CDST_TRAY) &&
706          (cd_->xbus_status & CDST_DISC) &&
707          (cd_->xbus_status & CDST_SPIN))
708         {
709           cd_->xbus_status |= CDST_RDY;
710           cd_->status_len   = 8;
711           cd_->status[0]    = CDROM_CMD_READ_DISC_INFO;
712           cd_->status[1]    = cd_->disc.disc_id;
713           cd_->status[2]    = cd_->disc.track_first;
714           cd_->status[3]    = cd_->disc.track_last;
715           cd_->status[4]    = cd_->disc.msf_total.minutes;
716           cd_->status[5]    = cd_->disc.msf_total.seconds;
717           cd_->status[6]    = cd_->disc.msf_total.frames;
718           cd_->status[7]    = cd_->xbus_status;
719           cd_->MEI_status   = MEI_CDROM_no_error;
720         }
721       else
722         {
723           cd_->status_len   = 2;
724           cd_->xbus_status |= CDST_ERRO;
725           cd_->status[0]    = CDROM_CMD_READ_DISC_INFO;
726           cd_->status[1]    = cd_->xbus_status;
727           cd_->MEI_status   = MEI_CDROM_recv_ecc;
728         }
729 
730       cd_->poll |= POLST;
731       break;
732 
733       /*
734         read toc
735         MKE !!!v the same
736         opera status request = 8
737         8c fl nn 00 00 00 00    // reads nn entry
738         status 12(8) bytes
739         00 11 22 33 44 55 66 77 XS
740         00 = 8c
741         11 = reserved0;         //NIX BYTE
742         22 = addressAndControl; //TOCENT_CTL_ADR=swapnibbles(11) ??? UPCCTLADR=_10_ | x02 (_11_ &F0 = _10_)
743         33 = trackNumber;       //TOC_ENT NUMBER
744         44 = reserved3;         //TOC_ENT FORMAT
745         55 = minutes;           //TOC_ENT ADRESS == 0x00445566
746         66 = seconds;
747         77 = frames;
748         88 = reserved7;
749       */
750     case CDROM_CMD_READ_TOC:
751       if((cd_->xbus_status & CDST_TRAY) &&
752          (cd_->xbus_status & CDST_DISC) &&
753          (cd_->xbus_status & CDST_SPIN))
754         {
755           toc_entry_t *toc = &cd_->disc.disc_toc[cd_->cmd[2]];
756 
757           cd_->xbus_status |= CDST_RDY;
758           cd_->status_len   = 10; /* CMD+status+DRVSTAT */
759           cd_->status[0]    = CDROM_CMD_READ_TOC;
760           cd_->status[1]    = toc->res0;
761           cd_->status[2]    = toc->CDCTL;
762           cd_->status[3]    = toc->track_number;
763           cd_->status[4]    = toc->res1;
764           cd_->status[5]    = toc->minutes;
765           cd_->status[6]    = toc->seconds;
766           cd_->status[7]    = toc->frames;
767           cd_->status[8]    = toc->res2;
768           cd_->status[9]    = cd_->xbus_status;
769           cd_->MEI_status   = MEI_CDROM_no_error;
770         }
771       else
772         {
773           cd_->status_len   = 2;
774           cd_->xbus_status |= CDST_ERRO;
775           cd_->status[0]    = CDROM_CMD_READ_TOC;
776           cd_->status[1]    = cd_->xbus_status;
777           cd_->MEI_status   = MEI_CDROM_recv_ecc;
778         }
779 
780       cd_->poll |= POLST;
781       break;
782 
783       /*
784         read session information
785         MKE !!!v the same
786         opera status request  = 6
787         status 8(6)
788         00 11 22 33 44 55 XS ==
789         00 = 8d
790         11 = valid;             // 0x80 = MULTISESS
791         22 = minutes;
792         33 = seconds;
793         44 = frames;
794         55 = rfu1;              //ignore
795         66 = rfu2               //ignore
796       */
797     case CDROM_CMD_READ_SESSION_INFO:
798       if((cd_->xbus_status & CDST_TRAY) &&
799          (cd_->xbus_status & CDST_DISC))
800         {
801           cd_->xbus_status |= CDST_RDY;
802           cd_->status_len   = 8; /* CMD+status+DRVSTAT */
803           cd_->status[0]    = CDROM_CMD_READ_SESSION_INFO;
804           cd_->status[1]    = 0x00;
805           cd_->status[2]    = cd_->disc.msf_session.minutes;
806           cd_->status[3]    = cd_->disc.msf_session.seconds;
807           cd_->status[4]    = cd_->disc.msf_session.frames;
808           cd_->status[5]    = 0x00;
809           cd_->status[6]    = 0x00;
810           cd_->status[7]    = cd_->xbus_status;
811           cd_->MEI_status   = MEI_CDROM_no_error;
812         }
813       else
814         {
815           cd_->status_len   = 2; //CMD+status+DRVSTAT
816           cd_->xbus_status |= CDST_ERRO;
817           cd_->status[0]    = CDROM_CMD_READ_SESSION_INFO;
818           cd_->status[1]    = cd_->xbus_status;
819           cd_->MEI_status   = MEI_CDROM_recv_ecc;
820         }
821 
822       cd_->poll |= POLST;
823       break;
824 
825       /* read device driver */
826     case CDROM_CMD_READ_DEVICE_DRIVER:
827       break;
828 
829       /* ????? */
830     case CDROM_CMD_UNKNOWN_0x93:
831       if((cd_->xbus_status & CDST_TRAY) &&
832          (cd_->xbus_status & CDST_DISC))
833         {
834           cd_->xbus_status |= CDST_RDY;
835         }
836       else
837         {
838           cd_->xbus_status |= CDST_ERRO;
839           cd_->xbus_status |= CDST_RDY;
840         }
841 
842       cd_->status_len = 4;
843       cd_->status[0]  = 0x0;
844       cd_->status[1]  = 0x0;
845       cd_->status[2]  = 0x0;
846       cd_->status[3]  = cd_->xbus_status;
847 
848       cd_->poll |= POLST;
849       break;
850 
851       /* error: shouldn't happen */
852     default:
853       break;
854     }
855 }
856 
857 void
opera_cdrom_send_cmd(cdrom_device_t * cd_,uint8_t val_)858 opera_cdrom_send_cmd(cdrom_device_t *cd_,
859                      uint8_t         val_)
860 {
861   if(cd_->cmd_idx < 7)
862     cd_->cmd[cd_->cmd_idx++] = (uint8_t)val_;
863 
864   if((cd_->cmd_idx >= 7) || (cd_->cmd[0] == 0x08))
865     {
866       opera_cdrom_do_cmd(cd_);
867       cd_->cmd_idx = 0;
868     }
869 }
870 
871 int
opera_cdrom_test_fiq(cdrom_device_t * cd_)872 opera_cdrom_test_fiq(cdrom_device_t *cd_)
873 {
874   return (((cd_->poll & POLST) && (cd_->poll & POLSTMASK)) ||
875           ((cd_->poll & POLDT) && (cd_->poll & POLDTMASK)));
876 }
877 
878 void
opera_cdrom_set_poll(cdrom_device_t * cd_,uint32_t val_)879 opera_cdrom_set_poll(cdrom_device_t *cd_,
880                      uint32_t        val_)
881 {
882   cd_->poll = ((cd_->poll & 0xF0) | (val_ & 0x0F));
883 }
884 
885 uint8_t
opera_cdrom_fifo_get_data(cdrom_device_t * cd_)886 opera_cdrom_fifo_get_data(cdrom_device_t *cd_)
887 {
888   uint8_t rv;
889 
890   rv = 0;
891   if(cd_->data_len > 0)
892     {
893       rv = cd_->data[cd_->data_idx];
894       cd_->data_idx++;
895       cd_->data_len--;
896 
897       if(cd_->data_len == 0)
898         {
899           cd_->data_idx = 0;
900           if(cd_->blocks_requested)
901             {
902               CDROM_SET_SECTOR(cd_->current_sector++);
903               CDROM_READ_SECTOR(cd_->data);
904               cd_->data_len = REQSIZE;
905               cd_->blocks_requested--;
906             }
907           else
908             {
909               cd_->poll             &= ~POLDT;
910               cd_->blocks_requested  = 0;
911               cd_->data_len          = 0;
912               cd_->data_idx          = 0;
913             }
914         }
915     }
916 
917   return rv;
918 }
919