Mercurial > mplayer.hg
annotate libmpdvdkit2/bsdi_ioctl.c @ 10252:d275152390ee
I've found some time to implement the encoding support for the new
DivX API. Now it's possible to play and encode movies with the
latest DivX release.
One thing that doesn't work is the new Video Buffer Verifier (VBV)
multipass encoding. The encoder segfaults. Maybe it just isn't
supported with the standard profile of the released binary encoder.
Andreas Hess <jaska@gmx.net>
author | arpi |
---|---|
date | Fri, 06 Jun 2003 19:57:37 +0000 |
parents | f0f0f176d298 |
children | d59cc68ba13b |
rev | line source |
---|---|
7027 | 1 #include "config.h" |
2 | |
3 /* | |
4 * Hacked version of the linux cdrom.c kernel module - everything except the | |
5 * DVD handling ripped out and the rest rewritten to use raw SCSI commands | |
6 * on BSD/OS 4.2 (but should work with earlier versions as well). | |
7 */ | |
8 | |
9 #include <sys/types.h> | |
10 #include <stdlib.h> | |
11 #include <stdio.h> | |
12 #include <errno.h> | |
13 #include <unistd.h> | |
14 #include <sys/ioctl.h> | |
15 #include </sys/dev/scsi/scsi.h> | |
16 #include </sys/dev/scsi/scsi_ioctl.h> | |
17 | |
18 #include "bsdi_dvd.h" | |
19 | |
20 /* | |
21 * Now get rid of the override/intercept macro so we can call the real ioctl() | |
22 * routine! | |
23 */ | |
24 #undef ioctl | |
25 | |
26 #define CMD_READ_10 0x28 | |
27 #define CMD_READ_TOC_PMA_ATIP 0x43 | |
28 #define CMD_READ_CD 0xbe | |
29 #define CMD_START_STOP_UNIT 0x1b | |
30 | |
31 #define CMD_SEND_KEY 0xa3 | |
32 #define CMD_REPORT_KEY 0xa4 | |
33 #define CMD_READ_DVD_STRUCTURE 0xad | |
34 | |
35 #define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) | |
36 #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge)) | |
37 | |
38 /* Define the Cdrom Generic Command structure */ | |
39 typedef struct cgc | |
40 { | |
41 u_char cdb[12]; | |
42 u_char *buf; | |
43 int buflen; | |
44 int rw; | |
45 int timeout; | |
46 scsi_user_sense_t *sus; | |
47 } cgc_t; | |
48 | |
49 static int scsi_cmd(int, cgc_t *); | |
50 static int cdrom_ioctl(int, u_long, void *); | |
51 static int cdrom_tray_move(int, int); | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
52 static void cdrom_count_tracks(int, tracktype *); |
7027 | 53 static int dvd_ioctl(int, u_long, void *); |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
54 static int debug = 0; |
7027 | 55 |
56 void dvd_cdrom_debug(int flag) | |
57 { | |
58 debug = flag; | |
59 } | |
60 | |
61 /* | |
62 * This is the published entry point. Actually applications should simply | |
63 * include <dvd.h> and not refer to this at all. | |
64 */ | |
65 int dvd_cdrom_ioctl(int fd, unsigned long cmd, void *arg) | |
66 { | |
67 switch (cmd) | |
68 { | |
69 case DVD_AUTH: | |
70 case DVD_READ_STRUCT: | |
71 return(dvd_ioctl(fd, cmd, arg)); | |
72 case CDROMREADTOCHDR: | |
73 case CDROMREADTOCENTRY: | |
74 case CDROMEJECT: | |
75 case CDROMREADRAW: | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
76 case CDROMREADMODE1: |
7027 | 77 case CDROMREADMODE2: |
78 case CDROMCLOSETRAY: | |
79 case CDROM_DRIVE_STATUS: | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
80 case CDROM_DISC_STATUS: |
7027 | 81 return(cdrom_ioctl(fd, cmd, arg)); |
82 default: | |
83 return(ioctl(fd, cmd, arg)); | |
84 } | |
85 } | |
86 | |
87 static void setup_report_key(cgc_t *cgc, u_int agid, u_int type) | |
88 { | |
89 | |
90 cgc->cdb[0] = CMD_REPORT_KEY; | |
91 cgc->cdb[10] = type | (agid << 6); | |
92 switch (type) | |
93 { | |
94 case 0: | |
95 case 5: | |
96 case 8: | |
97 cgc->buflen = 8; | |
98 break; | |
99 case 1: | |
100 cgc->buflen = 16; | |
101 break; | |
102 case 2: | |
103 case 4: | |
104 cgc->buflen = 12; | |
105 break; | |
106 } | |
107 cgc->cdb[9] = cgc->buflen; | |
108 cgc->rw = SUC_READ;; | |
109 } | |
110 | |
111 static void setup_send_key(cgc_t *cgc, u_int agid, u_int type) | |
112 { | |
113 | |
114 cgc->cdb[0] = CMD_SEND_KEY; | |
115 cgc->cdb[10] = type | (agid << 6); | |
116 switch (type) | |
117 { | |
118 case 1: | |
119 cgc->buflen = 16; | |
120 break; | |
121 case 3: | |
122 cgc->buflen = 12; | |
123 break; | |
124 case 6: | |
125 cgc->buflen = 8; | |
126 break; | |
127 } | |
128 cgc->cdb[9] = cgc->buflen; | |
129 cgc->rw = SUC_WRITE; | |
130 } | |
131 | |
132 static void cgc_init(cgc_t *cgc, void *buf, int len, int type) | |
133 { | |
134 | |
135 memset(cgc, 0, sizeof (*cgc)); | |
136 if (buf) | |
137 memset(buf, 0, len); | |
138 cgc->buf = (u_char *)buf; | |
139 cgc->buflen = len; | |
140 cgc->rw = type; | |
141 cgc->timeout = 5; /* 5 second timeout */ | |
142 } | |
143 | |
144 static int dvd_do_auth(int fd, dvd_authinfo *ai) | |
145 { | |
146 int ret; | |
147 u_char buf[20]; | |
148 cgc_t cgc; | |
149 rpc_state_t rpc_state; | |
150 | |
151 memset(buf, 0, sizeof(buf)); | |
152 cgc_init(&cgc, buf, 0, SUC_READ); | |
153 | |
154 switch (ai->type) | |
155 { | |
156 case DVD_LU_SEND_AGID: /* LU data send */ | |
157 setup_report_key(&cgc, ai->lsa.agid, 0); | |
158 if (ret = scsi_cmd(fd, &cgc)) | |
159 return ret; | |
160 ai->lsa.agid = buf[7] >> 6; | |
161 break; | |
162 case DVD_LU_SEND_KEY1: | |
163 setup_report_key(&cgc, ai->lsk.agid, 2); | |
164 if (ret = scsi_cmd(fd, &cgc)) | |
165 return ret; | |
166 copy_key(ai->lsk.key, &buf[4]); | |
167 break; | |
168 case DVD_LU_SEND_CHALLENGE: | |
169 setup_report_key(&cgc, ai->lsc.agid, 1); | |
170 if (ret = scsi_cmd(fd, &cgc)) | |
171 return ret; | |
172 copy_chal(ai->lsc.chal, &buf[4]); | |
173 break; | |
174 case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */ | |
175 setup_report_key(&cgc, ai->lstk.agid, 4); | |
176 cgc.cdb[5] = ai->lstk.lba; | |
177 cgc.cdb[4] = ai->lstk.lba >> 8; | |
178 cgc.cdb[3] = ai->lstk.lba >> 16; | |
179 cgc.cdb[2] = ai->lstk.lba >> 24; | |
180 if (ret = scsi_cmd(fd, &cgc)) | |
181 return ret; | |
182 ai->lstk.cpm = (buf[4] >> 7) & 1; | |
183 ai->lstk.cp_sec = (buf[4] >> 6) & 1; | |
184 ai->lstk.cgms = (buf[4] >> 4) & 3; | |
185 copy_key(ai->lstk.title_key, &buf[5]); | |
186 break; | |
187 case DVD_LU_SEND_ASF: | |
188 setup_report_key(&cgc, ai->lsasf.agid, 5); | |
189 if (ret = scsi_cmd(fd, &cgc)) | |
190 return ret; | |
191 ai->lsasf.asf = buf[7] & 1; | |
192 break; | |
193 case DVD_HOST_SEND_CHALLENGE: /* LU data receive (LU changes state) */ | |
194 setup_send_key(&cgc, ai->hsc.agid, 1); | |
195 buf[1] = 0xe; | |
196 copy_chal(&buf[4], ai->hsc.chal); | |
197 if (ret = scsi_cmd(fd, &cgc)) | |
198 return ret; | |
199 ai->type = DVD_LU_SEND_KEY1; | |
200 break; | |
201 case DVD_HOST_SEND_KEY2: | |
202 setup_send_key(&cgc, ai->hsk.agid, 3); | |
203 buf[1] = 0xa; | |
204 copy_key(&buf[4], ai->hsk.key); | |
205 if (ret = scsi_cmd(fd, &cgc)) | |
206 { | |
207 ai->type = DVD_AUTH_FAILURE; | |
208 return ret; | |
209 } | |
210 ai->type = DVD_AUTH_ESTABLISHED; | |
211 break; | |
212 case DVD_INVALIDATE_AGID: | |
213 setup_report_key(&cgc, ai->lsa.agid, 0x3f); | |
214 if (ret = scsi_cmd(fd, &cgc)) | |
215 return ret; | |
216 break; | |
217 case DVD_LU_SEND_RPC_STATE: /* Get region settings */ | |
218 setup_report_key(&cgc, 0, 8); | |
219 memset(&rpc_state, 0, sizeof(rpc_state_t)); | |
220 cgc.buf = (char *) &rpc_state; | |
221 if (ret = scsi_cmd(fd, &cgc)) | |
222 { | |
223 ai->lrpcs.type = 0; | |
224 ai->lrpcs.rpc_scheme = 0; | |
225 } | |
226 else | |
227 { | |
228 ai->lrpcs.type = rpc_state.type_code; | |
229 ai->lrpcs.vra = rpc_state.vra; | |
230 ai->lrpcs.ucca = rpc_state.ucca; | |
231 ai->lrpcs.region_mask = rpc_state.region_mask; | |
232 ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; | |
233 } | |
234 break; | |
235 case DVD_HOST_SEND_RPC_STATE: /* Set region settings */ | |
236 setup_send_key(&cgc, 0, 6); | |
237 buf[1] = 6; | |
238 buf[4] = ai->hrpcs.pdrc; | |
239 if (ret = scsi_cmd(fd, &cgc)) | |
240 return ret; | |
241 break; | |
242 default: | |
243 return EINVAL; | |
244 } | |
245 return 0; | |
246 } | |
247 | |
248 static int dvd_read_physical(int fd, dvd_struct *s) | |
249 { | |
250 int ret, i; | |
251 u_char buf[4 + 4 * 20], *base; | |
252 struct dvd_layer *layer; | |
253 cgc_t cgc; | |
254 | |
255 cgc_init(&cgc, buf, sizeof(buf), SUC_READ); | |
256 cgc.cdb[0] = CMD_READ_DVD_STRUCTURE; | |
257 cgc.cdb[6] = s->physical.layer_num; | |
258 cgc.cdb[7] = s->type; | |
259 cgc.cdb[9] = cgc.buflen & 0xff; | |
260 | |
261 if (ret = scsi_cmd(fd, &cgc)) | |
262 return ret; | |
263 | |
264 base = &buf[4]; | |
265 layer = &s->physical.layer[0]; | |
266 | |
267 /* place the data... really ugly, but at least we won't have to | |
268 worry about endianess in userspace or here. */ | |
269 for (i = 0; i < 4; ++i, base += 20, ++layer) | |
270 { | |
271 memset(layer, 0, sizeof(*layer)); | |
272 layer->book_version = base[0] & 0xf; | |
273 layer->book_type = base[0] >> 4; | |
274 layer->min_rate = base[1] & 0xf; | |
275 layer->disc_size = base[1] >> 4; | |
276 layer->layer_type = base[2] & 0xf; | |
277 layer->track_path = (base[2] >> 4) & 1; | |
278 layer->nlayers = (base[2] >> 5) & 3; | |
279 layer->track_density = base[3] & 0xf; | |
280 layer->linear_density = base[3] >> 4; | |
281 layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; | |
282 layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; | |
283 layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; | |
284 layer->bca = base[16] >> 7; | |
285 } | |
286 return 0; | |
287 } | |
288 | |
289 static int dvd_read_copyright(int fd, dvd_struct *s) | |
290 { | |
291 int ret; | |
292 u_char buf[8]; | |
293 cgc_t cgc; | |
294 | |
295 cgc_init(&cgc, buf, sizeof(buf), SUC_READ); | |
296 cgc.cdb[0] = CMD_READ_DVD_STRUCTURE; | |
297 cgc.cdb[6] = s->copyright.layer_num; | |
298 cgc.cdb[7] = s->type; | |
299 cgc.cdb[8] = cgc.buflen >> 8; | |
300 cgc.cdb[9] = cgc.buflen & 0xff; | |
301 | |
302 if (ret = scsi_cmd(fd, &cgc)) | |
303 return ret; | |
304 s->copyright.cpst = buf[4]; | |
305 s->copyright.rmi = buf[5]; | |
306 return 0; | |
307 } | |
308 | |
309 static int dvd_read_disckey(int fd, dvd_struct *s) | |
310 { | |
311 int ret, size; | |
312 u_char *buf; | |
313 cgc_t cgc; | |
314 | |
315 size = sizeof(s->disckey.value) + 4; | |
316 | |
317 if ((buf = (u_char *) malloc(size)) == NULL) | |
318 return ENOMEM; | |
319 | |
320 cgc_init(&cgc, buf, size, SUC_READ); | |
321 cgc.cdb[0] = CMD_READ_DVD_STRUCTURE; | |
322 cgc.cdb[7] = s->type; | |
323 cgc.cdb[8] = size >> 8; | |
324 cgc.cdb[9] = size & 0xff; | |
325 cgc.cdb[10] = s->disckey.agid << 6; | |
326 | |
327 if (!(ret = scsi_cmd(fd, &cgc))) | |
328 memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value)); | |
329 free(buf); | |
330 return ret; | |
331 } | |
332 | |
333 static int dvd_read_bca(int fd, dvd_struct *s) | |
334 { | |
335 int ret; | |
336 u_char buf[4 + 188]; | |
337 cgc_t cgc; | |
338 | |
339 cgc_init(&cgc, buf, sizeof(buf), SUC_READ); | |
340 cgc.cdb[0] = CMD_READ_DVD_STRUCTURE; | |
341 cgc.cdb[7] = s->type; | |
342 cgc.cdb[9] = cgc.buflen = 0xff; | |
343 | |
344 if (ret = scsi_cmd(fd, &cgc)) | |
345 return ret; | |
346 s->bca.len = buf[0] << 8 | buf[1]; | |
347 if (s->bca.len < 12 || s->bca.len > 188) | |
348 return EIO; | |
349 memcpy(s->bca.value, &buf[4], s->bca.len); | |
350 return 0; | |
351 } | |
352 | |
353 static int dvd_read_manufact(int fd, dvd_struct *s) | |
354 { | |
355 int ret = 0, size; | |
356 u_char *buf; | |
357 cgc_t cgc; | |
358 | |
359 size = sizeof(s->manufact.value) + 4; | |
360 | |
361 if ((buf = (u_char *) malloc(size)) == NULL) | |
362 return ENOMEM; | |
363 | |
364 cgc_init(&cgc, buf, size, SUC_READ); | |
365 cgc.cdb[0] = CMD_READ_DVD_STRUCTURE; | |
366 cgc.cdb[7] = s->type; | |
367 cgc.cdb[8] = size >> 8; | |
368 cgc.cdb[9] = size & 0xff; | |
369 | |
370 if (ret = scsi_cmd(fd, &cgc)) | |
371 { | |
372 free(buf); | |
373 return ret; | |
374 } | |
375 s->manufact.len = buf[0] << 8 | buf[1]; | |
376 if (s->manufact.len < 0 || s->manufact.len > 2048) | |
377 ret = -EIO; | |
378 else | |
379 memcpy(s->manufact.value, &buf[4], s->manufact.len); | |
380 free(buf); | |
381 return ret; | |
382 } | |
383 | |
384 static int dvd_read_struct(int fd, dvd_struct *s) | |
385 { | |
386 switch (s->type) | |
387 { | |
388 case DVD_STRUCT_PHYSICAL: | |
389 return dvd_read_physical(fd, s); | |
390 case DVD_STRUCT_COPYRIGHT: | |
391 return dvd_read_copyright(fd, s); | |
392 case DVD_STRUCT_DISCKEY: | |
393 return dvd_read_disckey(fd, s); | |
394 case DVD_STRUCT_BCA: | |
395 return dvd_read_bca(fd, s); | |
396 case DVD_STRUCT_MANUFACT: | |
397 return dvd_read_manufact(fd, s); | |
398 default: | |
399 return EINVAL; | |
400 } | |
401 } | |
402 | |
403 static u_char scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10}; | |
404 | |
405 static int scsi_cmd(int fd, cgc_t *cgc) | |
406 { | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
407 int i, scsistatus, cdblen; |
7027 | 408 unsigned char *cp; |
409 struct scsi_user_cdb suc; | |
410 | |
411 /* safety checks */ | |
412 if (cgc->rw != SUC_READ && cgc->rw != SUC_WRITE) | |
413 return(EINVAL); | |
414 | |
415 suc.suc_flags = cgc->rw; | |
416 cdblen = scsi_cdblen[(cgc->cdb[0] >> 5) & 7]; | |
417 suc.suc_cdblen = cdblen; | |
418 bcopy(cgc->cdb, suc.suc_cdb, cdblen); | |
419 suc.suc_data = cgc->buf; | |
420 suc.suc_datalen = cgc->buflen; | |
421 suc.suc_timeout = cgc->timeout; | |
422 if (ioctl(fd, SCSIRAWCDB, &suc) == -1) | |
423 return(errno); | |
424 scsistatus = suc.suc_sus.sus_status; | |
425 | |
426 /* | |
427 * If the device returns a scsi sense error and debugging is enabled print | |
428 * some hopefully useful information on stderr. | |
429 */ | |
430 if (scsistatus && debug) | |
431 { | |
432 cp = suc.suc_sus.sus_sense; | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
433 fprintf(stderr,"scsistatus = %x cdb =", |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
434 scsistatus); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
435 for (i = 0; i < cdblen; i++) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
436 fprintf(stderr, " %x", cgc->cdb[i]); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
437 fprintf(stderr, "\nsense ="); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
438 for (i = 0; i < 16; i++) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
439 fprintf(stderr, " %x", cp[i]); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
440 fprintf(stderr, "\n"); |
7027 | 441 } |
442 if (cgc->sus) | |
443 bcopy(&suc.suc_sus, cgc->sus, sizeof (struct scsi_user_sense)); | |
444 if (scsistatus) | |
445 return(EIO); /* generic i/o error for unsuccessful status */ | |
446 return(0); | |
447 } | |
448 | |
449 /* | |
450 * The entry point for the DVDioctls for BSD/OS. | |
451 */ | |
452 static int dvd_ioctl(int fd, u_long cmd, void *arg) | |
453 { | |
454 int ret; | |
455 | |
456 switch (cmd) | |
457 { | |
458 case DVD_READ_STRUCT: | |
459 ret = dvd_read_struct(fd, (dvd_struct *)arg); | |
460 if (ret) | |
461 errno = ret; | |
462 return(ret ? -1 : 0); | |
463 case DVD_AUTH: | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
464 ret = dvd_do_auth(fd, (dvd_authinfo *)arg); |
7027 | 465 if (ret) |
466 errno = ret; | |
467 return(ret ? -1 : 0); | |
468 default: | |
469 errno = EINVAL; | |
470 return(-1); | |
471 } | |
472 } | |
473 | |
474 /* | |
475 * The entry point for the CDROMioctls for BSD/OS | |
476 */ | |
477 static int cdrom_read_block(int, cgc_t *, int, int, int, int); | |
478 static int cdrom_read_cd(int, cgc_t *, int, int, int ); | |
479 int cdrom_blocksize(int, int ); | |
480 | |
481 static inline | |
482 int msf_to_lba(char m, char s, char f) | |
483 { | |
484 return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; | |
485 } | |
486 | |
487 cdrom_ioctl(int fd, u_long cmd, void *arg) | |
488 { | |
489 int ret; | |
490 cgc_t cgc; | |
491 | |
492 switch (cmd) | |
493 { | |
494 case CDROMREADRAW: | |
495 case CDROMREADMODE1: | |
496 case CDROMREADMODE2: | |
497 { | |
498 struct cdrom_msf *msf; | |
499 int blocksize = 0, format = 0, lba; | |
500 | |
501 switch (cmd) | |
502 { | |
503 case CDROMREADRAW: | |
504 blocksize = CD_FRAMESIZE_RAW; | |
505 break; | |
506 case CDROMREADMODE1: | |
507 blocksize = CD_FRAMESIZE; | |
508 format = 2; | |
509 break; | |
510 case CDROMREADMODE2: | |
511 blocksize = CD_FRAMESIZE_RAW0; | |
512 break; | |
513 } | |
514 msf = (struct cdrom_msf *)arg; | |
515 lba = msf_to_lba(msf->cdmsf_min0,msf->cdmsf_sec0, | |
516 msf->cdmsf_frame0); | |
517 ret = EINVAL; | |
518 if (lba < 0) | |
519 break; | |
520 | |
521 cgc_init(&cgc, arg, blocksize, SUC_READ); | |
522 ret = cdrom_read_block(fd, &cgc, lba, 1, format, blocksize); | |
523 if (ret) | |
524 { | |
525 /* | |
526 * SCSI-II devices are not required to support CMD_READ_CD (which specifies | |
527 * the blocksize to read) so try switching the block size with a mode select, | |
528 * doing the normal read sector command and then changing the sector size back | |
529 * to 2048. | |
530 * | |
531 * If the program dies before changing the blocksize back sdopen() | |
532 * in the kernel will fail opens with a message that looks something like: | |
533 * | |
534 * "sr1: blksize 2336 not multiple of 512: cannot use" | |
535 * | |
536 * At that point the drive has to be power cycled (or reset in some other way). | |
537 */ | |
538 if (ret = cdrom_blocksize(fd, blocksize)) | |
539 break; | |
540 ret = cdrom_read_cd(fd, &cgc, lba, blocksize, 1); | |
541 ret |= cdrom_blocksize(fd, 2048); | |
542 } | |
543 break; | |
544 } | |
545 case CDROMREADTOCHDR: | |
546 { | |
547 struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; | |
548 u_char buffer[12]; | |
549 | |
550 cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); | |
551 cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; | |
552 cgc.cdb[1] = 0x2; /* MSF */ | |
553 cgc.cdb[8] = 12; /* LSB of length */ | |
554 | |
555 ret = scsi_cmd(fd, &cgc); | |
556 if (!ret) | |
557 { | |
558 tochdr->cdth_trk0 = buffer[2]; | |
559 tochdr->cdth_trk1 = buffer[3]; | |
560 } | |
561 break; | |
562 } | |
563 case CDROMREADTOCENTRY: | |
564 { | |
565 struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; | |
566 u_char buffer[12]; | |
567 | |
568 cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); | |
569 cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; | |
570 cgc.cdb[1] = (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; | |
571 cgc.cdb[6] = tocentry->cdte_track; | |
572 cgc.cdb[8] = 12; /* LSB of length */ | |
573 | |
574 ret = scsi_cmd(fd, &cgc); | |
575 if (ret) | |
576 break; | |
577 | |
578 tocentry->cdte_ctrl = buffer[5] & 0xf; | |
579 tocentry->cdte_adr = buffer[5] >> 4; | |
580 tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; | |
581 if (tocentry->cdte_format == CDROM_MSF) | |
582 { | |
583 tocentry->cdte_addr.msf.minute = buffer[9]; | |
584 tocentry->cdte_addr.msf.second = buffer[10]; | |
585 tocentry->cdte_addr.msf.frame = buffer[11]; | |
586 } | |
587 else | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
588 tocentry->cdte_addr.lba = (((((buffer[8] << 8) |
7027 | 589 + buffer[9]) << 8) |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
590 + buffer[10]) << 8) |
7027 | 591 + buffer[11]; |
592 break; | |
593 } | |
594 case CDROMEJECT: /* NO-OP for now */ | |
595 ret = cdrom_tray_move(fd, 1); | |
596 break; | |
597 case CDROMCLOSETRAY: | |
598 ret = cdrom_tray_move(fd, 0); | |
599 break; | |
600 /* | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
601 * This sucks but emulates the expected behaviour. Instead of the return |
7027 | 602 * value being the actual status a success/fail indicator should have been |
603 * returned and the 3rd arg to the ioctl should have been an 'int *' to update | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
604 * with the actual status. Both the drive and disc status ioctl calls are |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
605 * similarily braindamaged. |
7027 | 606 */ |
607 case CDROM_DRIVE_STATUS: | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
608 return(CDS_NO_INFO); /* XXX */ |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
609 case CDROM_DISC_STATUS: |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
610 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
611 tracktype tracks; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
612 int cnt; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
613 |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
614 cdrom_count_tracks(fd, &tracks); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
615 if (tracks.error) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
616 return(tracks.error); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
617 if (tracks.audio > 0) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
618 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
619 cnt = tracks.data + tracks.cdi + tracks.xa; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
620 if (cnt == 0) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
621 return(CDS_AUDIO); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
622 else |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
623 return(CDS_MIXED); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
624 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
625 if (tracks.cdi) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
626 return(CDS_XA_2_2); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
627 if (tracks.xa) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
628 return(CDS_XA_2_1); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
629 if (tracks.data) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
630 return(CDS_DATA_1); |
7027 | 631 return(CDS_NO_INFO); |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
632 } |
7027 | 633 } |
634 errno = ret; | |
635 return(ret ? -1 : 0); | |
636 } | |
637 | |
638 static int cdrom_read_cd(int fd, cgc_t *cgc, int lba, int blocksize, int nblocks) | |
639 { | |
640 | |
641 memset(&cgc->cdb, 0, sizeof(cgc->cdb)); | |
642 cgc->cdb[0] = CMD_READ_10; | |
643 cgc->cdb[2] = (lba >> 24) & 0xff; | |
644 cgc->cdb[3] = (lba >> 16) & 0xff; | |
645 cgc->cdb[4] = (lba >> 8) & 0xff; | |
646 cgc->cdb[5] = lba & 0xff; | |
647 cgc->cdb[6] = (nblocks >> 16) & 0xff; | |
648 cgc->cdb[7] = (nblocks >> 8) & 0xff; | |
649 cgc->cdb[8] = nblocks & 0xff; | |
650 cgc->buflen = blocksize * nblocks; | |
651 return(scsi_cmd(fd, cgc)); | |
652 } | |
653 | |
654 static int cdrom_read_block(int fd, cgc_t *cgc, | |
655 int lba, int nblocks, int format, int blksize) | |
656 { | |
657 | |
658 memset(&cgc->cdb, 0, sizeof(cgc->cdb)); | |
659 cgc->cdb[0] = CMD_READ_CD; | |
660 /* expected sector size - cdda,mode1,etc. */ | |
661 cgc->cdb[1] = format << 2; | |
662 /* starting address */ | |
663 cgc->cdb[2] = (lba >> 24) & 0xff; | |
664 cgc->cdb[3] = (lba >> 16) & 0xff; | |
665 cgc->cdb[4] = (lba >> 8) & 0xff; | |
666 cgc->cdb[5] = lba & 0xff; | |
667 /* number of blocks */ | |
668 cgc->cdb[6] = (nblocks >> 16) & 0xff; | |
669 cgc->cdb[7] = (nblocks >> 8) & 0xff; | |
670 cgc->cdb[8] = nblocks & 0xff; | |
671 cgc->buflen = blksize * nblocks; | |
672 | |
673 /* set the header info returned */ | |
674 switch (blksize) | |
675 { | |
676 case CD_FRAMESIZE_RAW0: | |
677 cgc->cdb[9] = 0x58; | |
678 break; | |
679 case CD_FRAMESIZE_RAW1: | |
680 cgc->cdb[9] = 0x78; | |
681 break; | |
682 case CD_FRAMESIZE_RAW: | |
683 cgc->cdb[9] = 0xf8; | |
684 break; | |
685 default: | |
686 cgc->cdb[9] = 0x10; | |
687 } | |
688 return(scsi_cmd(fd, cgc)); | |
689 } | |
690 | |
9333
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
691 static void cdrom_count_tracks(int fd, tracktype *tracks) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
692 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
693 struct cdrom_tochdr header; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
694 struct cdrom_tocentry entry; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
695 int ret, i; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
696 |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
697 bzero(tracks, sizeof (*tracks)); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
698 ret = cdrom_ioctl(fd, CDROMREADTOCHDR, &header); |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
699 /* |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
700 * This whole business is a crock anyhow so we don't bother distinguishing |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
701 * between no media, drive not ready, etc and on any error just say we have |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
702 * no info. |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
703 */ |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
704 if (ret) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
705 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
706 tracks->error = CDS_NO_INFO; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
707 return; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
708 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
709 |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
710 entry.cdte_format = CDROM_MSF; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
711 for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
712 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
713 entry.cdte_track = i; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
714 if (cdrom_ioctl(fd, CDROMREADTOCENTRY, &entry)) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
715 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
716 tracks->error = CDS_NO_INFO; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
717 return; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
718 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
719 if (entry.cdte_ctrl & CDROM_DATA_TRACK) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
720 { |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
721 if (entry.cdte_format == 0x10) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
722 tracks->cdi++; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
723 else if (entry.cdte_format == 0x20) |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
724 tracks->xa++; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
725 else |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
726 tracks->data++; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
727 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
728 else |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
729 tracks->audio++; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
730 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
731 return; |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
732 } |
f0f0f176d298
sync with libdvdcss 1.2.5 (including u8->uint8_t and whitespace cosmetics...)
arpi
parents:
7027
diff
changeset
|
733 |
7027 | 734 static int cdrom_tray_move(int fd, int flag) |
735 { | |
736 cgc_t cgc; | |
737 | |
738 cgc_init(&cgc, NULL, 0, SUC_READ); | |
739 cgc.cdb[0] = CMD_START_STOP_UNIT; | |
740 cgc.cdb[1] = 1; /* immediate */ | |
741 cgc.cdb[4] = flag ? 0x2 : 0x3; /* eject : close */ | |
742 return(scsi_cmd(fd, &cgc)); | |
743 } | |
744 | |
745 /* | |
746 * Required when we need to use READ_10 to issue other than 2048 block | |
747 * reads | |
748 */ | |
749 int cdrom_blocksize(int fd, int size) | |
750 { | |
751 cgc_t cgc; | |
752 struct modesel_head mh; | |
753 | |
754 memset(&mh, 0, sizeof(mh)); | |
755 mh.block_desc_length = 0x08; | |
756 mh.block_length_med = (size >> 8) & 0xff; | |
757 mh.block_length_lo = size & 0xff; | |
758 | |
759 memset(&cgc, 0, sizeof(cgc)); | |
760 cgc.cdb[0] = 0x15; | |
761 cgc.cdb[1] = 1 << 4; | |
762 cgc.cdb[4] = 12; | |
763 cgc.buflen = sizeof(mh); | |
764 cgc.buf = (u_char *) &mh; | |
765 cgc.rw = SUC_WRITE; | |
766 mh.block_desc_length = 0x08; | |
767 mh.block_length_med = (size >> 8) & 0xff; | |
768 mh.block_length_lo = size & 0xff; | |
769 return(scsi_cmd(fd, &cgc)); | |
770 } |