Move cdrom code to its own file (cdrom.c).
[seabios.git] / src / cdrom.c
1 // 16bit code to access cdrom drives.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "disk.h" // cdrom_13
9 #include "util.h" // memset
10 #include "ata.h" // ATA_CMD_READ_SECTORS
11
12
13 /****************************************************************
14  * CDROM functions
15  ****************************************************************/
16
17 // read disk drive size
18 static void
19 cdrom_1315(struct bregs *regs, u8 device)
20 {
21     disk_ret(regs, DISK_RET_EADDRNOTFOUND);
22 }
23
24 // lock
25 static void
26 cdrom_134500(struct bregs *regs, u8 device)
27 {
28     u8 locks = GET_EBDA(ata.devices[device].lock);
29     if (locks == 0xff) {
30         regs->al = 1;
31         disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
32         return;
33     }
34     SET_EBDA(ata.devices[device].lock, locks + 1);
35     regs->al = 1;
36     disk_ret(regs, DISK_RET_SUCCESS);
37 }
38
39 // unlock
40 static void
41 cdrom_134501(struct bregs *regs, u8 device)
42 {
43     u8 locks = GET_EBDA(ata.devices[device].lock);
44     if (locks == 0x00) {
45         regs->al = 0;
46         disk_ret(regs, DISK_RET_ENOTLOCKED);
47         return;
48     }
49     locks--;
50     SET_EBDA(ata.devices[device].lock, locks);
51     regs->al = (locks ? 1 : 0);
52     disk_ret(regs, DISK_RET_SUCCESS);
53 }
54
55 // status
56 static void
57 cdrom_134502(struct bregs *regs, u8 device)
58 {
59     u8 locks = GET_EBDA(ata.devices[device].lock);
60     regs->al = (locks ? 1 : 0);
61     disk_ret(regs, DISK_RET_SUCCESS);
62 }
63
64 static void
65 cdrom_1345XX(struct bregs *regs, u8 device)
66 {
67     disk_ret(regs, DISK_RET_EPARAM);
68 }
69
70 // IBM/MS lock/unlock drive
71 static void
72 cdrom_1345(struct bregs *regs, u8 device)
73 {
74     switch (regs->al) {
75     case 0x00: cdrom_134500(regs, device); break;
76     case 0x01: cdrom_134501(regs, device); break;
77     case 0x02: cdrom_134502(regs, device); break;
78     default:   cdrom_1345XX(regs, device); break;
79     }
80 }
81
82 // IBM/MS eject media
83 static void
84 cdrom_1346(struct bregs *regs, u8 device)
85 {
86     u8 locks = GET_EBDA(ata.devices[device].lock);
87     if (locks != 0) {
88         disk_ret(regs, DISK_RET_ELOCKED);
89         return;
90     }
91
92     // FIXME should handle 0x31 no media in device
93     // FIXME should handle 0xb5 valid request failed
94
95     // Call removable media eject
96     struct bregs br;
97     memset(&br, 0, sizeof(br));
98     br.ah = 0x52;
99     call16_int(0x15, &br);
100
101     if (br.ah || br.flags & F_CF) {
102         disk_ret(regs, DISK_RET_ELOCKED);
103         return;
104     }
105     disk_ret(regs, DISK_RET_SUCCESS);
106 }
107
108 // IBM/MS extended media change
109 static void
110 cdrom_1349(struct bregs *regs, u8 device)
111 {
112     // always send changed ??
113     regs->ah = DISK_RET_ECHANGED;
114     set_cf(regs, 1);
115 }
116
117 static void
118 cdrom_ok(struct bregs *regs, u8 device)
119 {
120     disk_ret(regs, DISK_RET_SUCCESS);
121 }
122
123 static void
124 cdrom_wp(struct bregs *regs, u8 device)
125 {
126     disk_ret(regs, DISK_RET_EWRITEPROTECT);
127 }
128
129 void
130 cdrom_13(struct bregs *regs, u8 device)
131 {
132     //debug_stub(regs);
133
134     switch (regs->ah) {
135     case 0x15: cdrom_1315(regs, device); break;
136     case 0x45: cdrom_1345(regs, device); break;
137     case 0x46: cdrom_1346(regs, device); break;
138     case 0x49: cdrom_1349(regs, device); break;
139
140     // These functions are the same as for hard disks
141     case 0x01:
142     case 0x41:
143     case 0x42:
144     case 0x44:
145     case 0x47:
146     case 0x48:
147     case 0x4e:
148         disk_13(regs, device);
149         break;
150
151     // all these functions return SUCCESS
152     case 0x00: // disk controller reset
153     case 0x09: // initialize drive parameters
154     case 0x0c: // seek to specified cylinder
155     case 0x0d: // alternate disk reset
156     case 0x10: // check drive ready
157     case 0x11: // recalibrate
158     case 0x14: // controller internal diagnostic
159     case 0x16: // detect disk change
160         cdrom_ok(regs, device);
161         break;
162
163     // all these functions return disk write-protected
164     case 0x03: // write disk sectors
165     case 0x05: // format disk track
166     case 0x43: // IBM/MS extended write
167         cdrom_wp(regs, device);
168         break;
169
170     default:   disk_13XX(regs, device); break;
171     }
172 }
173
174
175 /****************************************************************
176  * CD emulation
177  ****************************************************************/
178
179 // read disk sectors
180 static void
181 cdemu_1302(struct bregs *regs, u8 device)
182 {
183     emu_access(regs, device, ATA_CMD_READ_SECTORS);
184 }
185
186 // verify disk sectors
187 static void
188 cdemu_1304(struct bregs *regs, u8 device)
189 {
190     emu_access(regs, device, 0);
191 }
192
193 // read disk drive parameters
194 static void
195 cdemu_1308(struct bregs *regs, u8 device)
196 {
197     u16 nlc   = GET_EBDA(cdemu.vdevice.cylinders) - 1;
198     u16 nlh   = GET_EBDA(cdemu.vdevice.heads) - 1;
199     u16 nlspt = GET_EBDA(cdemu.vdevice.spt);
200
201     regs->al = 0x00;
202     regs->bl = 0x00;
203     regs->ch = nlc & 0xff;
204     regs->cl = ((nlc >> 2) & 0xc0) | (nlspt  & 0x3f);
205     regs->dh = nlh;
206     // FIXME ElTorito Various. should send the real count of drives 1 or 2
207     // FIXME ElTorito Harddisk. should send the HD count
208     regs->dl = 0x02;
209     u8 media = GET_EBDA(cdemu.media);
210     if (media <= 3)
211         regs->bl = media * 2;
212
213     regs->es = SEG_BIOS;
214     regs->di = (u16)&diskette_param_table2;
215
216     disk_ret(regs, DISK_RET_SUCCESS);
217 }
218
219 void
220 cdemu_13(struct bregs *regs)
221 {
222     //debug_stub(regs);
223
224     u8 device  = GET_EBDA(cdemu.controller_index) * 2;
225     device += GET_EBDA(cdemu.device_spec);
226
227     switch (regs->ah) {
228     case 0x02: cdemu_1302(regs, device); break;
229     case 0x04: cdemu_1304(regs, device); break;
230     case 0x08: cdemu_1308(regs, device); break;
231     // XXX - All other calls get passed to standard CDROM functions.
232     default: cdrom_13(regs, device); break;
233     }
234 }
235
236 struct eltorito_s {
237     u8 size;
238     u8 media;
239     u8 emulated_drive;
240     u8 controller_index;
241     u32 ilba;
242     u16 device_spec;
243     u16 buffer_segment;
244     u16 load_segment;
245     u16 sector_count;
246     u8 cylinders;
247     u8 sectors;
248     u8 heads;
249 };
250
251 #define SET_INT13ET(regs,var,val)                                      \
252     SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
253
254 // ElTorito - Terminate disk emu
255 void
256 cdemu_134b(struct bregs *regs)
257 {
258     // FIXME ElTorito Hardcoded
259     SET_INT13ET(regs, size, 0x13);
260     SET_INT13ET(regs, media, GET_EBDA(cdemu.media));
261     SET_INT13ET(regs, emulated_drive, GET_EBDA(cdemu.emulated_drive));
262     SET_INT13ET(regs, controller_index, GET_EBDA(cdemu.controller_index));
263     SET_INT13ET(regs, ilba, GET_EBDA(cdemu.ilba));
264     SET_INT13ET(regs, device_spec, GET_EBDA(cdemu.device_spec));
265     SET_INT13ET(regs, buffer_segment, GET_EBDA(cdemu.buffer_segment));
266     SET_INT13ET(regs, load_segment, GET_EBDA(cdemu.load_segment));
267     SET_INT13ET(regs, sector_count, GET_EBDA(cdemu.sector_count));
268     SET_INT13ET(regs, cylinders, GET_EBDA(cdemu.vdevice.cylinders));
269     SET_INT13ET(regs, sectors, GET_EBDA(cdemu.vdevice.spt));
270     SET_INT13ET(regs, heads, GET_EBDA(cdemu.vdevice.heads));
271
272     // If we have to terminate emulation
273     if (regs->al == 0x00) {
274         // FIXME ElTorito Various. Should be handled accordingly to spec
275         SET_EBDA(cdemu.active, 0x00); // bye bye
276     }
277
278     disk_ret(regs, DISK_RET_SUCCESS);
279 }