1 /*****************************************************************************
2 * dvd_ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: dvd_ioctl.c,v 1.3 2001/03/05 11:53:44 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 <sys/types.h>
31 #include <netinet/in.h>
32 #ifdef HAVE_SYS_IOCTL_H
33 # include <sys/ioctl.h>
35 #ifdef HAVE_SYS_DVDIO_H
36 # include <sys/dvdio.h>
39 # include <linux/cdrom.h>
49 #include "dvd_ioctl.h"
51 /*****************************************************************************
52 * Local prototypes - BeOS specific
53 *****************************************************************************/
54 #if defined( SYS_BEOS )
55 static int ReadData ( int i_fd, dvd_struct *p_dvd );
56 static int ReadCopyright ( int i_fd, dvd_struct *p_dvd );
57 static int ReadKey ( int i_fd, dvd_struct *p_dvd );
58 static int ReadBCA ( int i_fd, dvd_struct *p_dvd );
59 static int ReadManufacturer ( int i_fd, dvd_struct *p_dvd );
61 static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
62 void *buf, int i_len, int i_type );
63 static void InitReadCommand ( struct cdrom_generic_command *p_cgc,
64 unsigned i_agid, unsigned i_type );
65 static void InitWriteCommand ( struct cdrom_generic_command *p_cgc,
66 unsigned i_agid, unsigned i_type );
68 static int SendCommand ( int i_fd, struct cdrom_generic_command *p_cgc );
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 )
85 unsigned char buf[20];
87 struct cdrom_generic_command p_cgc;
89 dvd_struct *p_dvd = (dvd_struct *)p_arg;
90 dvd_authinfo *p_authinfo = (dvd_authinfo *)p_arg;
94 case DVD_AUTH: /* Request type is "authentication" */
96 memset( buf, 0, sizeof( buf ) );
97 InitGenericCommand( &p_cgc, buf, 0, CGC_DATA_READ );
99 switch( p_authinfo->type )
101 case DVD_LU_SEND_AGID: /* LU data send */
103 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_AGID" );
105 InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0 );
107 i_ret = SendCommand( i_fd, &p_cgc );
109 p_authinfo->lsa.agid = buf[7] >> 6;
113 case DVD_LU_SEND_KEY1:
115 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY1" );
117 InitReadCommand( &p_cgc, p_authinfo->lsk.agid, 2 );
119 i_ret = SendCommand( i_fd, &p_cgc );
122 memcpy( p_authinfo->lsk.key, &buf[4], sizeof(dvd_key) );
126 case DVD_LU_SEND_CHALLENGE:
128 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
130 InitReadCommand( &p_cgc, p_authinfo->lsc.agid, 1 );
132 i_ret = SendCommand( i_fd, &p_cgc );
134 /* Copy the challenge */
135 memcpy( p_authinfo->lsc.chal, &buf[4],
136 sizeof(dvd_challenge) );
140 case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */
142 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_TITLE_KEY" );
144 InitReadCommand( &p_cgc, p_authinfo->lstk.agid, 4 );
146 p_cgc.cmd[5] = p_authinfo->lstk.lba;
147 p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
148 p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
149 p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
151 i_ret = SendCommand( i_fd, &p_cgc );
153 p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
154 p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
155 p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
158 memcpy( p_authinfo->lstk.title_key, &buf[5],
163 case DVD_LU_SEND_ASF:
165 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_ASF" );
167 InitReadCommand( &p_cgc, p_authinfo->lsasf.agid, 5 );
169 i_ret = SendCommand( i_fd, &p_cgc );
171 p_authinfo->lsasf.asf = buf[7] & 1;
175 case DVD_HOST_SEND_CHALLENGE: /* LU data receive */
177 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
179 InitWriteCommand( &p_cgc, p_authinfo->hsc.agid, 1 );
182 /* Copy the challenge */
183 memcpy( &buf[4], p_authinfo->hsc.chal,
184 sizeof(dvd_challenge) );
186 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
191 p_authinfo->type = DVD_LU_SEND_KEY1;
195 case DVD_HOST_SEND_KEY2:
197 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY2" );
199 InitWriteCommand( &p_cgc, p_authinfo->hsk.agid, 3 );
203 memcpy( &buf[4], p_authinfo->hsk.key, sizeof(dvd_key) );
205 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
207 p_authinfo->type = DVD_AUTH_FAILURE;
211 p_authinfo->type = DVD_AUTH_ESTABLISHED;
215 case DVD_INVALIDATE_AGID: /* Misc */
217 intf_WarnMsg( 2, "css DoAuth: DVD_INVALIDATE_AGID" );
219 InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0x3f );
221 return SendCommand( i_fd, &p_cgc );
223 case DVD_LU_SEND_RPC_STATE: /* Get region settings */
225 intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_RPC_STATE "
229 p_dvdetup_report_key( &p_cgc, 0, 8 );
230 memset( &rpc_state, 0, sizeof(rpc_state_t) );
231 p_cgc.buffer = (char *) &rpc_state;
233 if( (i_ret = SendCommand(i_fd, &p_cgc)) )
238 p_authinfo->lrpcs.type = rpc_state.type_code;
239 p_authinfo->lrpcs.vra = rpc_state.vra;
240 p_authinfo->lrpcs.ucca = rpc_state.ucca;
241 p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
242 p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
247 case DVD_HOST_SEND_RPC_STATE: /* Set region settings */
249 intf_WarnMsg( 2, "css DoAuth: DVD_HOST_SEND_RPC_STATE" );
251 InitWriteCommand( &p_cgc, 0, 6 );
253 buf[4] = p_authinfo->hrpcs.pdrc;
255 return SendCommand( i_fd, &p_cgc );
258 intf_ErrMsg( "css DoAuth: invalid DVD key ioctl" );
264 case DVD_READ_STRUCT: /* Request type is "read structure" */
266 switch( p_dvd->type )
268 case DVD_STRUCT_PHYSICAL:
270 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_PHYSICAL" );
272 return ReadData( i_fd, p_dvd );
274 case DVD_STRUCT_COPYRIGHT:
276 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_COPYRIGHT" );
278 return ReadCopyright( i_fd, p_dvd );
280 case DVD_STRUCT_DISCKEY:
282 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_DISCKEY" );
284 return ReadKey( i_fd, p_dvd );
288 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_BCA" );
290 return ReadBCA( i_fd, p_dvd );
292 case DVD_STRUCT_MANUFACT:
294 intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_MANUFACT" );
296 return ReadManufacturer( i_fd, p_dvd );
299 intf_WarnMsg( 2, "css ReadStruct: invalid request (%d)",
306 default: /* Unknown request type */
308 intf_ErrMsg( "css error: unknown command 0x%x", i_op );
318 /* Local prototypes */
320 #if defined( SYS_BEOS )
321 /*****************************************************************************
322 * ReadData: Get data structure information from the DVD.
323 *****************************************************************************/
324 static int ReadData( int i_fd, dvd_struct *p_dvd )
327 u_char buf[4 + 4 * 20], *base;
328 struct dvd_layer *layer;
329 struct cdrom_generic_command cgc;
331 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
333 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
334 cgc.cmd[6] = p_dvd->physical.layer_num;
335 cgc.cmd[7] = p_dvd->type;
336 cgc.cmd[9] = cgc.buflen & 0xff;
338 if( (i_ret = SendCommand(i_fd, &cgc)) )
344 layer = &p_dvd->physical.layer[0];
346 /* place the data... really ugly, but at least we won't have to
347 * worry about endianess in userspace or here. */
348 for( i = 0; i < 4; ++i, base += 20, ++layer )
350 memset( layer, 0, sizeof(*layer) );
352 layer->book_version = base[0] & 0xf;
353 layer->book_type = base[0] >> 4;
354 layer->min_rate = base[1] & 0xf;
355 layer->disc_size = base[1] >> 4;
356 layer->layer_type = base[2] & 0xf;
357 layer->track_path = (base[2] >> 4) & 1;
358 layer->nlayers = (base[2] >> 5) & 3;
359 layer->track_density = base[3] & 0xf;
360 layer->linear_density = base[3] >> 4;
361 layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
362 layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
363 layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
364 layer->bca = base[16] >> 7;
370 /*****************************************************************************
371 * ReadCopyright: get copyright information from the DVD.
372 *****************************************************************************/
373 static int ReadCopyright( int i_fd, dvd_struct *p_dvd )
377 struct cdrom_generic_command cgc;
379 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
381 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
382 cgc.cmd[6] = p_dvd->copyright.layer_num;
383 cgc.cmd[7] = p_dvd->type;
384 cgc.cmd[8] = cgc.buflen >> 8;
385 cgc.cmd[9] = cgc.buflen & 0xff;
387 if( (i_ret = SendCommand(i_fd, &cgc)) )
392 p_dvd->copyright.cpst = buf[4];
393 p_dvd->copyright.rmi = buf[5];
398 /*****************************************************************************
399 * ReadKey: get a key from the DVD.
400 *****************************************************************************/
401 static int ReadKey( int i_fd, dvd_struct *p_dvd )
405 struct cdrom_generic_command cgc;
407 size = sizeof( p_dvd->disckey.value ) + 4;
410 if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
415 buf = (u_char *) malloc( size );
417 InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
419 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
420 cgc.cmd[7] = p_dvd->type;
421 cgc.cmd[8] = size >> 8;
422 cgc.cmd[9] = size & 0xff;
423 cgc.cmd[10] = p_dvd->disckey.agid << 6;
425 if( !(i_ret = SendCommand(i_fd, &cgc)) )
427 memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
434 /*****************************************************************************
435 * ReadBCA: read the Burst Cutting Area of a DVD.
436 *****************************************************************************
437 * The BCA is a special part of the DVD which is used to burn additional
438 * data after it has been manufactured. DIVX is an exemple.
439 *****************************************************************************/
440 static int ReadBCA( int i_fd, dvd_struct *p_dvd )
444 struct cdrom_generic_command cgc;
446 InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
448 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
449 cgc.cmd[7] = p_dvd->type;
450 cgc.cmd[9] = cgc.buflen = 0xff;
452 if( (i_ret = SendCommand(i_fd, &cgc)) )
457 p_dvd->bca.len = buf[0] << 8 | buf[1];
458 if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
460 intf_ErrMsg( "css error: invalid BCA length (%d)", p_dvd->bca.len );
464 memcpy( p_dvd->bca.value, &buf[4], p_dvd->bca.len );
469 /*****************************************************************************
470 * ReadManufacturer: get manufacturer information from the DVD.
471 *****************************************************************************/
472 static int ReadManufacturer( int i_fd, dvd_struct *p_dvd )
476 struct cdrom_generic_command cgc;
478 size = sizeof( p_dvd->manufact.value ) + 4;
481 if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
486 buf = (u_char *) malloc(size);
488 InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
490 cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
491 cgc.cmd[7] = p_dvd->type;
492 cgc.cmd[8] = size >> 8;
493 cgc.cmd[9] = size & 0xff;
495 if( (i_ret = SendCommand(i_fd, &cgc)) )
500 p_dvd->manufact.len = buf[0] << 8 | buf[1];
501 if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
503 intf_ErrMsg( "css error: invalid manufacturer info length (%d)",
509 memcpy( p_dvd->manufact.value, &buf[4], p_dvd->manufact.len );
516 /*****************************************************************************
517 * InitGenericCommand: initialize a CGC structure
518 *****************************************************************************
519 * This function initializes a CDRom Generic Command structure for
520 * future use, either a read command or a write command.
521 *****************************************************************************/
522 static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
523 void *buf, int i_len, int i_type )
525 memset( p_cgc, 0, sizeof( struct cdrom_generic_command ) );
529 memset( buf, 0, i_len );
532 p_cgc->buffer = ( char * )buf;
533 p_cgc->buflen = i_len;
534 p_cgc->data_direction = i_type;
535 p_cgc->timeout = 255;
538 /*****************************************************************************
539 * InitReadCommand: fill a CGC structure for reading purposes.
540 *****************************************************************************
541 * This function fills a CDRom Generic Command for a command which will
542 * read data from the DVD.
543 *****************************************************************************/
544 static void InitReadCommand( struct cdrom_generic_command *p_cgc,
545 unsigned i_agid, unsigned i_type )
547 p_cgc->cmd[0] = GPCMD_REPORT_KEY;
548 p_cgc->cmd[10] = i_type | (i_agid << 6);
550 /* FIXME: check what i_type means */
569 p_cgc->cmd[9] = p_cgc->buflen;
570 p_cgc->data_direction = CGC_DATA_READ;
573 /*****************************************************************************
574 * InitWriteCommand: fill a CGC structure for writing purposes.
575 *****************************************************************************
576 * This function fills a CDRom Generic Command for a command which will
577 * send data to the DVD.
578 *****************************************************************************/
579 static void InitWriteCommand( struct cdrom_generic_command *p_cgc,
580 unsigned i_agid, unsigned i_type )
582 p_cgc->cmd[0] = GPCMD_SEND_KEY;
583 p_cgc->cmd[10] = i_type | (i_agid << 6);
585 /* FIXME: check what i_type means */
601 p_cgc->cmd[9] = p_cgc->buflen;
602 p_cgc->data_direction = CGC_DATA_WRITE;
605 /*****************************************************************************
606 * SendCommand: send a raw device command to the DVD drive.
607 *****************************************************************************
608 * This is the most important part of the ioctl emulation, the place where
609 * data is really sent to the DVD.
610 *****************************************************************************/
611 static int SendCommand( int i_fd, struct cdrom_generic_command *p_cgc )
615 raw_device_command rdc;
616 memset( &rdc, 0, sizeof( rdc ) );
618 /* fill out our raw device command data */
619 rdc.data = p_cgc->buffer;
620 rdc.data_length = p_cgc->buflen;
621 rdc.sense_data = p_cgc->sense;
622 rdc.sense_data_length = 0;
623 rdc.timeout = 1000000;
625 if( p_cgc->data_direction == CGC_DATA_READ )
627 intf_WarnMsg( 2, "css: data_direction == CGC_DATA_READ" );
628 rdc.flags = B_RAW_DEVICE_DATA_IN;
631 rdc.command_length = 12;
633 /* FIXME: check if this _really_ should go up to [12] */
634 for( i = 0 ; i < 13 ; i++ )
636 rdc.command[i] = p_cgc->cmd[i];
639 return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );