1 /*****************************************************************************
2 * dvd_ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ioctl.c,v 1.1 2001/02/20 07:49:12 sam Exp $
7 * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
30 #include <netinet/in.h>
31 #ifdef HAVE_SYS_IOCTL_H
32 # include <sys/ioctl.h>
34 #ifdef HAVE_SYS_DVDIO_H
35 # include <sys/dvdio.h>
38 # include <linux/cdrom.h>
48 #include "dvd_ioctl.h"
50 /*****************************************************************************
52 *****************************************************************************/
53 #if defined( SYS_BEOS )
54 static int dvd_do_auth ( int i_fd, dvd_authinfo *p_authinfo );
55 static int dvd_read_struct ( int i_fd, dvd_struct *p_dvd );
56 static int dvd_read_physical ( int i_fd, dvd_struct *p_dvd );
57 static int dvd_read_copyright ( int i_fd, dvd_struct *p_dvd );
58 static int dvd_read_disckey ( int i_fd, dvd_struct *p_dvd );
59 static int dvd_read_bca ( int i_fd, dvd_struct *p_dvd );
60 static int dvd_read_manufact ( int i_fd, dvd_struct *p_dvd );
61 static int communicate_with_dvd ( int i_fd,
62 struct cdrom_generic_command *p_cgc );
63 static void init_cdrom_command ( struct cdrom_generic_command *p_cgc,
64 void *buf, int i_len, int i_type );
65 static void setup_report_key ( struct cdrom_generic_command *p_cgc,
66 unsigned i_agid, unsigned i_type );
67 static void setup_send_key ( struct cdrom_generic_command *p_cgc,
68 unsigned i_agid, unsigned i_type );
71 /*****************************************************************************
72 * dvd_ioctl: DVD ioctl() wrapper
73 *****************************************************************************
74 * Since the DVD ioctls do not exist on every machine, we provide this wrapper
75 * so that it becomes easier to port them to any architecture.
76 *****************************************************************************/
77 int dvd_ioctl( int i_fd, unsigned long i_op, void *p_arg )
79 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
80 return( ioctl( i_fd, i_op, p_arg ) );
82 #elif defined( SYS_BEOS )
86 return dvd_do_auth( i_fd, (dvd_authinfo *)p_arg );
89 return dvd_read_struct( i_fd, (dvd_struct *)p_arg );
92 intf_ErrMsg( "css error: unknown command 0x%x", i_op );
101 #if defined( SYS_BEOS )
103 /*****************************************************************************
105 *****************************************************************************/
106 static void setup_report_key( struct cdrom_generic_command *p_cgc,
107 unsigned i_agid, unsigned i_type )
109 p_cgc->cmd[0] = GPCMD_REPORT_KEY;
110 p_cgc->cmd[10] = i_type | (i_agid << 6);
130 p_cgc->cmd[9] = p_cgc->buflen;
131 p_cgc->data_direction = CGC_DATA_READ;
134 /*****************************************************************************
136 *****************************************************************************/
137 static void setup_send_key( struct cdrom_generic_command *p_cgc,
138 unsigned i_agid, unsigned i_type )
140 p_cgc->cmd[0] = GPCMD_SEND_KEY;
141 p_cgc->cmd[10] = i_type | (i_agid << 6);
158 p_cgc->cmd[9] = p_cgc->buflen;
159 p_cgc->data_direction = CGC_DATA_WRITE;
162 /*****************************************************************************
164 *****************************************************************************/
165 static void init_cdrom_command( struct cdrom_generic_command *p_cgc,
166 void *buf, int i_len, int i_type )
168 memset( p_cgc, 0, sizeof(struct cdrom_generic_command) );
172 memset( buf, 0, i_len );
175 p_cgc->buffer = (char *) buf;
176 p_cgc->buflen = i_len;
177 p_cgc->data_direction = i_type;
178 p_cgc->timeout = 255;
183 /*****************************************************************************
185 *****************************************************************************/
186 static int dvd_do_auth( int i_fd, dvd_authinfo *p_authinfo )
189 unsigned char buf[20];
190 struct cdrom_generic_command p_cgc;
192 #define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))
193 #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
196 struct rpc_state_t rpc_state;
199 memset( buf, 0, sizeof(buf) );
200 init_cdrom_command( &p_cgc, buf, 0, CGC_DATA_READ );
202 switch (p_authinfo->type)
205 case DVD_LU_SEND_AGID:
207 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_AGID" );
209 setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0);
211 /* handle uniform packets for scsi type devices (scsi,atapi) */
212 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
217 p_authinfo->lsa.agid = buf[7] >> 6;
218 /* Returning data, let host change state */
222 case DVD_LU_SEND_KEY1:
224 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY1" );
226 setup_report_key(&p_cgc, p_authinfo->lsk.agid, 2);
228 /* handle uniform packets for scsi type devices (scsi,atapi) */
229 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
234 copy_key(p_authinfo->lsk.key, &buf[4]);
235 /* Returning data, let host change state */
239 case DVD_LU_SEND_CHALLENGE:
241 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
243 setup_report_key(&p_cgc, p_authinfo->lsc.agid, 1);
245 /* handle uniform packets for scsi type devices (scsi,atapi) */
246 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
251 copy_chal(p_authinfo->lsc.chal, &buf[4]);
252 /* Returning data, let host change state */
257 case DVD_LU_SEND_TITLE_KEY:
259 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_TITLE_KEY" );
261 setup_report_key(&p_cgc, p_authinfo->lstk.agid, 4);
262 p_cgc.cmd[5] = p_authinfo->lstk.lba;
263 p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
264 p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
265 p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
267 /* handle uniform packets for scsi type devices (scsi,atapi) */
268 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
273 p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
274 p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
275 p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
276 copy_key(p_authinfo->lstk.title_key, &buf[5]);
277 /* Returning data, let host change state */
281 case DVD_LU_SEND_ASF:
283 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_ASF" );
285 setup_report_key(&p_cgc, p_authinfo->lsasf.agid, 5);
287 /* handle uniform packets for scsi type devices (scsi,atapi) */
288 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
293 p_authinfo->lsasf.asf = buf[7] & 1;
297 /* LU data receive (LU changes state) */
298 case DVD_HOST_SEND_CHALLENGE:
300 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
302 setup_send_key(&p_cgc, p_authinfo->hsc.agid, 1);
304 copy_chal(&buf[4], p_authinfo->hsc.chal);
306 /* handle uniform packets for scsi type devices (scsi,atapi) */
307 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
312 p_authinfo->type = DVD_LU_SEND_KEY1;
316 case DVD_HOST_SEND_KEY2:
318 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY2" );
320 setup_send_key(&p_cgc, p_authinfo->hsk.agid, 3);
322 copy_key(&buf[4], p_authinfo->hsk.key);
324 /* handle uniform packets for scsi type devices (scsi,atapi) */
325 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
327 p_authinfo->type = DVD_AUTH_FAILURE;
330 p_authinfo->type = DVD_AUTH_ESTABLISHED;
335 case DVD_INVALIDATE_AGID:
337 intf_WarnMsg( 2, "css dvd_do_auth: DVD_INVALIDATE_AGID" );
339 setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0x3f);
341 /* handle uniform packets for scsi type devices (scsi,atapi) */
342 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
349 /* Get region settings */
350 case DVD_LU_SEND_RPC_STATE:
352 intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_RPC_STATE "
356 p_dvdetup_report_key(&p_cgc, 0, 8);
357 memset(&rpc_state, 0, sizeof(rpc_state_t));
358 p_cgc.buffer = (char *) &rpc_state;
360 /* handle uniform packets for scsi type devices (scsi,atapi) */
361 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
366 p_authinfo->lrpcs.type = rpc_state.type_code;
367 p_authinfo->lrpcs.vra = rpc_state.vra;
368 p_authinfo->lrpcs.ucca = rpc_state.ucca;
369 p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
370 p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
375 /* Set region settings */
376 case DVD_HOST_SEND_RPC_STATE:
378 intf_WarnMsg( 2, "css dvd_do_auth: DVD_HOST_SEND_RPC_STATE" );
380 setup_send_key(&p_cgc, 0, 6);
382 buf[4] = p_authinfo->hrpcs.pdrc;
384 /* handle uniform packets for scsi type devices (scsi,atapi) */
385 if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
393 intf_ErrMsg( "css dvd_do_auth: invalid DVD key ioctl" );
401 /*****************************************************************************
403 *****************************************************************************/
404 static int dvd_read_struct( int i_fd, dvd_struct *p_dvd )
408 case DVD_STRUCT_PHYSICAL:
410 intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_PHYSICAL" );
411 return dvd_read_physical(i_fd, p_dvd);
413 case DVD_STRUCT_COPYRIGHT:
415 intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_COPYRIGHT" );
416 return dvd_read_copyright(i_fd, p_dvd);
418 case DVD_STRUCT_DISCKEY:
420 intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_DISCKEY" );
421 return dvd_read_disckey(i_fd, p_dvd);
425 intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_BCA" );
426 return dvd_read_bca(i_fd, p_dvd);
428 case DVD_STRUCT_MANUFACT:
430 intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_MANUFACT" );
431 return dvd_read_manufact(i_fd, p_dvd);
434 intf_WarnMsg( 2, "css dvd_read_struct: invalid request (%d)",
440 /*****************************************************************************
442 *****************************************************************************/
443 static int dvd_read_physical( int i_fd, dvd_struct *p_dvd )
446 u_char buf[4 + 4 * 20], *base;
447 struct dvd_layer *layer;
448 struct cdrom_generic_command cgc;
450 init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
452 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
453 cgc.cmd[6] = p_dvd->physical.layer_num;
454 cgc.cmd[7] = p_dvd->type;
455 cgc.cmd[9] = cgc.buflen & 0xff;
457 /* handle uniform packets for scsi type devices (scsi,atapi) */
458 if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
464 layer = &p_dvd->physical.layer[0];
466 /* place the data... really ugly, but at least we won't have to
467 * worry about endianess in userspace or here. */
468 for( i = 0; i < 4; ++i, base += 20, ++layer )
470 memset( layer, 0, sizeof(*layer) );
472 layer->book_version = base[0] & 0xf;
473 layer->book_type = base[0] >> 4;
474 layer->min_rate = base[1] & 0xf;
475 layer->disc_size = base[1] >> 4;
476 layer->layer_type = base[2] & 0xf;
477 layer->track_path = (base[2] >> 4) & 1;
478 layer->nlayers = (base[2] >> 5) & 3;
479 layer->track_density = base[3] & 0xf;
480 layer->linear_density = base[3] >> 4;
481 layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
482 layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
483 layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
484 layer->bca = base[16] >> 7;
490 /*****************************************************************************
492 *****************************************************************************/
493 static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
497 struct cdrom_generic_command cgc;
499 init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
501 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
502 cgc.cmd[6] = p_dvd->copyright.layer_num;
503 cgc.cmd[7] = p_dvd->type;
504 cgc.cmd[8] = cgc.buflen >> 8;
505 cgc.cmd[9] = cgc.buflen & 0xff;
507 /* handle uniform packets for scsi type devices (scsi,atapi) */
508 if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
513 p_dvd->copyright.cpst = buf[4];
514 p_dvd->copyright.rmi = buf[5];
519 /*****************************************************************************
521 *****************************************************************************/
522 static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
526 struct cdrom_generic_command cgc;
528 size = sizeof( p_dvd->disckey.value ) + 4;
531 if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
536 buf = (u_char *) malloc(size);
538 init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
539 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
540 cgc.cmd[7] = p_dvd->type;
541 cgc.cmd[8] = size >> 8;
542 cgc.cmd[9] = size & 0xff;
543 cgc.cmd[10] = p_dvd->disckey.agid << 6;
545 /* handle uniform packets for scsi type devices (scsi,atapi) */
546 if( !(i_ret = communicate_with_dvd(i_fd, &cgc)) )
548 memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
555 /*****************************************************************************
557 *****************************************************************************/
558 static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
562 struct cdrom_generic_command cgc;
564 init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
565 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
566 cgc.cmd[7] = p_dvd->type;
567 cgc.cmd[9] = cgc.buflen = 0xff;
569 /* handle uniform packets for scsi type devices (scsi,atapi) */
570 if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
575 p_dvd->bca.len = buf[0] << 8 | buf[1];
576 if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
578 intf_ErrMsg("css error: invalid BCA length (%d)", p_dvd->bca.len );
582 memcpy( p_dvd->bca.value, &buf[4], p_dvd->bca.len );
587 /*****************************************************************************
589 *****************************************************************************/
590 static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
594 struct cdrom_generic_command cgc;
596 size = sizeof(p_dvd->manufact.value) + 4;
599 if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
604 buf = (u_char *) malloc(size);
606 init_cdrom_command( &cgc, buf, size, CGC_DATA_READ );
607 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
608 cgc.cmd[7] = p_dvd->type;
609 cgc.cmd[8] = size >> 8;
610 cgc.cmd[9] = size & 0xff;
612 /* handle uniform packets for scsi type devices (scsi,atapi) */
613 if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
618 p_dvd->manufact.len = buf[0] << 8 | buf[1];
619 if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
621 intf_ErrMsg( "css error: invalid manufacturer info length "
622 "(%d)\n", p_dvd->bca.len );
627 memcpy( p_dvd->manufact.value, &buf[4], p_dvd->manufact.len );
634 /*****************************************************************************
635 * communicate_with_dvd
636 *****************************************************************************/
637 static int communicate_with_dvd( int i_fd,
638 struct cdrom_generic_command *p_cgc )
640 raw_device_command rdc;
641 memset( &rdc, 0, sizeof( rdc ) );
643 /* fill out our raw device command data */
644 rdc.data = p_cgc->buffer;
645 rdc.data_length = p_cgc->buflen;
646 rdc.sense_data = p_cgc->sense;
647 rdc.sense_data_length = 0;
648 rdc.timeout = 1000000;
650 if( p_cgc->data_direction == CGC_DATA_READ )
652 intf_WarnMsg( 2, "css: data_direction == CGC_DATA_READ" );
653 rdc.flags = B_RAW_DEVICE_DATA_IN;
656 rdc.command_length = 12;
657 rdc.command[0] = p_cgc->cmd[0];
658 rdc.command[1] = p_cgc->cmd[1];
659 rdc.command[2] = p_cgc->cmd[2];
660 rdc.command[3] = p_cgc->cmd[3];
661 rdc.command[4] = p_cgc->cmd[4];
662 rdc.command[5] = p_cgc->cmd[5];
663 rdc.command[6] = p_cgc->cmd[6];
664 rdc.command[7] = p_cgc->cmd[7];
665 rdc.command[8] = p_cgc->cmd[8];
666 rdc.command[9] = p_cgc->cmd[9];
667 rdc.command[10] = p_cgc->cmd[10];
668 rdc.command[11] = p_cgc->cmd[11];
669 rdc.command[12] = p_cgc->cmd[12];
671 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );