]> git.sesse.net Git - vlc/blob - plugins/dvd/dvd_ioctl.c
* Ported Glide and MGA plugins to the new module API. MGA never worked,
[vlc] / plugins / dvd / dvd_ioctl.c
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 $
6  *
7  * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <netinet/in.h>
31 #ifdef HAVE_SYS_IOCTL_H
32 #   include <sys/ioctl.h>
33 #endif
34 #ifdef HAVE_SYS_DVDIO_H
35 #   include <sys/dvdio.h>
36 #endif
37 #ifdef LINUX_DVD
38 #   include <linux/cdrom.h>
39 #endif
40 #ifdef SYS_BEOS
41 #   include <malloc.h>
42 #   include <scsi.h>
43 #endif
44
45 #include "common.h"
46 #include "intf_msg.h"
47
48 #include "dvd_ioctl.h"
49
50 /*****************************************************************************
51  * Local prototypes
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 );
69 #endif
70
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 )
78 {
79 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
80     return( ioctl( i_fd, i_op, p_arg ) );
81
82 #elif defined( SYS_BEOS )
83     switch ( i_op )
84     {
85     case DVD_AUTH:
86         return dvd_do_auth( i_fd, (dvd_authinfo *)p_arg );
87
88     case DVD_READ_STRUCT:
89         return dvd_read_struct( i_fd, (dvd_struct *)p_arg );
90
91     default:
92         intf_ErrMsg( "css error: unknown command 0x%x", i_op );
93         return -1;
94     }
95 #else
96
97     return -1;
98 #endif
99 }
100
101 #if defined( SYS_BEOS )
102
103 /*****************************************************************************
104  * setup_report_key
105  *****************************************************************************/
106 static void setup_report_key( struct cdrom_generic_command *p_cgc,
107                               unsigned i_agid, unsigned i_type )
108 {
109     p_cgc->cmd[0] = GPCMD_REPORT_KEY;
110     p_cgc->cmd[10] = i_type | (i_agid << 6);
111
112     switch( i_type )
113     {
114         case 0:
115         case 8:
116         case 5:
117             p_cgc->buflen = 8;
118             break;
119
120         case 1:
121             p_cgc->buflen = 16;
122             break;
123
124         case 2:
125         case 4:
126             p_cgc->buflen = 12;
127             break;
128     }
129
130     p_cgc->cmd[9] = p_cgc->buflen;
131     p_cgc->data_direction = CGC_DATA_READ;
132 }
133
134 /*****************************************************************************
135  * setup_send_key
136  *****************************************************************************/
137 static void setup_send_key( struct cdrom_generic_command *p_cgc,
138                             unsigned i_agid, unsigned i_type )
139 {
140     p_cgc->cmd[0] = GPCMD_SEND_KEY;
141     p_cgc->cmd[10] = i_type | (i_agid << 6);
142
143     switch( i_type )
144     {
145         case 1:
146             p_cgc->buflen = 16;
147             break;
148
149         case 3:
150             p_cgc->buflen = 12;
151             break;
152
153         case 6:
154             p_cgc->buflen = 8;
155             break;
156     }
157
158     p_cgc->cmd[9] = p_cgc->buflen;
159     p_cgc->data_direction = CGC_DATA_WRITE;
160 }
161
162 /*****************************************************************************
163  * init_cdrom_command
164  *****************************************************************************/
165 static void init_cdrom_command( struct cdrom_generic_command *p_cgc,
166                                 void *buf, int i_len, int i_type )
167 {
168     memset( p_cgc, 0, sizeof(struct cdrom_generic_command) );
169
170     if (buf)
171     {
172         memset( buf, 0, i_len );
173     }
174
175     p_cgc->buffer = (char *) buf;
176     p_cgc->buflen = i_len;
177     p_cgc->data_direction = i_type;
178     p_cgc->timeout = 255;
179 }
180
181 /* DVD handling */
182
183 /*****************************************************************************
184  * dvd_do_auth
185  *****************************************************************************/
186 static int dvd_do_auth( int i_fd, dvd_authinfo *p_authinfo )
187 {
188     int i_ret;
189     unsigned char buf[20];
190     struct cdrom_generic_command p_cgc;
191
192 #define copy_key(dest,src)  memcpy((dest), (src), sizeof(dvd_key))
193 #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
194
195 #if 0
196     struct rpc_state_t rpc_state;
197 #endif
198
199     memset( buf, 0, sizeof(buf) );
200     init_cdrom_command( &p_cgc, buf, 0, CGC_DATA_READ );
201
202     switch (p_authinfo->type)
203     {
204         /* LU data send */
205         case DVD_LU_SEND_AGID:
206
207             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_AGID" );
208
209             setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0);
210
211             /* handle uniform packets for scsi type devices (scsi,atapi) */
212             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
213             {
214                 return i_ret;
215             }
216
217             p_authinfo->lsa.agid = buf[7] >> 6;
218             /* Returning data, let host change state */
219
220             break;
221
222         case DVD_LU_SEND_KEY1:
223
224             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY1" );
225
226             setup_report_key(&p_cgc, p_authinfo->lsk.agid, 2);
227
228             /* handle uniform packets for scsi type devices (scsi,atapi) */
229             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
230             {
231                 return i_ret;
232             }
233
234             copy_key(p_authinfo->lsk.key, &buf[4]);
235             /* Returning data, let host change state */
236
237             break;
238
239         case DVD_LU_SEND_CHALLENGE:
240
241             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
242
243             setup_report_key(&p_cgc, p_authinfo->lsc.agid, 1);
244
245             /* handle uniform packets for scsi type devices (scsi,atapi) */
246             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
247             {
248                 return i_ret;
249             }
250
251             copy_chal(p_authinfo->lsc.chal, &buf[4]);
252             /* Returning data, let host change state */
253
254             break;
255
256         /* Post-auth key */
257         case DVD_LU_SEND_TITLE_KEY:
258
259             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_TITLE_KEY" );
260
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;
266
267             /* handle uniform packets for scsi type devices (scsi,atapi) */
268             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
269             {
270                 return i_ret;
271             }
272
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 */
278
279             break;
280
281         case DVD_LU_SEND_ASF:
282
283             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_ASF" );
284
285             setup_report_key(&p_cgc, p_authinfo->lsasf.agid, 5);
286
287             /* handle uniform packets for scsi type devices (scsi,atapi) */
288             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
289             {
290                 return i_ret;
291             }
292
293             p_authinfo->lsasf.asf = buf[7] & 1;
294
295             break;
296
297         /* LU data receive (LU changes state) */
298         case DVD_HOST_SEND_CHALLENGE:
299
300             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
301
302             setup_send_key(&p_cgc, p_authinfo->hsc.agid, 1);
303             buf[1] = 0xe;
304             copy_chal(&buf[4], p_authinfo->hsc.chal);
305
306             /* handle uniform packets for scsi type devices (scsi,atapi) */
307             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
308             {
309                 return i_ret;
310             }
311
312             p_authinfo->type = DVD_LU_SEND_KEY1;
313
314             break;
315
316         case DVD_HOST_SEND_KEY2:
317
318             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY2" );
319
320             setup_send_key(&p_cgc, p_authinfo->hsk.agid, 3);
321             buf[1] = 0xa;
322             copy_key(&buf[4], p_authinfo->hsk.key);
323
324             /* handle uniform packets for scsi type devices (scsi,atapi) */
325             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
326             {
327                 p_authinfo->type = DVD_AUTH_FAILURE;
328                 return i_ret;
329             }
330             p_authinfo->type = DVD_AUTH_ESTABLISHED;
331
332             break;
333
334         /* Misc */
335         case DVD_INVALIDATE_AGID:
336
337             intf_WarnMsg( 2, "css dvd_do_auth: DVD_INVALIDATE_AGID" );
338
339             setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0x3f);
340
341             /* handle uniform packets for scsi type devices (scsi,atapi) */
342             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
343             {
344                 return i_ret;
345             }
346
347             break;
348
349         /* Get region settings */
350         case DVD_LU_SEND_RPC_STATE:
351
352             intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_RPC_STATE "
353                              "(unimplemented)" );
354
355 #if 0
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;
359
360             /* handle uniform packets for scsi type devices (scsi,atapi) */
361             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
362             {
363                 return i_ret;
364             }
365
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;
371 #endif
372
373             break;
374
375         /* Set region settings */
376         case DVD_HOST_SEND_RPC_STATE:
377
378             intf_WarnMsg( 2, "css dvd_do_auth: DVD_HOST_SEND_RPC_STATE" );
379
380             setup_send_key(&p_cgc, 0, 6);
381             buf[1] = 6;
382             buf[4] = p_authinfo->hrpcs.pdrc;
383
384             /* handle uniform packets for scsi type devices (scsi,atapi) */
385             if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
386             {
387                 return i_ret;
388             }
389
390             break;
391
392         default:
393             intf_ErrMsg( "css dvd_do_auth: invalid DVD key ioctl" );
394             return -1;
395
396     }
397
398     return 0;
399 }
400
401 /*****************************************************************************
402  * dvd_read_struct
403  *****************************************************************************/
404 static int dvd_read_struct( int i_fd, dvd_struct *p_dvd )
405 {
406     switch (p_dvd->type)
407     {
408         case DVD_STRUCT_PHYSICAL:
409
410             intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_PHYSICAL" );
411             return dvd_read_physical(i_fd, p_dvd);
412
413         case DVD_STRUCT_COPYRIGHT:
414
415             intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_COPYRIGHT" );
416             return dvd_read_copyright(i_fd, p_dvd);
417
418         case DVD_STRUCT_DISCKEY:
419
420             intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_DISCKEY" );
421             return dvd_read_disckey(i_fd, p_dvd);
422
423         case DVD_STRUCT_BCA:
424
425             intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_BCA" );
426             return dvd_read_bca(i_fd, p_dvd);
427
428         case DVD_STRUCT_MANUFACT:
429
430             intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_MANUFACT" );
431             return dvd_read_manufact(i_fd, p_dvd);
432
433         default:
434             intf_WarnMsg( 2, "css dvd_read_struct: invalid request (%d)",
435                           p_dvd->type );
436             return -1;
437     }
438 }
439
440 /*****************************************************************************
441  * dvd_read_physical
442  *****************************************************************************/
443 static int dvd_read_physical( int i_fd, dvd_struct *p_dvd )
444 {
445     int i_ret, i;
446     u_char buf[4 + 4 * 20], *base;
447     struct dvd_layer *layer;
448     struct cdrom_generic_command cgc;
449
450     init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
451
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;
456
457     /* handle uniform packets for scsi type devices (scsi,atapi) */
458     if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
459     {
460         return i_ret;
461     }
462
463     base = &buf[4];
464     layer = &p_dvd->physical.layer[0];
465
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 )
469     {
470         memset( layer, 0, sizeof(*layer) );
471
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;
485     }
486
487     return 0;
488 }
489
490 /*****************************************************************************
491  * dvd_read_copyright
492  *****************************************************************************/
493 static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
494 {
495     int i_ret;
496     u_char buf[8];
497     struct cdrom_generic_command cgc;
498
499     init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
500
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;
506
507     /* handle uniform packets for scsi type devices (scsi,atapi) */
508     if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
509     {
510         return i_ret;
511     }
512
513     p_dvd->copyright.cpst = buf[4];
514     p_dvd->copyright.rmi = buf[5];
515
516     return 0;
517 }
518
519 /*****************************************************************************
520  * dvd_read_disckey
521  *****************************************************************************/
522 static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
523 {
524     int i_ret, size;
525     u_char *buf;
526     struct cdrom_generic_command cgc;
527
528     size = sizeof( p_dvd->disckey.value ) + 4;
529
530 #if 0
531     if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)
532     {
533         return -ENOMEM;
534     }
535 #endif
536     buf = (u_char *) malloc(size);
537
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;
544
545     /* handle uniform packets for scsi type devices (scsi,atapi) */
546     if( !(i_ret = communicate_with_dvd(i_fd, &cgc)) )
547     {
548         memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
549     }
550
551     free( buf );
552     return i_ret;
553 }
554
555 /*****************************************************************************
556  * dvd_read_bca
557  *****************************************************************************/
558 static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
559 {
560     int i_ret;
561     u_char buf[4 + 188];
562     struct cdrom_generic_command cgc;
563
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;
568
569     /* handle uniform packets for scsi type devices (scsi,atapi) */
570     if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
571     {
572         return i_ret;
573     }
574
575     p_dvd->bca.len = buf[0] << 8 | buf[1];
576     if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
577     {
578         intf_ErrMsg("css error: invalid BCA length (%d)", p_dvd->bca.len );
579         return -1;
580     }
581
582     memcpy( p_dvd->bca.value, &buf[4], p_dvd->bca.len );
583
584     return 0;
585 }
586
587 /*****************************************************************************
588  * dvd_read_manufact
589  *****************************************************************************/
590 static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
591 {
592     int i_ret = 0, size;
593     u_char *buf;
594     struct cdrom_generic_command cgc;
595
596     size = sizeof(p_dvd->manufact.value) + 4;
597
598 #if 0
599     if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
600     {
601         return -ENOMEM;
602     }
603 #endif
604     buf = (u_char *) malloc(size);
605
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;
611
612     /* handle uniform packets for scsi type devices (scsi,atapi) */
613     if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
614     {
615         return i_ret;
616     }
617
618     p_dvd->manufact.len = buf[0] << 8 | buf[1];
619     if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
620     {
621         intf_ErrMsg( "css error: invalid manufacturer info length "
622                      "(%d)\n", p_dvd->bca.len );
623         i_ret = -1;
624     }
625     else
626     {
627         memcpy( p_dvd->manufact.value, &buf[4], p_dvd->manufact.len );
628     }
629
630     free( buf );
631     return i_ret;
632 }
633
634 /*****************************************************************************
635  * communicate_with_dvd
636  *****************************************************************************/
637 static int communicate_with_dvd( int i_fd,
638                                  struct cdrom_generic_command *p_cgc )
639 {
640     raw_device_command rdc;
641     memset( &rdc, 0, sizeof( rdc ) );
642
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;
649
650     if( p_cgc->data_direction == CGC_DATA_READ )
651     {
652         intf_WarnMsg( 2, "css: data_direction == CGC_DATA_READ" );
653         rdc.flags = B_RAW_DEVICE_DATA_IN;
654     }
655
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];
670
671     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
672 }
673
674 #endif
675