HostCDROM.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: package xeij;
14:
15: import java.awt.event.*;
16: import java.lang.foreign.*;
17: import java.lang.invoke.*;
18: import java.util.*;
19: import javax.sound.sampled.*;
20: import javax.swing.*;
21: import javax.swing.event.*;
22:
23:
24:
25: public class HostCDROM {
26:
27:
28:
29:
30: public static final boolean HCD_ENABLED = true;
31: static final int HCD_DEFAULT_SCSI_ID = 6;
32: static final int HCD_DEFAULT_VOLUME = 25;
33: static final int HCD_PLAY_QUEUE_SIZE = 4;
34: static final int HCD_PLAY_SECTORS = 30;
35: static final int HCD_PLAY_MILLIS = 1000 * HCD_PLAY_SECTORS / 75;
36: static final int HCD_PLAY_BYTES = 2352 * HCD_PLAY_SECTORS;
37:
38:
39:
40: static final int ERROR_NOT_READY = 21;
41: static final int ERROR_WRONG_DISK = 34;
42: static final int ERROR_NO_MORE_ITEMS = 259;
43:
44:
45: static final long INVALID_HANDLE_VALUE = -1L;
46:
47: static final int GENERIC_ALL = 0x10000000;
48: static final int GENERIC_EXECUTE = 0x20000000;
49: static final int GENERIC_WRITE = 0x40000000;
50: static final int GENERIC_READ = 0x80000000;
51:
52: static final int FILE_SHARE_READ = 0x00000001;
53: static final int FILE_SHARE_WRITE = 0x00000002;
54: static final int FILE_SHARE_DELETE = 0x00000004;
55:
56: static final int CREATE_NEW = 1;
57: static final int CREATE_ALWAYS = 2;
58: static final int OPEN_EXISTING = 3;
59: static final int OPEN_ALWAYS = 4;
60: static final int TRUNCATE_EXISTING = 5;
61:
62: static final int FILE_BEGIN = 0;
63: static final int FILE_CURRENT = 1;
64: static final int FILE_END = 2;
65:
66:
67:
68: static final int DRIVE_UNKNOWN = 0;
69: static final int DRIVE_NO_ROOT_DIR = 1;
70: static final int DRIVE_REMOVABLE = 2;
71: static final int DRIVE_FIXED = 3;
72: static final int DRIVE_REMOTE = 4;
73: static final int DRIVE_CDROM = 5;
74: static final int DRIVE_RAMDISK = 6;
75:
76: static final int IOCTL_CDROM_READ_TOC = 0x00024000;
77: static final int IOCTL_CDROM_RAW_READ = 0x0002403e;
78: static final int IOCTL_CDROM_READ_TOC_EX = 0x00024054;
79: static final int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x0004d014;
80: static final int IOCTL_SCSI_PASS_THROUGH_DIRECT_EX = 0x0004d048;
81: static final int IOCTL_STORAGE_CHECK_VERIFY2 = 0x002d0800;
82: static final int IOCTL_STORAGE_LOAD_MEDIA2 = 0x002d080c;
83: static final int IOCTL_STORAGE_QUERY_PROPERTY = 0x002d1400;
84: static final int IOCTL_STORAGE_CHECK_VERIFY = 0x002d4800;
85: static final int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002d4804;
86: static final int IOCTL_STORAGE_EJECT_MEDIA = 0x002d4808;
87: static final int IOCTL_STORAGE_LOAD_MEDIA = 0x002d480c;
88: static final int CDROM_READ_TOC_EX_FORMAT_TOC = 0x00000000;
89:
90: static final int MAXIMUM_NUMBER_TRACKS = 0x00000064;
91:
92:
93: static final int YellowMode2 = 0;
94: static final int XAForm2 = 1;
95: static final int CDDA = 2;
96: static final int RawWithC2AndSubCode = 3;
97: static final int RawWithC2 = 4;
98: static final int RawWithSubCode = 5;
99:
100:
101:
102: static final int StorageDeviceProperty = 0;
103:
104:
105:
106: static final int PropertyStandardQuery = 0;
107:
108:
109: static final int BusTypeUnknown = 0;
110: static final int BusTypeScsi = 1;
111: static final int BusTypeAtapi = 2;
112: static final int BusTypeAta = 3;
113: static final int BusType1394 = 4;
114: static final int BusTypeSsa = 5;
115: static final int BusTypeFibre = 6;
116: static final int BusTypeUsb = 7;
117: static final int BusTypeRAID = 8;
118: static final int BusTypeiScsi = 9;
119: static final int BusTypeSas = 10;
120: static final int BusTypeSata = 11;
121: static final int BusTypeSd = 12;
122: static final int BusTypeMmc = 13;
123: static final int BusTypeVirtual = 14;
124: static final int BusTypeFileBackedVirtual = 15;
125: static final int BusTypeSpaces = 16;
126: static final int BusTypeNvme = 17;
127: static final int BusTypeSCM = 18;
128: static final int BusTypeUfs = 19;
129: static final int BusTypeNvmeof = 20;
130: static final int BusTypeMax = 21;
131: static final int BusTypeMaxReserved = 127;
132:
133:
134:
135:
136: static boolean hcdAvailable;
137: static boolean hcdDebugInfo;
138: static boolean hcdConnectNext;
139: static boolean hcdConnected;
140: static int hcdSCSIIdNext;
141: public static int hcdSCSIId;
142: static int hcdVolumeInt;
143: static float hcdVolumeFloat;
144:
145:
146: static JSpinner hcdIdSpinner;
147: static SpinnerNumberModel hcdIdModel;
148: static JLabel hcdVolumeLabel;
149: static JSlider hcdVolumeSlider;
150: public static JMenu hcdMenu;
151:
152:
153: static MemoryLayout TRACK_DATA;
154: static MemoryLayout CDROM_TOC;
155: static MemoryLayout CDROM_READ_TOC_EX;
156: static MemoryLayout RAW_READ_INFO;
157: static MemoryLayout STORAGE_DEVICE_DESCRIPTOR;
158: static MemoryLayout STORAGE_PROPERTY_QUERY;
159:
160:
161: static Linker linker;
162: static MethodHandle downcallHandle (MemorySegment address, FunctionDescriptor function) {
163: return linker.downcallHandle (address, function);
164: }
165:
166:
167: static Arena arena;
168:
169:
170: static MethodHandle CloseHandle;
171: static MethodHandle CreateFileA;
172: static MethodHandle DeviceIoControl;
173: static MethodHandle GetDiskFreeSpaceA;
174: static MethodHandle GetDriveTypeA;
175: static MethodHandle GetLastError;
176: static MethodHandle GetLogicalDrives;
177: static MethodHandle QueryDosDeviceA;
178: static MethodHandle ReadFile;
179: static MethodHandle SetFilePointerEx;
180:
181:
182: static int hcdDriveLetter;
183: static String hcdRootPath;
184: static String hcdDevicePath;
185: public static String hcdDeviceName;
186: static byte[] hcdVendorProduct;
187:
188:
189: static volatile boolean hcdRunning;
190: static volatile boolean hcdPlaying;
191: static volatile boolean hcdPausing;
192: static volatile int hcdAudioStatus;
193:
194:
195: static MemorySegment hcdReadTocEx;
196: static MemorySegment hcdToc;
197: static MemorySegment hcdBytesReturned;
198: static MemorySegment hcdBufferSegment;
199: static MemorySegment hcdReadInfo;
200:
201:
202: static MemorySegment hcdHandle;
203:
204:
205: static SourceDataLine hcdSourceDataLine;
206:
207:
208: static byte[][] hcdPlayQueueArray;
209: static volatile int hcdPlayQueueWrite;
210: static volatile int hcdPlayQueueRead;
211:
212:
213: static Thread hcdReadThread;
214: static volatile int hcdStartSector;
215: static volatile int hcdCurrentSector;
216: static volatile int hcdEndSector;
217:
218:
219: static int[] hcdTOCAddressArray;
220: static int hcdTOCFirstTrack;
221: static int hcdTOCLastTrack;
222:
223:
224: static int hcdDataOffset;
225:
226:
227: static Thread hcdPlayThread;
228:
229:
230: static volatile int hcdRequested;
231: static volatile int hcdCompleted;
232: static volatile int hcdRetrieved;
233: static volatile SPC.SCUnit hcdUnit;
234: static volatile SPC.SPCChip hcdChip;
235: static volatile byte[] hcdResultBuffer;
236: static volatile int hcdResultLength;
237: static volatile int hcdResultSense0;
238: static volatile int hcdResultSense2;
239: static volatile int hcdResultStatus;
240: static volatile int hcdResultMessage;
241: static volatile int hcdBytesPerSector;
242:
243:
244:
245:
246:
247:
248:
249: public static void hcdInit () {
250:
251:
252: hcdAvailable = HCD_ENABLED && XEiJ.prgIsWindows;
253: hcdDebugInfo = Settings.sgsGetOnOff ("hcddebug");
254: hcdConnectNext = Settings.sgsGetOnOff ("hcdconnect");
255: hcdConnected = hcdConnectNext;
256: hcdSCSIIdNext = Settings.sgsGetInt ("hcdscsiid", HCD_DEFAULT_SCSI_ID);
257: if (hcdSCSIIdNext < 0 || 15 < hcdSCSIIdNext) {
258: hcdSCSIIdNext = HCD_DEFAULT_SCSI_ID;
259: }
260: hcdSCSIId = hcdSCSIIdNext;
261: hcdVolumeInt = Settings.sgsGetInt ("hcdvolume", HCD_DEFAULT_VOLUME);
262: if (hcdVolumeInt < 0 || 100 < hcdVolumeInt) {
263: hcdVolumeInt = HCD_DEFAULT_VOLUME;
264: }
265: if (hcdDebugInfo) {
266: System.out.printf ("volume=%d\n", hcdVolumeInt);
267: }
268: hcdVolumeFloat = (float) hcdVolumeInt / 100F;
269:
270:
271: ActionListener listener = new ActionListener () {
272: @Override public void actionPerformed (ActionEvent ae) {
273: Object source = ae.getSource ();
274: String command = ae.getActionCommand ();
275: switch (command) {
276: case "Connect on next execution":
277: hcdConnectNext = ((JCheckBoxMenuItem) source).isSelected ();
278: break;
279: case "Debug info":
280: hcdDebugInfo = ((JCheckBoxMenuItem) source).isSelected ();
281: break;
282: default:
283: System.out.println ("unknown action command " + command);
284: }
285: }
286: };
287: hcdMenu = Multilingual.mlnText (
288: ComponentFactory.createMenu (
289: "Host CD-ROM",
290: Multilingual.mlnText (
291: ComponentFactory.createCheckBoxMenuItem (hcdConnectNext, "Connect on next execution", listener),
292: "ja", "次回の実行時に接続する"),
293: ComponentFactory.createHorizontalBox (
294: Box.createHorizontalStrut (20),
295: ComponentFactory.createLabel ("SCSI ID "),
296: hcdIdSpinner = ComponentFactory.createNumberSpinner (
297: hcdIdModel = new SpinnerNumberModel (hcdSCSIIdNext, 0, 15, 1),
298: 2,
299: new ChangeListener () {
300: @Override public void stateChanged (ChangeEvent ce) {
301: hcdSCSIIdNext = hcdIdModel.getNumber ().intValue ();
302: }
303: }
304: ),
305: Box.createHorizontalGlue ()
306: ),
307: ComponentFactory.createHorizontalBox (
308: Box.createHorizontalGlue (),
309: Multilingual.mlnText (ComponentFactory.createLabel ("Volume "), "ja", "音量 "),
310: hcdVolumeLabel = ComponentFactory.createLabel (String.valueOf (hcdVolumeInt)),
311: Box.createHorizontalGlue ()
312: ),
313: ComponentFactory.createHorizontalBox (
314: hcdVolumeSlider = ComponentFactory.setPreferredSize (
315: ComponentFactory.createHorizontalSlider (
316: 0, 100, hcdVolumeInt, 10, 1,
317: new ChangeListener () {
318: @Override public void stateChanged (ChangeEvent ce) {
319: hcdVolumeInt = ((JSlider) ce.getSource ()).getValue ();
320: if (hcdDebugInfo) {
321: System.out.printf ("volume=%d\n", hcdVolumeInt);
322: }
323: hcdVolumeFloat = (float) hcdVolumeInt / 100F;
324: hcdVolumeLabel.setText (String.valueOf (hcdVolumeInt));
325: }
326: }
327: ),
328: LnF.lnfFontSize * 18, LnF.lnfFontSize * 2 + 28)
329: ),
330: ComponentFactory.createHorizontalSeparator (),
331: Multilingual.mlnText (
332: ComponentFactory.createCheckBoxMenuItem (hcdDebugInfo, "Debug info", listener),
333: "ja", "デバッグ情報")
334: ),
335: "ja", "ホスト CD-ROM");
336: hcdMenu.setEnabled (false);
337:
338: if (!hcdAvailable) {
339: hcdConnected = false;
340: return;
341: }
342:
343:
344:
345: TRACK_DATA = MemoryLayout.structLayout (
346: ValueLayout.JAVA_BYTE.withName ("Reserved"),
347: ValueLayout.JAVA_BYTE.withName ("Adr_Control"),
348: ValueLayout.JAVA_BYTE.withName ("TrackNumber"),
349: ValueLayout.JAVA_BYTE.withName ("Reserved1"),
350: MemoryLayout.sequenceLayout (4, ValueLayout.JAVA_BYTE).withName ("Address"));
351:
352:
353:
354: CDROM_TOC = MemoryLayout.structLayout (
355: MemoryLayout.sequenceLayout (2, ValueLayout.JAVA_BYTE).withName ("Length"),
356: ValueLayout.JAVA_BYTE.withName ("FirstTrack"),
357: ValueLayout.JAVA_BYTE.withName ("LastTrack"),
358: MemoryLayout.sequenceLayout (MAXIMUM_NUMBER_TRACKS, TRACK_DATA).withName ("TrackData"));
359:
360:
361: CDROM_READ_TOC_EX = MemoryLayout.structLayout (
362: ValueLayout.JAVA_BYTE.withName ("Msf_Reserved1_Format"),
363: ValueLayout.JAVA_BYTE.withName ("SessionTrack"),
364: ValueLayout.JAVA_BYTE.withName ("Reserved2"),
365: ValueLayout.JAVA_BYTE.withName ("Reserved3"));
366:
367:
368:
369: RAW_READ_INFO = MemoryLayout.structLayout (
370: ValueLayout.JAVA_LONG.withName ("DiskOffset"),
371: ValueLayout.JAVA_INT.withName ("SectorCount"),
372: ValueLayout.JAVA_INT.withName ("TrackMode"));
373:
374:
375:
376:
377: STORAGE_DEVICE_DESCRIPTOR = MemoryLayout.structLayout (
378: ValueLayout.JAVA_INT.withName ("Version"),
379: ValueLayout.JAVA_INT.withName ("Size"),
380: ValueLayout.JAVA_BYTE.withName ("DeviceType"),
381: ValueLayout.JAVA_BYTE.withName ("DeviceTypeModifier"),
382: ValueLayout.JAVA_BYTE.withName ("RemovableMedia"),
383: ValueLayout.JAVA_BYTE.withName ("CommandQueueing"),
384: ValueLayout.JAVA_INT.withName ("VendorIdOffset"),
385: ValueLayout.JAVA_INT.withName ("ProductIdOffset"),
386: ValueLayout.JAVA_INT.withName ("ProductRevisionOffset"),
387: ValueLayout.JAVA_INT.withName ("SerialNumberOffset"),
388: ValueLayout.JAVA_INT.withName ("BusType"),
389: ValueLayout.JAVA_INT.withName ("RawPropertiesLength"),
390: MemoryLayout.sequenceLayout (1, ValueLayout.JAVA_BYTE).withName ("RawDeviceProperties"),
391: MemoryLayout.paddingLayout (3)
392:
393: );
394:
395:
396:
397:
398:
399:
400: STORAGE_PROPERTY_QUERY = MemoryLayout.structLayout (
401: ValueLayout.JAVA_INT.withName ("PropertyId"),
402: ValueLayout.JAVA_INT.withName ("QueryType"),
403: MemoryLayout.sequenceLayout (1, ValueLayout.JAVA_BYTE).withName ("AdditionalParameters"),
404: MemoryLayout.paddingLayout (3)
405:
406: );
407:
408:
409: linker = Linker.nativeLinker ();
410:
411:
412: arena = Arena.ofAuto ();
413:
414:
415: SymbolLookup kernel32 = SymbolLookup.libraryLookup ("kernel32", arena);
416:
417:
418: try {
419:
420:
421:
422: CloseHandle = downcallHandle (
423: kernel32.findOrThrow ("CloseHandle"),
424: FunctionDescriptor.of (
425: ValueLayout.JAVA_INT,
426: ValueLayout.ADDRESS));
427:
428:
429:
430: CreateFileA = downcallHandle (
431: kernel32.findOrThrow ("CreateFileA"),
432: FunctionDescriptor.of (
433: ValueLayout.ADDRESS,
434: ValueLayout.ADDRESS,
435: ValueLayout.JAVA_INT,
436: ValueLayout.JAVA_INT,
437: ValueLayout.ADDRESS,
438: ValueLayout.JAVA_INT,
439: ValueLayout.JAVA_INT,
440: ValueLayout.ADDRESS));
441:
442:
443:
444: DeviceIoControl = downcallHandle (
445: kernel32.findOrThrow ("DeviceIoControl"),
446: FunctionDescriptor.of (
447: ValueLayout.JAVA_INT,
448: ValueLayout.ADDRESS,
449: ValueLayout.JAVA_INT,
450: ValueLayout.ADDRESS,
451: ValueLayout.JAVA_INT,
452: ValueLayout.ADDRESS,
453: ValueLayout.JAVA_INT,
454: ValueLayout.ADDRESS,
455: ValueLayout.ADDRESS));
456:
457:
458:
459: GetDiskFreeSpaceA = downcallHandle (
460: kernel32.findOrThrow ("GetDiskFreeSpaceA"),
461: FunctionDescriptor.of (
462: ValueLayout.JAVA_INT,
463: ValueLayout.ADDRESS,
464: ValueLayout.ADDRESS,
465: ValueLayout.ADDRESS,
466: ValueLayout.ADDRESS,
467: ValueLayout.ADDRESS));
468:
469:
470:
471: GetDriveTypeA = downcallHandle (
472: kernel32.findOrThrow ("GetDriveTypeA"),
473: FunctionDescriptor.of (
474: ValueLayout.JAVA_INT,
475: ValueLayout.ADDRESS));
476:
477:
478:
479: GetLastError = downcallHandle (
480: kernel32.findOrThrow ("GetLastError"),
481: FunctionDescriptor.of (
482: ValueLayout.JAVA_INT));
483:
484:
485:
486: GetLogicalDrives = downcallHandle (
487: kernel32.findOrThrow ("GetLogicalDrives"),
488: FunctionDescriptor.of (
489: ValueLayout.JAVA_INT));
490:
491:
492:
493: QueryDosDeviceA = downcallHandle (
494: kernel32.findOrThrow ("QueryDosDeviceA"),
495: FunctionDescriptor.of (
496: ValueLayout.JAVA_INT,
497: ValueLayout.ADDRESS,
498: ValueLayout.ADDRESS,
499: ValueLayout.JAVA_INT));
500:
501:
502:
503: ReadFile = downcallHandle (
504: kernel32.findOrThrow ("ReadFile"),
505: FunctionDescriptor.of (
506: ValueLayout.JAVA_INT,
507: ValueLayout.ADDRESS,
508: ValueLayout.ADDRESS,
509: ValueLayout.JAVA_INT,
510: ValueLayout.ADDRESS,
511: ValueLayout.ADDRESS));
512:
513:
514:
515: SetFilePointerEx = downcallHandle (
516: kernel32.findOrThrow ("SetFilePointerEx"),
517: FunctionDescriptor.of (
518: ValueLayout.JAVA_INT,
519: ValueLayout.ADDRESS,
520: ValueLayout.JAVA_LONG,
521: ValueLayout.ADDRESS,
522: ValueLayout.JAVA_INT));
523:
524: } catch (NoSuchElementException nsee) {
525: if (hcdDebugInfo) {
526: nsee.printStackTrace ();
527: }
528: hcdAvailable = false;
529: hcdConnected = false;
530: return;
531: }
532:
533:
534: hcdDriveLetter = 0;
535: hcdRootPath = null;
536: hcdDevicePath = null;
537: hcdDeviceName = null;
538: try {
539: int error;
540: int logicalDrives = 0;
541: if ((logicalDrives = (int) GetLogicalDrives.invoke ()) == 0 &&
542: (error = (int) GetLastError.invoke ()) != -1) {
543: if (hcdDebugInfo) {
544: System.out.printf ("GetLogicalDrives returned error %d\n",
545: error);
546: }
547: hcdAvailable = false;
548: hcdConnected = false;
549: return;
550: }
551: for (int driveLetter = 'A'; driveLetter <= 'Z'; driveLetter++) {
552: if ((logicalDrives & (1 << (driveLetter - 'A'))) != 0) {
553: String rootPath = String.format ("%c:\\", driveLetter);
554: if ((int) GetDriveTypeA.invoke (
555: arena.allocateFrom (rootPath)) == DRIVE_CDROM) {
556: hcdDriveLetter = driveLetter;
557: hcdRootPath = rootPath;
558: break;
559: }
560: }
561: }
562: if (hcdDriveLetter == 0) {
563: if (hcdDebugInfo) {
564: System.out.println ("CD-ROM drive not found");
565: }
566: hcdAvailable = false;
567: hcdConnected = false;
568: return;
569: }
570: hcdDevicePath = String.format ("\\\\.\\%c:", hcdDriveLetter);
571: hcdDeviceName = String.format ("%c:", hcdDriveLetter);
572: if (hcdDebugInfo) {
573: System.out.printf ("CD-ROM drive is %s\n",
574: hcdDeviceName);
575: }
576:
577:
578:
579: MemorySegment handle;
580: if ((handle = (MemorySegment) CreateFileA.invoke (
581: arena.allocateFrom (hcdDevicePath),
582: 0,
583: FILE_SHARE_READ | FILE_SHARE_WRITE,
584: MemorySegment.NULL,
585: OPEN_EXISTING,
586: 0,
587: MemorySegment.NULL)).address () == INVALID_HANDLE_VALUE &&
588: (error = (int) GetLastError.invoke ()) != -1) {
589: if (hcdDebugInfo) {
590: System.out.printf ("CreateFileA returned error %d\n",
591: error);
592: }
593: } else {
594: MemorySegment query = arena.allocate (STORAGE_PROPERTY_QUERY);
595: MemorySegment descriptor = arena.allocate (1024);
596: MemorySegment bytesReturned = arena.allocate (ValueLayout.JAVA_INT);
597: query.set (ValueLayout.JAVA_INT,
598: STORAGE_PROPERTY_QUERY.byteOffset (MemoryLayout.PathElement.groupElement ("PropertyId")),
599: StorageDeviceProperty);
600: query.set (ValueLayout.JAVA_INT,
601: STORAGE_PROPERTY_QUERY.byteOffset (MemoryLayout.PathElement.groupElement ("QueryType")),
602: PropertyStandardQuery);
603: if ((int) DeviceIoControl.invoke (
604: handle,
605: IOCTL_STORAGE_QUERY_PROPERTY,
606: query,
607: (int) query.byteSize (),
608: descriptor,
609: (int) descriptor.byteSize (),
610: bytesReturned,
611: MemorySegment.NULL) == 0 &&
612: (error = (int) GetLastError.invoke ()) != -1) {
613: if (hcdDebugInfo) {
614: System.out.printf ("DeviceIoControl IOCTL_STORAGE_QUERY_PROPERTY returned error %d\n",
615: error);
616: }
617: } else {
618: hcdVendorProduct = new byte[8 + 16 + 4];
619: Arrays.fill (hcdVendorProduct, (byte) ' ');
620: for (int k = 0; k < 3; k++) {
621: int o = descriptor.get (ValueLayout.JAVA_INT,
622: STORAGE_DEVICE_DESCRIPTOR.byteOffset (MemoryLayout.PathElement.groupElement (
623: k == 0 ? "VendorIdOffset" :
624: k == 1 ? "ProductIdOffset" :
625: "ProductRevisionOffset")));
626: if (o != 0) {
627: int p = k == 0 ? 0 : k == 1 ? 8 : 8 + 16;
628: int l = k == 0 ? 8 : k == 1 ? 16 : 4;
629: for (int i = 0; i < l; i++) {
630: int c = 0xff & descriptor.get (ValueLayout.JAVA_BYTE, o++);
631: if (c == 0) {
632: break;
633: }
634: hcdVendorProduct[p++] = (byte) (0x20 <= c && c <= 0x7e ? c : '?');
635: }
636: }
637: }
638: if (hcdDebugInfo) {
639: System.out.print ("VendorProduct is ");
640: for (int i = 0; i < 8 + 16 + 4; i++) {
641: System.out.printf ("%c", 0xff & hcdVendorProduct[i]);
642: }
643: System.out.println ();
644: int BusType = descriptor.get (ValueLayout.JAVA_INT,
645: STORAGE_DEVICE_DESCRIPTOR.byteOffset (MemoryLayout.PathElement.groupElement ("BusType")));
646: System.out.printf ("BusType is %s\n",
647: BusType == BusTypeUnknown ? "BusTypeUnknown" :
648: BusType == BusTypeScsi ? "BusTypeScsi" :
649: BusType == BusTypeAtapi ? "BusTypeAtapi" :
650: BusType == BusTypeAta ? "BusTypeAta" :
651: BusType == BusType1394 ? "BusType1394" :
652: BusType == BusTypeSsa ? "BusTypeSsa" :
653: BusType == BusTypeFibre ? "BusTypeFibre" :
654: BusType == BusTypeUsb ? "BusTypeUsb" :
655: BusType == BusTypeRAID ? "BusTypeRAID" :
656: BusType == BusTypeiScsi ? "BusTypeiScsi" :
657: BusType == BusTypeSas ? "BusTypeSas" :
658: BusType == BusTypeSata ? "BusTypeSata" :
659: BusType == BusTypeSd ? "BusTypeSd" :
660: BusType == BusTypeMmc ? "BusTypeMmc" :
661: BusType == BusTypeVirtual ? "BusTypeVirtual" :
662: BusType == BusTypeFileBackedVirtual ? "BusTypeFileBackedVirtual" :
663: BusType == BusTypeSpaces ? "BusTypeSpaces" :
664: BusType == BusTypeNvme ? "BusTypeNvme" :
665: BusType == BusTypeSCM ? "BusTypeSCM" :
666: BusType == BusTypeUfs ? "BusTypeUfs" :
667: BusType == BusTypeNvmeof ? "BusTypeNvmeof" :
668: BusType == BusTypeMax ? "BusTypeMax" :
669: BusType == BusTypeMaxReserved ? "BusTypeMaxReserved" :
670: String.valueOf (BusType));
671: }
672: }
673: CloseHandle.invoke (handle);
674: }
675:
676: } catch (Throwable e) {
677: if (hcdDebugInfo) {
678: e.printStackTrace ();
679: }
680: hcdAvailable = false;
681: hcdConnected = false;
682: return;
683: }
684:
685: hcdMenu.setEnabled (true);
686:
687:
688: hcdRunning = true;
689:
690:
691: hcdReadTocEx = arena.allocate (CDROM_READ_TOC_EX);
692: hcdToc = arena.allocate (CDROM_TOC);
693: hcdBytesReturned = arena.allocate (ValueLayout.JAVA_INT);
694: hcdBufferSegment = arena.allocate (HCD_PLAY_BYTES);
695: hcdReadInfo = arena.allocate (RAW_READ_INFO);
696:
697:
698: hcdHandle = null;
699:
700:
701: hcdSourceDataLine = null;
702: try {
703: AudioFormat audioFormat = new AudioFormat (44100F,
704: 16,
705: 2,
706: true,
707: false);
708: hcdSourceDataLine = AudioSystem.getSourceDataLine (audioFormat);
709: hcdSourceDataLine.open (audioFormat, HCD_PLAY_BYTES * 2);
710: hcdSourceDataLine.start ();
711: } catch (LineUnavailableException lue) {
712: if (hcdDebugInfo) {
713: lue.printStackTrace ();
714: }
715: }
716:
717:
718: hcdPlayQueueArray = new byte[HCD_PLAY_QUEUE_SIZE][];
719: for (int i = 0; i < HCD_PLAY_QUEUE_SIZE; i++) {
720: hcdPlayQueueArray[i] = new byte[HCD_PLAY_BYTES];
721: }
722: hcdPlayQueueWrite = 0;
723: hcdPlayQueueRead = 0;
724:
725:
726:
727:
728:
729:
730:
731:
732:
733: hcdReadThread = new Thread (() -> {
734: while (hcdRunning) {
735: if (hcdCompleted != hcdRequested) {
736: hcdCommandComplete_2nd ();
737: hcdCompleted = hcdRequested;
738: } else if (hcdHandle == null ||
739: !hcdPlaying ||
740: hcdPausing ||
741: hcdEndSector <= hcdCurrentSector ||
742: (hcdPlayQueueWrite - hcdPlayQueueRead) == HCD_PLAY_QUEUE_SIZE) {
743: try {
744: Thread.sleep ((long) (HCD_PLAY_MILLIS / 2));
745: } catch (InterruptedException ie) {
746: }
747: } else {
748:
749: byte[] buffer = hcdPlayQueueArray[hcdPlayQueueWrite & (HCD_PLAY_QUEUE_SIZE - 1)];
750: int sectors = Math.min (HCD_PLAY_SECTORS, hcdEndSector - hcdCurrentSector);
751: hcdReadInfo.set (ValueLayout.JAVA_LONG,
752: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("DiskOffset")),
753: 2048L * (long) hcdCurrentSector);
754: hcdReadInfo.set (ValueLayout.JAVA_INT,
755: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("SectorCount")),
756: sectors);
757: hcdReadInfo.set (ValueLayout.JAVA_INT,
758: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("TrackMode")),
759: CDDA);
760: try {
761: int error;
762: if ((int) DeviceIoControl.invoke (
763: hcdHandle,
764: IOCTL_CDROM_RAW_READ,
765: hcdReadInfo,
766: (int) hcdReadInfo.byteSize (),
767: hcdBufferSegment,
768: 2352 * sectors,
769: hcdBytesReturned,
770: MemorySegment.NULL) == 0 &&
771: (error = (int) GetLastError.invoke ()) != -1) {
772: if (hcdDebugInfo) {
773: System.out.printf ("DeviceIoControl IOCTL_CDROM_RAW_READ returned error %d\n",
774: error);
775: }
776: hcdPlaying = false;
777: hcdAudioStatus = 0x14;
778: Arrays.fill (buffer, (byte) 0);
779: }
780: } catch (Throwable e) {
781: if (hcdDebugInfo) {
782: e.printStackTrace ();
783: }
784: hcdPlaying = false;
785: hcdAudioStatus = 0x14;
786: Arrays.fill (buffer, (byte) 0);
787: }
788:
789: for (int i = 0; i < 588 * sectors; i++) {
790:
791:
792: int l = ((int) hcdBufferSegment.get (ValueLayout.JAVA_BYTE, 4 * i + 1) << 8 |
793: (0xff & (int) hcdBufferSegment.get (ValueLayout.JAVA_BYTE, 4 * i + 0)));
794: int r = ((int) hcdBufferSegment.get (ValueLayout.JAVA_BYTE, 4 * i + 3) << 8 |
795: (0xff & (int) hcdBufferSegment.get (ValueLayout.JAVA_BYTE, 4 * i + 2)));
796: l = Math.max (-32768, Math.min (32767, Math.round ((float) l * hcdVolumeFloat)));
797: r = Math.max (-32768, Math.min (32767, Math.round ((float) r * hcdVolumeFloat)));
798: buffer[4 * i + 0] = (byte) l;
799: buffer[4 * i + 1] = (byte) (l >> 8);
800: buffer[4 * i + 2] = (byte) r;
801: buffer[4 * i + 3] = (byte) (r >> 8);
802: }
803: if (sectors < HCD_PLAY_SECTORS) {
804: Arrays.fill (buffer,
805: 2352 * sectors,
806: HCD_PLAY_BYTES,
807: (byte) 0);
808: }
809: hcdCurrentSector += sectors;
810: hcdPlayQueueWrite++;
811: }
812: }
813: });
814: hcdReadThread.start ();
815:
816:
817:
818:
819:
820:
821:
822:
823:
824:
825:
826:
827:
828: hcdPlayThread = new Thread (() -> {
829: while (hcdRunning) {
830: if (!hcdPlaying ||
831: hcdPausing ||
832: (((hcdCurrentSector - hcdStartSector) < HCD_PLAY_SECTORS * HCD_PLAY_QUEUE_SIZE * 2) &&
833: hcdPlayQueueRead == hcdPlayQueueWrite)) {
834: try {
835: Thread.sleep ((long) (HCD_PLAY_MILLIS / 2));
836: } catch (InterruptedException ie) {
837: }
838: } else if (hcdPlayQueueRead == hcdPlayQueueWrite) {
839: hcdPlaying = false;
840: hcdAudioStatus = 0x14;
841: } else if (hcdSourceDataLine == null) {
842:
843: hcdPlayQueueRead++;
844: try {
845: Thread.sleep ((long) (HCD_PLAY_MILLIS));
846: } catch (InterruptedException ie) {
847: }
848: } else {
849:
850: hcdSourceDataLine.write (hcdPlayQueueArray[hcdPlayQueueRead & (HCD_PLAY_QUEUE_SIZE - 1)], 0, HCD_PLAY_BYTES);
851: hcdPlayQueueRead++;
852: if (hcdEndSector <= hcdCurrentSector) {
853: hcdPlaying = false;
854: hcdAudioStatus = 0x13;
855: }
856: }
857: }
858: });
859: hcdPlayThread.start ();
860:
861: }
862:
863:
864:
865: public static void hcdTini () {
866:
867:
868: hcdRunning = false;
869:
870:
871: if (hcdReadThread != null) {
872: hcdReadThread.interrupt ();
873: try {
874: hcdReadThread.join ((long) (HCD_PLAY_MILLIS * 2));
875: } catch (InterruptedException ie) {
876: }
877: hcdReadThread = null;
878: }
879:
880:
881: if (hcdPlayThread != null) {
882: hcdPlayThread.interrupt ();
883: try {
884: hcdPlayThread.join ((long) (HCD_PLAY_MILLIS * 2));
885: } catch (InterruptedException ie) {
886: }
887: hcdPlayThread = null;
888: }
889:
890:
891: if (hcdSourceDataLine != null) {
892: hcdSourceDataLine.stop ();
893: hcdSourceDataLine.close ();
894: hcdSourceDataLine = null;
895: }
896:
897:
898: Settings.sgsPutOnOff ("hcddebug", hcdDebugInfo);
899: Settings.sgsPutOnOff ("hcdconnect", hcdConnectNext);
900: Settings.sgsPutInt ("hcdscsiid", hcdSCSIIdNext);
901: Settings.sgsPutInt ("hcdvolume", hcdVolumeInt);
902:
903: }
904:
905:
906:
907: public static void hcdReset () {
908: if (hcdConnected) {
909: hcdRequested = 0;
910: hcdCompleted = 0;
911: hcdRetrieved = 0;
912: hcdTOCAddressArray = null;
913: hcdDataOffset = -1;
914: hcdUnit = null;
915: hcdChip = null;
916: hcdResultBuffer = null;
917: hcdResultLength = 0;
918: hcdResultSense0 = 0;
919: hcdResultSense2 = 0;
920: hcdResultStatus = SPC.SPC_GOOD;
921: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
922: hcdBytesPerSector = 2048;
923: hcdPlaying = false;
924: hcdPausing = false;
925: hcdAudioStatus = 0x15;
926: }
927: }
928:
929:
930:
931: static boolean hcdOpen () {
932: if (hcdHandle != null) {
933: return true;
934: }
935: if (hcdRootPath == null) {
936: return false;
937: }
938: try {
939: int error;
940:
941: MemorySegment sectorsPerCluster = arena.allocate (ValueLayout.JAVA_INT);
942: MemorySegment bytesPerSector = arena.allocate (ValueLayout.JAVA_INT);
943: MemorySegment numberOfFreeClusters = arena.allocate (ValueLayout.JAVA_INT);
944: MemorySegment totalNumberOfClusters = arena.allocate (ValueLayout.JAVA_INT);
945: if ((int) GetDiskFreeSpaceA.invoke (
946: arena.allocateFrom (hcdRootPath),
947: sectorsPerCluster,
948: bytesPerSector,
949: numberOfFreeClusters,
950: totalNumberOfClusters) == 0 &&
951: (error = (int) GetLastError.invoke ()) != -1) {
952: if (hcdDebugInfo) {
953: System.out.printf ("GetDiskFreeSpaceA returned error %d\n",
954: error);
955: }
956: return false;
957: }
958: if (hcdDebugInfo) {
959: System.out.printf ("sectorsPerCluster=%d\n",
960: sectorsPerCluster.get (ValueLayout.JAVA_INT, 0));
961: System.out.printf ("bytesPerSector=%d\n",
962: bytesPerSector.get (ValueLayout.JAVA_INT, 0));
963: System.out.printf ("numberOfFreeClusters=%d\n",
964: numberOfFreeClusters.get (ValueLayout.JAVA_INT, 0));
965: System.out.printf ("totalNumberOfClusters=%d\n",
966: totalNumberOfClusters.get (ValueLayout.JAVA_INT, 0));
967: }
968:
969: if ((hcdHandle = (MemorySegment) CreateFileA.invoke (
970: arena.allocateFrom (hcdDevicePath),
971: GENERIC_READ,
972: FILE_SHARE_READ | FILE_SHARE_WRITE,
973: MemorySegment.NULL,
974: OPEN_EXISTING,
975: 0,
976: MemorySegment.NULL)).address () == INVALID_HANDLE_VALUE &&
977: (error = (int) GetLastError.invoke ()) != -1) {
978: if (hcdDebugInfo) {
979: System.out.printf ("CreateFileA returned error %d\n",
980: error);
981: }
982: hcdHandle = null;
983: return false;
984: }
985: } catch (Throwable e) {
986: if (hcdDebugInfo) {
987: e.printStackTrace ();
988: }
989: hcdHandle = null;
990: return false;
991: }
992: return true;
993: }
994:
995:
996:
997: static void hcdClose () {
998: if (hcdHandle == null) {
999: return;
1000: }
1001: try {
1002: CloseHandle.invoke (hcdHandle);
1003: } catch (Throwable e) {
1004: if (hcdDebugInfo) {
1005: e.printStackTrace ();
1006: }
1007: }
1008: hcdHandle = null;
1009: hcdTOCAddressArray = null;
1010: hcdDataOffset = -1;
1011: }
1012:
1013:
1014:
1015: static byte[] hcdReadTOC (boolean msf) {
1016: if (!hcdOpen ()) {
1017: return null;
1018: }
1019: try {
1020: int error;
1021: hcdReadTocEx.set (ValueLayout.JAVA_BYTE,
1022: CDROM_READ_TOC_EX.byteOffset (MemoryLayout.PathElement.groupElement ("Msf_Reserved1_Format")),
1023: (byte) ((msf ? 1 : 0) << 7 |
1024: 0 << 4 |
1025: CDROM_READ_TOC_EX_FORMAT_TOC));
1026: hcdReadTocEx.set (ValueLayout.JAVA_BYTE,
1027: CDROM_READ_TOC_EX.byteOffset (MemoryLayout.PathElement.groupElement ("SessionTrack")),
1028: (byte) 1);
1029: hcdReadTocEx.set (ValueLayout.JAVA_BYTE,
1030: CDROM_READ_TOC_EX.byteOffset (MemoryLayout.PathElement.groupElement ("Reserved2")),
1031: (byte) 0);
1032: hcdReadTocEx.set (ValueLayout.JAVA_BYTE,
1033: CDROM_READ_TOC_EX.byteOffset (MemoryLayout.PathElement.groupElement ("Reserved3")),
1034: (byte) 0);
1035: if ((int) DeviceIoControl.invoke (
1036: hcdHandle,
1037: IOCTL_CDROM_READ_TOC_EX,
1038: hcdReadTocEx,
1039: (int) hcdReadTocEx.byteSize (),
1040: hcdToc,
1041: (int) hcdToc.byteSize (),
1042: hcdBytesReturned,
1043: MemorySegment.NULL) == 0 &&
1044: (error = (int) GetLastError.invoke ()) != -1) {
1045: if (hcdDebugInfo) {
1046: System.out.printf ("DeviceIoControl IOCTL_CDROM_READ_TOC_EX returned error %d\n",
1047: error);
1048: }
1049: hcdClose ();
1050: return (error == 0 ||
1051: error == ERROR_NOT_READY ||
1052: error == ERROR_WRONG_DISK ? null :
1053: new byte[0]);
1054: }
1055: int Length_0 = (0xff & (int) (hcdToc.get (ValueLayout.JAVA_BYTE,
1056: CDROM_TOC.byteOffset (MemoryLayout.PathElement.groupElement ("Length"),
1057: MemoryLayout.PathElement.sequenceElement (0)))));
1058: int Length_1 = (0xff & (int) (hcdToc.get (ValueLayout.JAVA_BYTE,
1059: CDROM_TOC.byteOffset (MemoryLayout.PathElement.groupElement ("Length"),
1060: MemoryLayout.PathElement.sequenceElement (1)))));
1061: int Length = 256 * Length_0 + Length_1;
1062: byte[] buffer = new byte[2 + Length];
1063: for (int i = 0; i < buffer.length; i++) {
1064: buffer[i] = hcdToc.get (ValueLayout.JAVA_BYTE, (long) i);
1065: }
1066: if (false) {
1067: for (int i = 0; i < buffer.length; i++) {
1068: System.out.printf ("%02x ", 0xff & buffer[i]);
1069: }
1070: System.out.println ();
1071: }
1072: return buffer;
1073: } catch (Throwable e) {
1074: if (hcdDebugInfo) {
1075: e.printStackTrace ();
1076: }
1077: return null;
1078: }
1079: }
1080:
1081:
1082:
1083: static void hcdPlay (int startSector, int endSector) {
1084: if (!hcdPlaying) {
1085: if (!hcdOpen ()) {
1086: return;
1087: }
1088: }
1089:
1090:
1091: hcdPlayQueueRead = hcdPlayQueueWrite;
1092: hcdStartSector = startSector;
1093: hcdCurrentSector = startSector;
1094: hcdEndSector = endSector;
1095: hcdPlaying = true;
1096: hcdPausing = false;
1097: hcdAudioStatus = 0x11;
1098: }
1099:
1100:
1101:
1102: static void hcdPause () {
1103: if (!hcdPlaying) {
1104: return;
1105: }
1106: hcdPausing = true;
1107: hcdAudioStatus = 0x12;
1108: }
1109:
1110:
1111:
1112: static void hcdResume () {
1113: if (!hcdPlaying) {
1114: return;
1115: }
1116: hcdStartSector = hcdCurrentSector;
1117: hcdPausing = false;
1118: hcdAudioStatus = 0x11;
1119: }
1120:
1121:
1122:
1123: static void hcdSetBytesPerSector (int bytesPerSector) {
1124: if (bytesPerSector == 2048 ||
1125: bytesPerSector == 2336 ||
1126: bytesPerSector == 2352) {
1127: hcdBytesPerSector = bytesPerSector;
1128: if (hcdDebugInfo) {
1129: System.out.printf ("bytesPerSector=%d\n", bytesPerSector);
1130: }
1131: }
1132: }
1133:
1134:
1135:
1136: static byte[] hcdRead (int startSector, int sectors) {
1137: if (hcdDebugInfo) {
1138: System.out.printf ("hcdRead(%d,%d)\n", startSector, sectors);
1139: }
1140: if (!hcdOpen ()) {
1141: return null;
1142: }
1143: byte[] buffer = new byte[hcdBytesPerSector * sectors];
1144: try {
1145: int error;
1146: if (hcdBytesPerSector == 2048) {
1147: if ((int) SetFilePointerEx.invoke (
1148: hcdHandle,
1149: 2048L * (long) startSector,
1150: MemorySegment.NULL,
1151: FILE_BEGIN) == 0 &&
1152: (error = (int) GetLastError.invoke ()) != -1) {
1153: if (hcdDebugInfo) {
1154: System.out.printf ("SetFilePointerEx returned error %d\n",
1155: error);
1156: }
1157: hcdClose ();
1158: return (error == 0 ||
1159: error == ERROR_NOT_READY ||
1160: error == ERROR_WRONG_DISK ? null :
1161: new byte[0]);
1162: }
1163: }
1164: for (int offset = 0; offset < sectors; ) {
1165: int step = Math.min (HCD_PLAY_SECTORS, sectors - offset);
1166: if (hcdBytesPerSector == 2048) {
1167: if ((int) ReadFile.invoke (
1168: hcdHandle,
1169: hcdBufferSegment,
1170: 2048 * step,
1171: hcdBytesReturned,
1172: MemorySegment.NULL) == 0 &&
1173: (error = (int) GetLastError.invoke ()) != -1) {
1174: if (hcdDebugInfo) {
1175: System.out.printf ("ReadFile returned error %d\n",
1176: error);
1177: }
1178: hcdClose ();
1179: return (error == 0 ||
1180: error == ERROR_NOT_READY ||
1181: error == ERROR_WRONG_DISK ? null :
1182: new byte[0]);
1183: }
1184: } else {
1185: hcdReadInfo.set (ValueLayout.JAVA_LONG,
1186: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("DiskOffset")),
1187: 2048L * (long) (startSector + offset));
1188: hcdReadInfo.set (ValueLayout.JAVA_INT,
1189: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("SectorCount")),
1190: step);
1191: hcdReadInfo.set (ValueLayout.JAVA_INT,
1192: RAW_READ_INFO.byteOffset (MemoryLayout.PathElement.groupElement ("TrackMode")),
1193: hcdBytesPerSector == 2336 ? YellowMode2 : CDDA);
1194: if ((int) DeviceIoControl.invoke (
1195: hcdHandle,
1196: IOCTL_CDROM_RAW_READ,
1197: hcdReadInfo,
1198: (int) hcdReadInfo.byteSize (),
1199: hcdBufferSegment,
1200: hcdBytesPerSector * step,
1201: hcdBytesReturned,
1202: MemorySegment.NULL) == 0 &&
1203: (error = (int) GetLastError.invoke ()) != -1) {
1204: if (hcdDebugInfo) {
1205: System.out.printf ("DeviceIoControl IOCTL_CDROM_RAW_READ returned error %d\n",
1206: error);
1207: }
1208: hcdClose ();
1209: return (error == 0 ||
1210: error == ERROR_NOT_READY ||
1211: error == ERROR_WRONG_DISK ? null :
1212: new byte[0]);
1213: }
1214: }
1215: for (int i = 0; i < hcdBytesPerSector * step; i++) {
1216: buffer[hcdBytesPerSector * offset + i] = hcdBufferSegment.get (ValueLayout.JAVA_BYTE, i);
1217: }
1218: offset += step;
1219: }
1220: return buffer;
1221: } catch (Throwable e) {
1222: if (hcdDebugInfo) {
1223: e.printStackTrace ();
1224: }
1225: return null;
1226: }
1227: }
1228:
1229:
1230: static byte[] hcdReadCapacity () {
1231: if (!hcdOpen ()) {
1232: return null;
1233: }
1234: try {
1235: int error;
1236: MemorySegment sectorsPerCluster = arena.allocate (ValueLayout.JAVA_INT);
1237: MemorySegment bytesPerSector = arena.allocate (ValueLayout.JAVA_INT);
1238: MemorySegment numberOfFreeClusters = arena.allocate (ValueLayout.JAVA_INT);
1239: MemorySegment totalNumberOfClusters = arena.allocate (ValueLayout.JAVA_INT);
1240: if ((int) GetDiskFreeSpaceA.invoke (
1241: arena.allocateFrom (hcdRootPath),
1242: sectorsPerCluster,
1243: bytesPerSector,
1244: numberOfFreeClusters,
1245: totalNumberOfClusters) == 0 &&
1246: (error = (int) GetLastError.invoke ()) != -1) {
1247: if (hcdDebugInfo) {
1248: System.out.printf ("GetDiskFreeSpaceA returned error %d\n",
1249: error);
1250: }
1251: hcdClose ();
1252: return (error == 0 ||
1253: error == ERROR_NOT_READY ||
1254: error == ERROR_WRONG_DISK ? null :
1255: new byte[0]);
1256: }
1257: byte[] buffer = new byte[8];
1258: ByteArray.byaWl (buffer,
1259: 0,
1260: sectorsPerCluster.get (ValueLayout.JAVA_INT, 0) *
1261: totalNumberOfClusters.get (ValueLayout.JAVA_INT, 0) - 1);
1262: ByteArray.byaWl (buffer,
1263: 4,
1264: bytesPerSector.get (ValueLayout.JAVA_INT, 0));
1265: return buffer;
1266: } catch (Throwable e) {
1267: if (hcdDebugInfo) {
1268: e.printStackTrace ();
1269: }
1270: return null;
1271: }
1272: }
1273:
1274:
1275:
1276:
1277: static void hcdEject () {
1278: hcdClose ();
1279: try {
1280: int error;
1281: MemorySegment handle;
1282: if ((handle = (MemorySegment) CreateFileA.invoke (
1283: arena.allocateFrom (hcdDevicePath),
1284: 0,
1285: FILE_SHARE_READ | FILE_SHARE_WRITE,
1286: MemorySegment.NULL,
1287: OPEN_EXISTING,
1288: 0,
1289: MemorySegment.NULL)).address () == INVALID_HANDLE_VALUE &&
1290: (error = (int) GetLastError.invoke ()) != -1) {
1291: if (hcdDebugInfo) {
1292: System.out.printf ("CreateFileA returned error %d\n",
1293: error);
1294: }
1295: return;
1296: }
1297: MemorySegment bytesReturned = arena.allocate (ValueLayout.JAVA_INT);
1298: if ((int) DeviceIoControl.invoke (
1299: handle,
1300: IOCTL_STORAGE_EJECT_MEDIA,
1301: MemorySegment.NULL,
1302: 0,
1303: MemorySegment.NULL,
1304: 0,
1305: bytesReturned,
1306: MemorySegment.NULL) == 0 &&
1307: (error = (int) GetLastError.invoke ()) != -1) {
1308: if (hcdDebugInfo) {
1309: System.out.printf ("DeviceIoControl IOCTL_STORAGE_EJECT_MEDIA returned error %d\n",
1310: error);
1311: }
1312: }
1313: CloseHandle.invoke (handle);
1314: } catch (Throwable e) {
1315: if (hcdDebugInfo) {
1316: e.printStackTrace ();
1317: }
1318: }
1319: }
1320:
1321:
1322:
1323:
1324: public static void hcdCommandComplete_1st (SPC.SCUnit unit, int oc) {
1325: if (hcdDebugInfo) {
1326: unit.scuPrintCommand (oc);
1327: }
1328: hcdUnit = unit;
1329: hcdChip = unit.scuChip;
1330: hcdResultBuffer = null;
1331: hcdResultLength = 0;
1332: hcdResultSense0 = 0;
1333: hcdResultSense2 = 0;
1334: hcdResultStatus = SPC.SPC_GOOD;
1335: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
1336: if (!(oc == 0x03 ||
1337: oc == 0x12) &&
1338: hcdChip.spiLUN != 0) {
1339: unit.scuNotReady ();
1340: return;
1341: }
1342: switch (oc) {
1343:
1344:
1345:
1346: case 0x01:
1347: hcdDoRezeroUnit_1st ();
1348: break;
1349: case 0x03:
1350: unit.scuDoRequestSense ();
1351: break;
1352: case 0x12:
1353: hcdDoInquiry_1st ();
1354: break;
1355: case 0x1a:
1356: hcdDoModeSense6_1st ();
1357: break;
1358: case 0x42:
1359: hcdDoReadSubChannel_1st ();
1360: break;
1361: case 0x45:
1362: hcdDoPlayAudio10_1st ();
1363: break;
1364: case 0x47:
1365: hcdDoPlayAudioMSF_1st ();
1366: break;
1367: case 0x4b:
1368: hcdDoPauseResume_1st ();
1369: break;
1370: case 0xa5:
1371: hcdDoPlayAudio12_1st ();
1372: break;
1373:
1374:
1375:
1376: case 0x15:
1377: hcdDoModeSelect6_1st ();
1378: break;
1379:
1380:
1381:
1382: case 0x00:
1383: case 0x08:
1384: case 0x1b:
1385: case 0x25:
1386: case 0x28:
1387: case 0x43:
1388: case 0xd8:
1389: hcdRequested++;
1390: if (hcdReadThread != null) {
1391: hcdReadThread.interrupt ();
1392: }
1393: break;
1394:
1395:
1396:
1397: default:
1398: hcdUnit.scuDoInvalid ();
1399: }
1400: }
1401:
1402:
1403:
1404:
1405: static void hcdCommandComplete_2nd () {
1406: int oc = hcdChip.spiCommandBuffer[0] & 255;
1407: switch (oc) {
1408:
1409:
1410:
1411: case 0x00:
1412: hcdDoTestUnitReady_2nd ();
1413: break;
1414: case 0x08:
1415: hcdDoRead6_2nd ();
1416: break;
1417: case 0x1b:
1418: hcdDoStartStopUnit_2nd ();
1419: break;
1420: case 0x25:
1421: hcdDoReadCapacity_2nd ();
1422: break;
1423: case 0x28:
1424: hcdDoRead10_2nd ();
1425: break;
1426: case 0x43:
1427: hcdDoReadTOC_2nd ();
1428: break;
1429: case 0xd8:
1430: hcdDoReadCDDA_2nd ();
1431: break;
1432: }
1433: }
1434:
1435:
1436:
1437:
1438:
1439:
1440: static void hcdDoTestUnitReady_2nd () {
1441: if (!hcdOpen ()) {
1442: hcdNotReady ();
1443: return;
1444: }
1445: try {
1446: int error;
1447: MemorySegment bytesReturned = arena.allocate (ValueLayout.JAVA_INT);
1448: if ((int) DeviceIoControl.invoke (
1449: hcdHandle,
1450: IOCTL_STORAGE_CHECK_VERIFY,
1451: MemorySegment.NULL,
1452: 0,
1453: MemorySegment.NULL,
1454: 0,
1455: bytesReturned,
1456: MemorySegment.NULL) == 0 &&
1457: (error = (int) GetLastError.invoke ()) != -1) {
1458: if (hcdDebugInfo) {
1459: System.out.printf ("DeviceIoControl IOCTL_STORAGE_CHECK_VERIFY returned error %d\n",
1460: error);
1461: }
1462: hcdNotReady ();
1463: return;
1464: }
1465: } catch (Throwable e) {
1466: if (hcdDebugInfo) {
1467: e.printStackTrace ();
1468: }
1469: hcdNotReady ();
1470: return;
1471: }
1472: hcdGood ();
1473: }
1474:
1475:
1476:
1477:
1478:
1479: static void hcdDoRezeroUnit_1st () {
1480: hcdRequested = 0;
1481: hcdCompleted = 0;
1482: hcdRetrieved = 0;
1483: hcdBytesPerSector = 2048;
1484:
1485: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
1486: }
1487:
1488:
1489:
1490:
1491:
1492:
1493: static void hcdDoRead6_2nd () {
1494: if (!hcdOpen ()) {
1495: hcdNotReady ();
1496: return;
1497: }
1498: int a = ByteArray.byaRls (hcdChip.spiCommandBuffer, 0) & 0x001fffff;
1499: int n = hcdChip.spiCommandBuffer[4] & 255;
1500: if (n == 0) {
1501: n = 256;
1502: }
1503: byte[] buffer = hcdRead (a, n);
1504: if (buffer == null) {
1505: hcdNotReady ();
1506: return;
1507: }
1508: if (buffer.length == 0) {
1509: hcdMediumError ();
1510: return;
1511: }
1512:
1513: hcdResultBuffer = buffer;
1514: hcdResultLength = buffer.length;
1515: }
1516:
1517:
1518:
1519:
1520:
1521:
1522:
1523: static void hcdDoInquiry_1st () {
1524: boolean evpd = (hcdChip.spiCommandBuffer[1] & 1) != 0;
1525: if (evpd) {
1526: hcdUnit.scuIllegalRequest ();
1527: return;
1528: }
1529: int n = hcdChip.spiCommandBuffer[4] & 255;
1530: byte[] buffer = new byte[36];
1531: if (hcdChip.spiLUN != 0) {
1532: buffer[0] = 0x7f;
1533: } else {
1534: buffer[0] = (byte) (SPC.SPC_CDROM_DEVICE);
1535: buffer[1] = (byte) (1 << 7);
1536: buffer[2] = 2;
1537: buffer[3] = 1;
1538: buffer[4] = 31;
1539: buffer[5] = 0;
1540: buffer[6] = 0;
1541: buffer[7] = 0;
1542: System.arraycopy (hcdVendorProduct, 0,
1543: buffer, 8,
1544: 8 + 16 + 4);
1545: }
1546: if (hcdDebugInfo) {
1547: hcdDumpBuffer (buffer, buffer.length);
1548: }
1549: hcdChip.spiDataInPhase (buffer, 0, Math.min (n, buffer.length), 0);
1550: }
1551:
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559:
1560:
1561:
1562:
1563:
1564:
1565:
1566:
1567:
1568:
1569:
1570:
1571:
1572:
1573:
1574:
1575:
1576:
1577:
1578:
1579:
1580: static void hcdDoModeSelect6_1st () {
1581: int n = hcdChip.spiCommandBuffer[4] & 255;
1582: hcdChip.spiDataOutPhase (hcdChip.spiDataOutBuffer, 0, n, 0);
1583: }
1584:
1585:
1586:
1587:
1588:
1589:
1590:
1591: static void hcdDoModeSense6_1st () {
1592: boolean dbd = (hcdChip.spiCommandBuffer[1] & 8) != 0;
1593: int pc = (hcdChip.spiCommandBuffer[2] >> 6) & 3;
1594: if (pc == 3) {
1595: hcdUnit.scuIllegalRequest ();
1596: return;
1597: }
1598: int pageCode = hcdChip.spiCommandBuffer[2] & 63;
1599: int n = hcdChip.spiCommandBuffer[4] & 255;
1600:
1601:
1602:
1603:
1604:
1605:
1606:
1607:
1608:
1609:
1610:
1611:
1612:
1613:
1614:
1615:
1616:
1617: if (pageCode != 0x01 &&
1618: pageCode != 0x03 &&
1619: pageCode != 0x0e &&
1620: pageCode != 0x31 &&
1621: pageCode != 0x3f) {
1622: hcdUnit.scuIllegalRequest ();
1623: return;
1624: }
1625: byte[] buffer = new byte[256];
1626:
1627: buffer[0] = 3;
1628: buffer[1] = 0x00;
1629: buffer[2] = 0x00;
1630: buffer[3] = 0;
1631: int length = 4;
1632: if (!dbd) {
1633:
1634: if (pc == 0) {
1635: buffer[length + 6] = (byte) (hcdBytesPerSector >> 8);
1636: buffer[length + 7] = (byte) hcdBytesPerSector;
1637: } else if (pc == 1) {
1638: buffer[length + 6] = -1;
1639: buffer[length + 7] = -1;
1640: } else {
1641: buffer[length + 6] = (byte) (2048 >> 8);
1642: buffer[length + 7] = (byte) 2048;
1643: }
1644: buffer[0] += 8;
1645: buffer[3] += 8;
1646: length += 8;
1647: }
1648: if (pageCode == 0x01 ||
1649: pageCode == 0x3f) {
1650:
1651: buffer[length + 0] = 0x01;
1652: buffer[length + 1] = 6;
1653: if (pc == 0) {
1654: buffer[length + 2] = 0x11;
1655: buffer[length + 3] = 0x00;
1656: } else if (pc == 1) {
1657: buffer[length + 2] = 0;
1658: buffer[length + 3] = 0;
1659: } else {
1660: buffer[length + 2] = 0x11;
1661: buffer[length + 3] = 0x00;
1662: }
1663: buffer[0] += 8;
1664: length += 8;
1665: }
1666: if (pageCode == 0x03 ||
1667: pageCode == 0x3f) {
1668: buffer[length + 0] = 0x03;
1669: buffer[length + 1] = 22;
1670: if (pc == 0) {
1671: buffer[length + 20] = 0x20;
1672: } else if (pc == 1) {
1673: buffer[length + 20] = 0;
1674: } else {
1675: buffer[length + 20] = 0x20;
1676: }
1677: buffer[0] += 24;
1678: length += 24;
1679: }
1680: if (pageCode == 0x0e ||
1681: pageCode == 0x3f) {
1682: buffer[length + 0] = 0x0e;
1683: buffer[length + 1] = 14;
1684: if (pc == 0) {
1685: buffer[length + 9] =
1686: buffer[length + 11] =
1687: buffer[length + 13] =
1688: buffer[length + 15] = (byte) (hcdVolumeInt * 255 / 100);
1689: } else if (pc == 1) {
1690: buffer[length + 9] =
1691: buffer[length + 11] =
1692: buffer[length + 13] =
1693: buffer[length + 15] = -1;
1694: } else {
1695: buffer[length + 9] =
1696: buffer[length + 11] =
1697: buffer[length + 13] =
1698: buffer[length + 15] = (byte) (HCD_DEFAULT_VOLUME * 255 / 100);
1699: }
1700: length += 16;
1701: }
1702: if (pageCode == 0x31 ||
1703: pageCode == 0x3f) {
1704: buffer[length + 0] = 0x31;
1705: buffer[length + 1] = 2;
1706: if (pc == 0) {
1707: buffer[length + 2] = 24;
1708: } else if (pc == 1) {
1709: buffer[length + 2] = 0;
1710: } else {
1711: buffer[length + 2] = 24;
1712: }
1713: buffer[0] += 4;
1714: length += 4;
1715: }
1716: if (hcdDebugInfo) {
1717: hcdDumpBuffer (buffer, length);
1718: }
1719: hcdChip.spiDataInPhase (buffer, 0, Math.min (n, length), 0);
1720: }
1721:
1722:
1723:
1724:
1725:
1726:
1727: static void hcdDoStartStopUnit_2nd () {
1728: int loejStart = hcdChip.spiCommandBuffer[4] & 3;
1729: if (loejStart == 2) {
1730:
1731: hcdEject ();
1732: }
1733: hcdGood ();
1734: }
1735:
1736:
1737:
1738:
1739:
1740:
1741:
1742: static void hcdDoReadCapacity_2nd () {
1743: if (!hcdOpen ()) {
1744: hcdNotReady ();
1745: return;
1746: }
1747: byte[] buffer = hcdReadCapacity ();
1748: if (buffer == null) {
1749: hcdNotReady ();
1750: return;
1751: }
1752: if (buffer.length == 0) {
1753: hcdMediumError ();
1754: return;
1755: }
1756:
1757: hcdResultBuffer = buffer;
1758: hcdResultLength = buffer.length;
1759: }
1760:
1761:
1762:
1763:
1764:
1765:
1766:
1767: static void hcdDoRead10_2nd () {
1768: if (!hcdOpen ()) {
1769: hcdNotReady ();
1770: return;
1771: }
1772: int a = ByteArray.byaRls (hcdChip.spiCommandBuffer, 2);
1773: int n = ByteArray.byaRwz (hcdChip.spiCommandBuffer, 7);
1774: if (n == 0) {
1775: hcdGood ();
1776: return;
1777: }
1778: byte[] buffer = hcdRead (a, n);
1779: if (buffer == null) {
1780: hcdNotReady ();
1781: return;
1782: }
1783: if (buffer.length == 0) {
1784: hcdMediumError ();
1785: return;
1786: }
1787:
1788: hcdResultBuffer = buffer;
1789: hcdResultLength = buffer.length;
1790: }
1791:
1792:
1793:
1794:
1795:
1796:
1797:
1798:
1799:
1800: static void hcdDoReadSubChannel_1st () {
1801: boolean msf = (hcdChip.spiCommandBuffer[1] & 2) != 0;
1802: boolean subQ = (hcdChip.spiCommandBuffer[2] & 64) != 0;
1803: int type = hcdChip.spiCommandBuffer[3] & 255;
1804: int n = ByteArray.byaRwz (hcdChip.spiCommandBuffer, 7);
1805: if (subQ &&
1806: type == 0x01) {
1807: int currentSector = 0;
1808: int currentTrack = hcdTOCFirstTrack;
1809: int currentOffset = 0;
1810: if (hcdPlaying &&
1811: hcdTOCAddressArray != null) {
1812: currentSector = hcdCurrentSector;
1813: while (currentTrack + 1 <= hcdTOCLastTrack &&
1814: hcdTOCAddressArray[currentTrack + 1 - hcdTOCFirstTrack] <= currentSector) {
1815: currentTrack++;
1816: }
1817: currentOffset = currentSector - hcdTOCAddressArray[currentTrack - hcdTOCFirstTrack];
1818: }
1819:
1820: byte[] buffer = new byte[16];
1821: buffer[1] = (byte) hcdAudioStatus;
1822: if (hcdAudioStatus == 0x13 ||
1823: hcdAudioStatus == 0x14) {
1824: hcdAudioStatus = 0x15;
1825: }
1826: buffer[2] = 0;
1827: buffer[3] = 12;
1828: buffer[3] = 0x01;
1829: buffer[5] = 0x10;
1830: buffer[6] = (byte) ((currentTrack / 10) << 4 |
1831: (currentTrack % 10));
1832: buffer[7] = 0x01;
1833: if (msf) {
1834: int t = currentSector + 75 * 2;
1835: buffer[8] = 0;
1836: buffer[9] = (byte) (t / (75 * 60));
1837: buffer[10] = (byte) ((t / 75) % 60);
1838: buffer[11] = (byte) (t % 75);
1839: buffer[12] = 0;
1840: buffer[13] = (byte) (currentOffset / (75 * 60));
1841: buffer[14] = (byte) ((currentOffset / 75) % 60);
1842: buffer[15] = (byte) (currentOffset % 75);
1843: } else {
1844: buffer[8] = (byte) (currentSector >> 24);
1845: buffer[9] = (byte) (currentSector >> 16);
1846: buffer[10] = (byte) (currentSector >> 8);
1847: buffer[11] = (byte) currentSector;
1848: buffer[12] = (byte) (currentOffset >> 24);
1849: buffer[13] = (byte) (currentOffset >> 16);
1850: buffer[14] = (byte) (currentOffset >> 8);
1851: buffer[15] = (byte) currentOffset;
1852: }
1853: if (false) {
1854: System.out.printf ("currentSector=%d\n", currentSector);
1855: System.out.printf ("currentTrack=%d\n", currentTrack);
1856: System.out.printf ("currentOffset=%d\n", currentOffset);
1857: for (int i = 0; i < buffer.length; i++) {
1858: System.out.printf ("%02x ", buffer[i] & 255);
1859: }
1860: System.out.println ();
1861: }
1862: if (hcdDebugInfo) {
1863: hcdDumpBuffer (buffer, buffer.length);
1864: }
1865: hcdChip.spiDataInPhase (buffer, 0, Math.min (n, buffer.length), 0);
1866: } else {
1867: hcdIllegalRequest ();
1868: }
1869: }
1870:
1871:
1872:
1873:
1874:
1875:
1876:
1877: static void hcdDoReadTOC_2nd () {
1878: boolean msf = (hcdChip.spiCommandBuffer[1] & 2) != 0;
1879: int startTrack = hcdChip.spiCommandBuffer[6] & 255;
1880: if (startTrack == 0) {
1881: startTrack = 1;
1882: }
1883: if (0xaa < startTrack) {
1884: hcdIllegalRequest ();
1885: return;
1886: }
1887: int allocLength = ByteArray.byaRwz (hcdChip.spiCommandBuffer, 7);
1888: byte[] buffer = hcdReadTOC (msf);
1889: if (buffer == null) {
1890: hcdNotReady ();
1891: return;
1892: }
1893: if (buffer.length == 0) {
1894: hcdMediumError ();
1895: return;
1896: }
1897:
1898:
1899:
1900:
1901: hcdTOCAddressArray = new int[(buffer.length - 4) / 8];
1902: hcdTOCFirstTrack = buffer[2] & 255;
1903: hcdTOCLastTrack = buffer[3] & 255;
1904: for (int i = 0; i < hcdTOCAddressArray.length; i++) {
1905: hcdTOCAddressArray[i] = (msf ?
1906: -75 * 2 +
1907: (buffer[4 + 8 * i + 5] & 255) * (75 * 60) +
1908: (buffer[4 + 8 * i + 6] & 255) * 75 +
1909: (buffer[4 + 8 * i + 7] & 255) :
1910: (buffer[4 + 8 * i + 4] & 255) << 24 |
1911: (buffer[4 + 8 * i + 5] & 255) << 16 |
1912: (buffer[4 + 8 * i + 6] & 255) << 8 |
1913: (buffer[4 + 8 * i + 7] & 255));
1914: }
1915:
1916: int dataLength = buffer.length;
1917: int p = 4;
1918: while (p < dataLength - 8 &&
1919: (0xff & buffer[p + 2]) < startTrack) {
1920: p += 8;
1921: }
1922: if (4 < p) {
1923: for (int i = 0; i < dataLength - p; i++) {
1924: buffer[4 + i] = buffer[p + i];
1925: }
1926: dataLength -= p - 4;
1927: ByteArray.byaWw (buffer, 0, dataLength - 2);
1928: }
1929:
1930: hcdResultBuffer = buffer;
1931: hcdResultLength = Math.min (dataLength, allocLength);
1932: }
1933:
1934:
1935:
1936:
1937:
1938:
1939:
1940: static void hcdDoPlayAudio10_1st () {
1941: int start = ByteArray.byaRls (hcdChip.spiCommandBuffer, 2);
1942: int length = ByteArray.byaRwz (hcdChip.spiCommandBuffer, 7);
1943: hcdPlay (start, start + length);
1944: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
1945: }
1946:
1947:
1948:
1949:
1950:
1951:
1952:
1953:
1954:
1955:
1956:
1957: static void hcdDoPlayAudioMSF_1st () {
1958: int start = (-75 * 2 +
1959: (hcdChip.spiCommandBuffer[3] & 255) * (75 * 60) +
1960: (hcdChip.spiCommandBuffer[4] & 255) * 75 +
1961: (hcdChip.spiCommandBuffer[5] & 255));
1962: int end = (-75 * 2 +
1963: (hcdChip.spiCommandBuffer[6] & 255) * (75 * 60) +
1964: (hcdChip.spiCommandBuffer[7] & 255) * 75 +
1965: (hcdChip.spiCommandBuffer[8] & 255));
1966: hcdPlay (start, end);
1967: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
1968: }
1969:
1970:
1971:
1972:
1973:
1974:
1975: static void hcdDoPauseResume_1st () {
1976: boolean resume = (hcdChip.spiCommandBuffer[8] & 1) != 0;
1977: if (resume) {
1978: hcdResume ();
1979: } else {
1980: hcdPause ();
1981: }
1982: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
1983: }
1984:
1985:
1986:
1987:
1988:
1989:
1990:
1991: static void hcdDoPlayAudio12_1st () {
1992: int start = ByteArray.byaRls (hcdChip.spiCommandBuffer, 2);
1993: int length = ByteArray.byaRls (hcdChip.spiCommandBuffer, 6);
1994: hcdPlay (start, start + length);
1995: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
1996: }
1997:
1998:
1999:
2000:
2001:
2002:
2003: static void hcdDoReadCDDA_2nd () {
2004: if (!hcdOpen ()) {
2005: hcdNotReady ();
2006: return;
2007: }
2008: int a = ByteArray.byaRls (hcdChip.spiCommandBuffer, 2);
2009: int n = ByteArray.byaRwz (hcdChip.spiCommandBuffer, 8);
2010: if (n == 0) {
2011: hcdGood ();
2012: return;
2013: }
2014: byte[] buffer = hcdRead (a, n);
2015: if (buffer == null) {
2016: hcdNotReady ();
2017: return;
2018: }
2019: if (buffer.length == 0) {
2020: hcdMediumError ();
2021: return;
2022: }
2023:
2024: hcdResultBuffer = buffer;
2025: hcdResultLength = buffer.length;
2026: }
2027:
2028:
2029: static void hcdGood () {
2030: hcdResultSense0 = 0;
2031: hcdResultSense2 = 0;
2032: hcdResultStatus = SPC.SPC_GOOD;
2033: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2034: }
2035:
2036: static void hcdNotReady () {
2037: hcdResultSense0 = SPC.SPC_EXTENDED_SENSE;
2038: hcdResultSense2 = SPC.SPC_NOT_READY;
2039: hcdResultStatus = SPC.SPC_CHECK_CONDITION;
2040: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2041: }
2042:
2043: static void hcdUnitAttention () {
2044: hcdResultSense0 = SPC.SPC_EXTENDED_SENSE;
2045: hcdResultSense2 = SPC.SPC_UNIT_ATTENTION;
2046: hcdResultStatus = SPC.SPC_CHECK_CONDITION;
2047: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2048: }
2049:
2050: static void hcdDataProtect () {
2051: hcdResultSense0 = SPC.SPC_EXTENDED_SENSE;
2052: hcdResultSense2 = SPC.SPC_DATA_PROTECT;
2053: hcdResultStatus = SPC.SPC_CHECK_CONDITION;
2054: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2055: }
2056:
2057: static void hcdMediumError () {
2058: hcdResultSense0 = SPC.SPC_EXTENDED_SENSE;
2059: hcdResultSense2 = SPC.SPC_MEDIUM_ERROR;
2060: hcdResultStatus = SPC.SPC_CHECK_CONDITION;
2061: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2062: }
2063:
2064: static void hcdIllegalRequest () {
2065: hcdResultSense0 = SPC.SPC_EXTENDED_SENSE;
2066: hcdResultSense2 = SPC.SPC_ILLEGAL_REQUEST;
2067: hcdResultStatus = SPC.SPC_CHECK_CONDITION;
2068: hcdResultMessage = SPC.SPC_COMMAND_COMPLETE;
2069: }
2070:
2071:
2072:
2073:
2074: public static void hcdReadINTSPSNS () {
2075: if (hcdRetrieved != hcdCompleted) {
2076: if (hcdResultBuffer != null) {
2077: hcdChip.spiDataInPhase (hcdResultBuffer, 0, hcdResultLength, 0);
2078: } else {
2079: hcdChip.spiSenseBuffer[hcdChip.spiLUN][0] = (byte) hcdResultSense0;
2080: hcdChip.spiSenseBuffer[hcdChip.spiLUN][2] = (byte) hcdResultSense2;
2081: hcdChip.spiStatusPhase (hcdResultStatus, hcdResultMessage);
2082: }
2083: hcdChip.spiSetInterruptStatus (SPC.SPC_INTS_CC);
2084: hcdRetrieved = hcdCompleted;
2085: }
2086: }
2087:
2088:
2089:
2090:
2091: public static void hcdDataOutComplete (int oc) {
2092: switch (oc) {
2093: case 0x15:
2094: hcdDoModeSelect6_2nd ();
2095: break;
2096: default:
2097: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
2098: }
2099: }
2100:
2101:
2102: static void hcdDoModeSelect6_2nd () {
2103: int oc = hcdChip.spiCommandBuffer[0] & 255;
2104: if (hcdDebugInfo) {
2105: hcdUnit.scuPrintDataOut (oc);
2106: }
2107: int length = 4;
2108: if (length + 8 <= hcdChip.spiBufferLimit &&
2109: (hcdChip.spiDataOutBuffer[3] & 255) == 8) {
2110: hcdSetBytesPerSector ((hcdChip.spiDataOutBuffer[length + 6] & 255) << 8 |
2111: (hcdChip.spiDataOutBuffer[length + 7] & 255));
2112: length += 8;
2113: }
2114: while (length + 1 <= hcdChip.spiBufferLimit) {
2115: int pageCode = hcdChip.spiDataOutBuffer[length] & 63;
2116: if (length + 8 <= hcdChip.spiBufferLimit &&
2117: pageCode == 0x01) {
2118: length += 8;
2119: } else if (length + 24 <= hcdChip.spiBufferLimit &&
2120: pageCode == 0x03) {
2121: length += 24;
2122: } else if (length + 16 <= hcdChip.spiBufferLimit &&
2123: pageCode == 0x0e) {
2124: hcdVolumeInt = (hcdChip.spiDataOutBuffer[length + 9] & 255) * 100 / 255;
2125: if (hcdDebugInfo) {
2126: System.out.printf ("volume=%d\n", hcdVolumeInt);
2127: }
2128: hcdVolumeFloat = (float) hcdVolumeInt / 100F;
2129: hcdVolumeSlider.setValue (hcdVolumeInt);
2130: hcdVolumeLabel.setText (String.valueOf (hcdVolumeInt));
2131: length += 16;
2132: } else if (length + 4 <= hcdChip.spiBufferLimit &&
2133: pageCode == 0x31) {
2134: length += 4;
2135: } else {
2136: break;
2137: }
2138: }
2139: hcdChip.spiStatusPhase (SPC.SPC_GOOD, SPC.SPC_COMMAND_COMPLETE);
2140: }
2141:
2142:
2143: static void hcdDumpBuffer (byte[] buffer, int length) {
2144: System.out.print ("[");
2145: for (int i = 0; i < length; i++) {
2146: if (i != 0) {
2147: System.out.print (",");
2148: }
2149: System.out.printf ("0x%02x", buffer[i] & 255);
2150: }
2151: System.out.println ("]");
2152: }
2153:
2154: }