1 /*****************************************************************************
2 * dvd_ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ioctl.c,v 1.2 2001/02/26 12:16:28 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 /*****************************************************************************
51 * Local prototypes - BeOS specific
52 *****************************************************************************/
53 #if defined( SYS_BEOS )
54 static int ReadData ( int i_fd, dvd_struct *p_dvd );
55 static int ReadCopyright ( int i_fd, dvd_struct *p_dvd );
56 static int ReadKey ( int i_fd, dvd_struct *p_dvd );
57 static int ReadBCA ( int i_fd, dvd_struct *p_dvd );
58 static int ReadManufacturer ( int i_fd, dvd_struct *p_dvd );
60 static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
61 void *buf, int i_len, int i_type );
62 static void InitReadCommand ( struct cdrom_generic_command *p_cgc,
63 unsigned i_agid, unsigned i_type );
64 static void InitWriteCommand ( struct cdrom_generic_command *p_cgc,
65 unsigned i_agid, unsigned i_type );
67 static int SendCommand ( int i_fd, struct cdrom_generic_command *p_cgc );
70 /*****************************************************************************
71 * dvd_ioctl: DVD ioctl() wrapper
72 *****************************************************************************
73 * Since the DVD ioctls do not exist on every machine, we provide this wrapper
74 * so that it becomes easier to port them to any architecture.
75 *****************************************************************************/
76 int dvd_ioctl( int i_fd, unsigned long i_op, void *p_arg )
78 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
79 return( ioctl( i_fd, i_op, p_arg ) );
81 #elif defined( SYS_BEOS )
84 unsigned char buf[20];
86 struct cdrom_generic_command p_cgc;
88 dvd_struct *p_dvd = (dvd_struct *)p_arg;
89 dvd_authinfo *p_authinfo = (dvd_authinfo *)p_arg;
93 case DVD_AUTH: /* Request type is "authentication" */
95 memset( buf, 0, sizeof( buf ) );
96 InitGenericCommand( &p_cgc, buf, 0, CGC_DATA_READ );
98 switch( p_authinfo->type )
100 case DVD_LU_SEND_AGID: /* LU data send */
102 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_AGID" );
104 InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0 );
106 i_ret = SendCommand( i_fd, &p_cgc );
108 p_authinfo->lsa.agid = buf[7] >> 6;
112 case DVD_LU_SEND_KEY1:
114 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY1" );
116 InitReadCommand( &p_cgc, p_authinfo->lsk.agid, 2 );
118 i_ret = SendCommand( i_fd, &p_cgc );
121 memcpy( p_authinfo->lsk.key, &buf[4], sizeof(dvd_key) );
125 case DVD_LU_SEND_CHALLENGE:
127 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
129 InitReadCommand( &p_cgc, p_authinfo->lsc.agid, 1 );
131 i_ret = SendCommand( i_fd, &p_cgc );
133 /* Copy the challenge */
134 memcpy( p_authinfo->lsc.chal, &buf[4],
135 sizeof(dvd_challenge) );
139 case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */
141 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_TITLE_KEY" );
143 InitReadCommand( &p_cgc, p_authinfo->lstk.agid, 4 );
145 p_cgc.cmd[5] = p_authinfo->lstk.lba;
146 p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
147 p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
148 p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
150 i_ret = SendCommand( i_fd, &p_cgc );
152 p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
153 p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
154 p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
157 memcpy( p_authinfo->lstk.title_key, &buf[5],
162 case DVD_LU_SEND_ASF:
164 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_ASF" );
166 InitReadCommand( &p_cgc, p_authinfo->lsasf.agid, 5 );
168 i_ret = SendCommand( i_fd, &p_cgc );
170 p_authinfo->lsasf.asf = buf[7] & 1;
174 case DVD_HOST_SEND_CHALLENGE: /* LU data receive */
176 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
178 InitWriteCommand( &p_cgc, p_authinfo->hsc.agid, 1 );
181 /* Copy the challenge */
182 memcpy( &buf[4], p_authinfo->hsc.chal,
183 sizeof(dvd_challenge) );
185 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
190 p_authinfo->type = DVD_LU_SEND_KEY1;
194 case DVD_HOST_SEND_KEY2:
196 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY2" );
198 InitWriteCommand( &p_cgc, p_authinfo->hsk.agid, 3 );
202 memcpy( &buf[4], p_authinfo->hsk.key, sizeof(dvd_key) );
204 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
206 p_authinfo->type = DVD_AUTH_FAILURE;
210 p_authinfo->type = DVD_AUTH_ESTABLISHED;
214 case DVD_INVALIDATE_AGID: /* Misc */
216 intf_WarnMsg( 2, "css DoAuth: DVD_INVALIDATE_AGID" );
218 InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0x3f );
220 return SendCommand( i_fd, &p_cgc );
222 case DVD_LU_SEND_RPC_STATE: /* Get region settings */
224 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_RPC_STATE "
228 p_dvdetup_report_key( &p_cgc, 0, 8 );
229 memset( &rpc_state, 0, sizeof(rpc_state_t) );
230 p_cgc.buffer = (char *) &rpc_state;
232 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
237 p_authinfo->lrpcs.type = rpc_state.type_code;
238 p_authinfo->lrpcs.vra = rpc_state.vra;
239 p_authinfo->lrpcs.ucca = rpc_state.ucca;
240 p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
241 p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
246 case DVD_HOST_SEND_RPC_STATE: /* Set region settings */
248 intf_WarnMsg( 2, "css DoAuth: DVD_HOST_SEND_RPC_STATE" );
250 InitWriteCommand( &p_cgc, 0, 6 );
252 buf[4] = p_authinfo->hrpcs.pdrc;
254 return SendCommand( i_fd, &p_cgc );
257 intf_ErrMsg( "css DoAuth: invalid DVD key ioctl" );
263 case DVD_READ_STRUCT: /* Request type is "read structure" */
265 switch( p_dvd->type )
267 case DVD_STRUCT_PHYSICAL:
269 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_PHYSICAL" );
271 return ReadData( i_fd, p_dvd );
273 case DVD_STRUCT_COPYRIGHT:
275 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_COPYRIGHT" );
277 return ReadCopyright( i_fd, p_dvd );
279 case DVD_STRUCT_DISCKEY:
281 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_DISCKEY" );
283 return ReadKey( i_fd, p_dvd );
287 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_BCA" );
289 return ReadBCA( i_fd, p_dvd );
291 case DVD_STRUCT_MANUFACT:
293 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_MANUFACT" );
295 return ReadManufacturer( i_fd, p_dvd );
298 intf_WarnMsg( 2, "css ReadStruct: invalid request (%d)",
305 default: /* Unknown request type */
307 intf_ErrMsg( "css error: unknown command 0x%x", i_op );
317 /* Local prototypes */
319 #if defined( SYS_BEOS )
320 /*****************************************************************************
321 * ReadData: Get data structure information from the DVD.
322 *****************************************************************************/
323 static int ReadData( int i_fd, dvd_struct *p_dvd )
326 u_char buf[4 + 4 * 20], *base;
327 struct dvd_layer *layer;
328 struct cdrom_generic_command cgc;
330 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
332 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
333 cgc.cmd[6] = p_dvd->physical.layer_num;
334 cgc.cmd[7] = p_dvd->type;
335 cgc.cmd[9] = cgc.buflen & 0xff;
337 if( (i_ret = SendCommand(i_fd, &cgc)) )
343 layer = &p_dvd->physical.layer[0];
345 /* place the data... really ugly, but at least we won't have to
346 * worry about endianess in userspace or here. */
347 for( i = 0; i < 4; ++i, base += 20, ++layer )
349 memset( layer, 0, sizeof(*layer) );
351 layer->book_version = base[0] & 0xf;
352 layer->book_type = base[0] >> 4;
353 layer->min_rate = base[1] & 0xf;
354 layer->disc_size = base[1] >> 4;
355 layer->layer_type = base[2] & 0xf;
356 layer->track_path = (base[2] >> 4) & 1;
357 layer->nlayers = (base[2] >> 5) & 3;
358 layer->track_density = base[3] & 0xf;
359 layer->linear_density = base[3] >> 4;
360 layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
361 layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
362 layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
363 layer->bca = base[16] >> 7;
369 /*****************************************************************************
370 * ReadCopyright: get copyright information from the DVD.
371 *****************************************************************************/
372 static int ReadCopyright( int i_fd, dvd_struct *p_dvd )
376 struct cdrom_generic_command cgc;
378 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
380 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
381 cgc.cmd[6] = p_dvd->copyright.layer_num;
382 cgc.cmd[7] = p_dvd->type;
383 cgc.cmd[8] = cgc.buflen >> 8;
384 cgc.cmd[9] = cgc.buflen & 0xff;
386 if( (i_ret = SendCommand(i_fd, &cgc)) )
391 p_dvd->copyright.cpst = buf[4];
392 p_dvd->copyright.rmi = buf[5];
397 /*****************************************************************************
398 * ReadKey: get a key from the DVD.
399 *****************************************************************************/
400 static int ReadKey( int i_fd, dvd_struct *p_dvd )
404 struct cdrom_generic_command cgc;
406 size = sizeof( p_dvd->disckey.value ) + 4;
409 if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
414 buf = (u_char *) malloc( size );
416 InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
418 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
419 cgc.cmd[7] = p_dvd->type;
420 cgc.cmd[8] = size >> 8;
421 cgc.cmd[9] = size & 0xff;
422 cgc.cmd[10] = p_dvd->disckey.agid << 6;
424 if( !(i_ret = SendCommand(i_fd, &cgc)) )
426 memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
433 /*****************************************************************************
434 * ReadBCA: read the Burst Cutting Area of a DVD.
435 *****************************************************************************
436 * The BCA is a special part of the DVD which is used to burn additional
437 * data after it has been manufactured. DIVX is an exemple.
438 *****************************************************************************/
439 static int ReadBCA( int i_fd, dvd_struct *p_dvd )
443 struct cdrom_generic_command cgc;
445 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
447 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
448 cgc.cmd[7] = p_dvd->type;
449 cgc.cmd[9] = cgc.buflen = 0xff;
451 if( (i_ret = SendCommand(i_fd, &cgc)) )
456 p_dvd->bca.len = buf[0] << 8 | buf[1];
457 if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
459 intf_ErrMsg( "css error: invalid BCA length (%d)", p_dvd->bca.len );
463 memcpy( p_dvd->bca.value, &buf[4], p_dvd->bca.len );
468 /*****************************************************************************
469 * ReadManufacturer: get manufacturer information from the DVD.
470 *****************************************************************************/
471 static int ReadManufacturer( int i_fd, dvd_struct *p_dvd )
475 struct cdrom_generic_command cgc;
477 size = sizeof( p_dvd->manufact.value ) + 4;
480 if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
485 buf = (u_char *) malloc(size);
487 InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
489 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
490 cgc.cmd[7] = p_dvd->type;
491 cgc.cmd[8] = size >> 8;
492 cgc.cmd[9] = size & 0xff;
494 if( (i_ret = SendCommand(i_fd, &cgc)) )
499 p_dvd->manufact.len = buf[0] << 8 | buf[1];
500 if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
502 intf_ErrMsg( "css error: invalid manufacturer info length (%d)",
508 memcpy( p_dvd->manufact.value, &buf[4], p_dvd->manufact.len );
515 /*****************************************************************************
516 * InitGenericCommand: initialize a CGC structure
517 *****************************************************************************
518 * This function initializes a CDRom Generic Command structure for
519 * future use, either a read command or a write command.
520 *****************************************************************************/
521 static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
522 void *buf, int i_len, int i_type )
524 memset( p_cgc, 0, sizeof( struct cdrom_generic_command ) );
528 memset( buf, 0, i_len );
531 p_cgc->buffer = ( char * )buf;
532 p_cgc->buflen = i_len;
533 p_cgc->data_direction = i_type;
534 p_cgc->timeout = 255;
537 /*****************************************************************************
538 * InitReadCommand: fill a CGC structure for reading purposes.
539 *****************************************************************************
540 * This function fills a CDRom Generic Command for a command which will
541 * read data from the DVD.
542 *****************************************************************************/
543 static void InitReadCommand( struct cdrom_generic_command *p_cgc,
544 unsigned i_agid, unsigned i_type )
546 p_cgc->cmd[0] = GPCMD_REPORT_KEY;
547 p_cgc->cmd[10] = i_type | (i_agid << 6);
549 /* FIXME: check what i_type means */
568 p_cgc->cmd[9] = p_cgc->buflen;
569 p_cgc->data_direction = CGC_DATA_READ;
572 /*****************************************************************************
573 * InitWriteCommand: fill a CGC structure for writing purposes.
574 *****************************************************************************
575 * This function fills a CDRom Generic Command for a command which will
576 * send data to the DVD.
577 *****************************************************************************/
578 static void InitWriteCommand( struct cdrom_generic_command *p_cgc,
579 unsigned i_agid, unsigned i_type )
581 p_cgc->cmd[0] = GPCMD_SEND_KEY;
582 p_cgc->cmd[10] = i_type | (i_agid << 6);
584 /* FIXME: check what i_type means */
600 p_cgc->cmd[9] = p_cgc->buflen;
601 p_cgc->data_direction = CGC_DATA_WRITE;
604 /*****************************************************************************
605 * SendCommand: send a raw device command to the DVD drive.
606 *****************************************************************************
607 * This is the most important part of the ioctl emulation, the place where
608 * data is really sent to the DVD.
609 *****************************************************************************/
610 static int SendCommand( int i_fd, struct cdrom_generic_command *p_cgc )
614 raw_device_command rdc;
615 memset( &rdc, 0, sizeof( rdc ) );
617 /* fill out our raw device command data */
618 rdc.data = p_cgc->buffer;
619 rdc.data_length = p_cgc->buflen;
620 rdc.sense_data = p_cgc->sense;
621 rdc.sense_data_length = 0;
622 rdc.timeout = 1000000;
624 if( p_cgc->data_direction == CGC_DATA_READ )
626 intf_WarnMsg( 2, "css: data_direction == CGC_DATA_READ" );
627 rdc.flags = B_RAW_DEVICE_DATA_IN;
630 rdc.command_length = 12;
632 /* FIXME: check if this _really_ should go up to [12] */
633 for( i = 0 ; i < 13 ; i++ )
635 rdc.command[i] = p_cgc->cmd[i];
638 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );