1/*
2 * Copyright (c) 2006-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/errno.h>
25#include <sys/proc.h>
26#include <IOKit/storage/IOBDMediaBSDClient.h>
27
28#define super IOMediaBSDClient
29OSDefineMetaClassAndStructors(IOBDMediaBSDClient, IOMediaBSDClient)
30
31typedef struct
32{
33    uint8_t       format;
34
35    uint8_t       reserved0008[3];
36
37    uint32_t      address;
38    uint8_t       grantID;
39    uint8_t       layer;
40
41    uint8_t       reserved0080[4];
42
43    uint16_t      bufferLength;
44    user32_addr_t buffer;
45} dk_bd_read_structure_32_t;
46
47typedef struct
48{
49    uint8_t       format;
50
51    uint8_t       reserved0008[3];
52
53    uint32_t      address;
54    uint8_t       grantID;
55    uint8_t       layer;
56
57    uint8_t       reserved0080[4];
58
59    uint16_t      bufferLength;
60    user64_addr_t buffer;
61} dk_bd_read_structure_64_t;
62
63typedef struct
64{
65    uint8_t       format;
66    uint8_t       keyClass;
67
68    uint8_t       reserved0016[2];
69
70    uint32_t      address;
71    uint8_t       grantID;
72
73    uint8_t       reserved0072[5];
74
75    uint16_t      bufferLength;
76    user32_addr_t buffer;
77} dk_bd_report_key_32_t;
78
79typedef struct
80{
81    uint8_t       format;
82    uint8_t       keyClass;
83
84    uint8_t       reserved0016[2];
85
86    uint32_t      address;
87    uint8_t       grantID;
88
89    uint8_t       reserved0072[5];
90
91    uint16_t      bufferLength;
92    user64_addr_t buffer;
93} dk_bd_report_key_64_t;
94
95typedef struct
96{
97    uint8_t       format;
98    uint8_t       keyClass;
99
100    uint8_t       reserved0016[6];
101
102    uint8_t       grantID;
103
104    uint8_t       reserved0072[5];
105
106    uint16_t      bufferLength;
107    user32_addr_t buffer;
108} dk_bd_send_key_32_t;
109
110typedef struct
111{
112    uint8_t       format;
113    uint8_t       keyClass;
114
115    uint8_t       reserved0016[6];
116
117    uint8_t       grantID;
118
119    uint8_t       reserved0072[5];
120
121    uint16_t      bufferLength;
122    user64_addr_t buffer;
123} dk_bd_send_key_64_t;
124
125typedef struct
126{
127    uint8_t       reserved0000[14];
128
129    uint16_t      bufferLength;
130    user32_addr_t buffer;
131} dk_bd_read_disc_info_32_t;
132
133typedef struct
134{
135    uint8_t       reserved0000[14];
136
137    uint16_t      bufferLength;
138    user64_addr_t buffer;
139} dk_bd_read_disc_info_64_t;
140
141typedef struct
142{
143    uint8_t       reserved0000[4];
144
145    uint32_t      address;
146    uint8_t       addressType;
147
148    uint8_t       reserved0072[5];
149
150    uint16_t      bufferLength;
151    user32_addr_t buffer;
152} dk_bd_read_track_info_32_t;
153
154typedef struct
155{
156    uint8_t       reserved0000[4];
157
158    uint32_t      address;
159    uint8_t       addressType;
160
161    uint8_t       reserved0072[5];
162
163    uint16_t      bufferLength;
164    user64_addr_t buffer;
165} dk_bd_read_track_info_64_t;
166
167#define DKIOCBDREADSTRUCTURE32   _IOW('d', 160, dk_bd_read_structure_32_t)
168#define DKIOCBDREADSTRUCTURE64   _IOW('d', 160, dk_bd_read_structure_64_t)
169#define DKIOCBDREPORTKEY32       _IOW('d', 161, dk_bd_report_key_32_t)
170#define DKIOCBDREPORTKEY64       _IOW('d', 161, dk_bd_report_key_64_t)
171#define DKIOCBDSENDKEY32         _IOW('d', 162, dk_bd_send_key_32_t)
172#define DKIOCBDSENDKEY64         _IOW('d', 162, dk_bd_send_key_64_t)
173
174#define DKIOCBDREADDISCINFO32    _IOWR('d', 164, dk_bd_read_disc_info_32_t)
175#define DKIOCBDREADDISCINFO64    _IOWR('d', 164, dk_bd_read_disc_info_64_t)
176#define DKIOCBDREADTRACKINFO32   _IOWR('d', 165, dk_bd_read_track_info_32_t)
177#define DKIOCBDREADTRACKINFO64   _IOWR('d', 165, dk_bd_read_track_info_64_t)
178
179static bool DKIOC_IS_RESERVED(caddr_t data, uint32_t reserved)
180{
181    UInt32 index;
182
183    for ( index = 0; index < sizeof(reserved) * 8; index++, reserved >>= 1 )
184    {
185        if ( (reserved & 1) )
186        {
187            if ( data[index] )  return true;
188        }
189    }
190
191    return false;
192}
193
194static IOMemoryDescriptor * DKIOC_PREPARE_BUFFER( user_addr_t address,
195                                                  UInt32      length,
196                                                  IODirection direction,
197                                                  proc_t      proc )
198{
199    IOMemoryDescriptor * buffer = 0;
200
201    if ( address && length )
202    {
203        buffer = IOMemoryDescriptor::withAddressRange(    // (create the buffer)
204            /* address */ address,
205            /* length  */ length,
206            /* options */ direction,
207            /* task    */ (proc == kernproc) ? kernel_task : current_task() );
208    }
209
210    if ( buffer )
211    {
212        if ( buffer->prepare() != kIOReturnSuccess )     // (prepare the buffer)
213        {
214            buffer->release();
215            buffer = 0;
216        }
217    }
218
219    return buffer;
220}
221
222static void DKIOC_COMPLETE_BUFFER(IOMemoryDescriptor * buffer)
223{
224    if ( buffer )
225    {
226        buffer->complete();                             // (complete the buffer)
227        buffer->release();                               // (release the buffer)
228    }
229}
230
231IOBDMedia * IOBDMediaBSDClient::getProvider() const
232{
233    //
234    // Obtain this object's provider.  We override the superclass's method
235    // to return a more specific subclass of IOService -- IOBDMedia.  This
236    // method serves simply as a convenience to subclass developers.
237    //
238
239    return (IOBDMedia *) IOService::getProvider();
240}
241
242int IOBDMediaBSDClient::ioctl( dev_t   dev,
243                               u_long  cmd,
244                               caddr_t data,
245                               int     flags,
246                               proc_t  proc )
247{
248    //
249    // Process a BD-specific ioctl.
250    //
251
252    IOMemoryDescriptor * buffer = 0;
253    int                  error  = 0;
254    IOReturn             status = kIOReturnSuccess;
255
256    switch ( cmd )
257    {
258        case DKIOCBDREADSTRUCTURE32:            // (dk_bd_read_structure_32_t *)
259        {
260            dk_bd_read_structure_32_t * request;
261
262            request = (dk_bd_read_structure_32_t *) data;
263
264            if ( proc_is64bit(proc) )  { error = ENOTTY;  break; }
265
266            if ( DKIOC_IS_RESERVED(data, 0x3C0E) )  { error = EINVAL;  break; }
267
268            buffer = DKIOC_PREPARE_BUFFER(
269                       /* address   */ CAST_USER_ADDR_T(request->buffer),
270                       /* length    */ request->bufferLength,
271                       /* direction */ kIODirectionIn,
272                       /* proc      */ proc );
273
274            status = getProvider()->readStructure(
275                       /* buffer    */ buffer,
276                       /* format    */ request->format,
277                       /* address   */ request->address,
278                       /* layer     */ request->layer,
279                       /* grantID   */ request->grantID );
280
281            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
282
283            DKIOC_COMPLETE_BUFFER(buffer);
284
285        } break;
286
287        case DKIOCBDREADSTRUCTURE64:            // (dk_bd_read_structure_64_t *)
288        {
289            dk_bd_read_structure_64_t * request;
290
291            request = (dk_bd_read_structure_64_t *) data;
292
293            if ( proc_is64bit(proc) == 0 )  { error = ENOTTY;  break; }
294
295            if ( DKIOC_IS_RESERVED(data, 0x3C0E) )  { error = EINVAL;  break; }
296
297            buffer = DKIOC_PREPARE_BUFFER(
298                       /* address   */ request->buffer,
299                       /* length    */ request->bufferLength,
300                       /* direction */ kIODirectionIn,
301                       /* proc      */ proc );
302
303            status = getProvider()->readStructure(
304                       /* buffer    */ buffer,
305                       /* format    */ request->format,
306                       /* address   */ request->address,
307                       /* layer     */ request->layer,
308                       /* grantID   */ request->grantID );
309
310            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
311
312            DKIOC_COMPLETE_BUFFER(buffer);
313
314        } break;
315
316        case DKIOCBDREPORTKEY32:                    // (dk_bd_report_key_32_t *)
317        {
318            dk_bd_report_key_32_t * request = (dk_bd_report_key_32_t *) data;
319
320            if ( proc_is64bit(proc) )  { error = ENOTTY;  break; }
321
322            if ( DKIOC_IS_RESERVED(data, 0x3E0C) )  { error = EINVAL;  break; }
323
324            buffer = DKIOC_PREPARE_BUFFER(
325                       /* address   */ CAST_USER_ADDR_T(request->buffer),
326                       /* length    */ request->bufferLength,
327                       /* direction */ kIODirectionIn,
328                       /* proc      */ proc );
329
330            status = getProvider()->reportKey(
331                       /* buffer    */ buffer,
332                       /* keyClass  */ request->keyClass,
333                       /* address   */ request->address,
334                       /* grantID   */ request->grantID,
335                       /* format    */ request->format );
336
337            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
338
339            DKIOC_COMPLETE_BUFFER(buffer);
340
341        } break;
342
343        case DKIOCBDREPORTKEY64:                    // (dk_bd_report_key_64_t *)
344        {
345            dk_bd_report_key_64_t * request = (dk_bd_report_key_64_t *) data;
346
347            if ( proc_is64bit(proc) == 0 )  { error = ENOTTY;  break; }
348
349            if ( DKIOC_IS_RESERVED(data, 0x3E0C) )  { error = EINVAL;  break; }
350
351            buffer = DKIOC_PREPARE_BUFFER(
352                       /* address   */ request->buffer,
353                       /* length    */ request->bufferLength,
354                       /* direction */ kIODirectionIn,
355                       /* proc      */ proc );
356
357            status = getProvider()->reportKey(
358                       /* buffer    */ buffer,
359                       /* keyClass  */ request->keyClass,
360                       /* address   */ request->address,
361                       /* grantID   */ request->grantID,
362                       /* format    */ request->format );
363
364            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
365
366            DKIOC_COMPLETE_BUFFER(buffer);
367
368        } break;
369
370        case DKIOCBDSENDKEY32:                        // (dk_bd_send_key_32_t *)
371        {
372            dk_bd_send_key_32_t * request = (dk_bd_send_key_32_t *) data;
373
374            if ( proc_is64bit(proc) )  { error = ENOTTY;  break; }
375
376            if ( DKIOC_IS_RESERVED(data, 0x3EFC) )  { error = EINVAL;  break; }
377
378            buffer = DKIOC_PREPARE_BUFFER(
379                       /* address   */ CAST_USER_ADDR_T(request->buffer),
380                       /* length    */ request->bufferLength,
381                       /* direction */ kIODirectionOut,
382                       /* proc      */ proc );
383
384            status = getProvider()->sendKey(
385                       /* buffer    */ buffer,
386                       /* keyClass  */ request->keyClass,
387                       /* grantID   */ request->grantID,
388                       /* format    */ request->format );
389
390            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
391
392            DKIOC_COMPLETE_BUFFER(buffer);
393
394        } break;
395
396        case DKIOCBDSENDKEY64:                        // (dk_bd_send_key_64_t *)
397        {
398            dk_bd_send_key_64_t * request = (dk_bd_send_key_64_t *) data;
399
400            if ( proc_is64bit(proc) == 0 )  { error = ENOTTY;  break; }
401
402            if ( DKIOC_IS_RESERVED(data, 0x3EFC) )  { error = EINVAL;  break; }
403
404            buffer = DKIOC_PREPARE_BUFFER(
405                       /* address   */ request->buffer,
406                       /* length    */ request->bufferLength,
407                       /* direction */ kIODirectionOut,
408                       /* proc      */ proc );
409
410            status = getProvider()->sendKey(
411                       /* buffer    */ buffer,
412                       /* keyClass  */ request->keyClass,
413                       /* grantID   */ request->grantID,
414                       /* format    */ request->format );
415
416            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
417
418            DKIOC_COMPLETE_BUFFER(buffer);
419
420        } break;
421
422        case DKIOCBDGETSPEED:                                    // (uint16_t *)
423        {
424            status = getProvider()->getSpeed((uint16_t *)data);
425
426        } break;
427
428        case DKIOCBDSETSPEED:                                    // (uint16_t *)
429        {
430            status = getProvider()->setSpeed(*(uint16_t *)data);
431
432        } break;
433
434        case DKIOCBDREADDISCINFO32:             // (dk_bd_read_disc_info_32_t *)
435        {
436            dk_bd_read_disc_info_32_t * request;
437
438            request = (dk_bd_read_disc_info_32_t *) data;
439
440            if ( proc_is64bit(proc) )  { error = ENOTTY;  break; }
441
442            if ( DKIOC_IS_RESERVED(data, 0x3FFF) )  { error = EINVAL;  break; }
443
444            buffer = DKIOC_PREPARE_BUFFER(
445                       /* address   */ CAST_USER_ADDR_T(request->buffer),
446                       /* length    */ request->bufferLength,
447                       /* direction */ kIODirectionIn,
448                       /* proc      */ proc );
449
450            status = getProvider()->readDiscInfo(
451                       /* buffer          */ buffer,
452                       /* type            */ 0,
453                       /* actualByteCount */ &request->bufferLength );
454
455            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
456
457            DKIOC_COMPLETE_BUFFER(buffer);
458
459        } break;
460
461        case DKIOCBDREADDISCINFO64:             // (dk_bd_read_disc_info_64_t *)
462        {
463            dk_bd_read_disc_info_64_t * request;
464
465            request = (dk_bd_read_disc_info_64_t *) data;
466
467            if ( proc_is64bit(proc) == 0 )  { error = ENOTTY;  break; }
468
469            if ( DKIOC_IS_RESERVED(data, 0x3FFF) )  { error = EINVAL;  break; }
470
471            buffer = DKIOC_PREPARE_BUFFER(
472                       /* address   */ request->buffer,
473                       /* length    */ request->bufferLength,
474                       /* direction */ kIODirectionIn,
475                       /* proc      */ proc );
476
477            status = getProvider()->readDiscInfo(
478                       /* buffer          */ buffer,
479                       /* type            */ 0,
480                       /* actualByteCount */ &request->bufferLength );
481
482            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
483
484            DKIOC_COMPLETE_BUFFER(buffer);
485
486        } break;
487
488        case DKIOCBDREADTRACKINFO32:           // (dk_bd_read_track_info_32_t *)
489        {
490            dk_bd_read_track_info_32_t * request;
491
492            request = (dk_bd_read_track_info_32_t *) data;
493
494            if ( proc_is64bit(proc) )  { error = ENOTTY;  break; }
495
496            if ( DKIOC_IS_RESERVED(data, 0x3E0F) )  { error = EINVAL;  break; }
497
498            buffer = DKIOC_PREPARE_BUFFER(
499                       /* address   */ CAST_USER_ADDR_T(request->buffer),
500                       /* length    */ request->bufferLength,
501                       /* direction */ kIODirectionIn,
502                       /* proc      */ proc );
503
504            status = getProvider()->readTrackInfo(
505                       /* buffer          */ buffer,
506                       /* address         */ request->address,
507                       /* addressType     */ request->addressType,
508                       /* open            */ 0,
509                       /* actualByteCount */ &request->bufferLength );
510
511            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
512
513            DKIOC_COMPLETE_BUFFER(buffer);
514
515        } break;
516
517        case DKIOCBDREADTRACKINFO64:           // (dk_bd_read_track_info_64_t *)
518        {
519            dk_bd_read_track_info_64_t * request;
520
521            request = (dk_bd_read_track_info_64_t *) data;
522
523            if ( proc_is64bit(proc) == 0 )  { error = ENOTTY;  break; }
524
525            if ( DKIOC_IS_RESERVED(data, 0x3E0F) )  { error = EINVAL;  break; }
526
527            buffer = DKIOC_PREPARE_BUFFER(
528                       /* address   */ request->buffer,
529                       /* length    */ request->bufferLength,
530                       /* direction */ kIODirectionIn,
531                       /* proc      */ proc );
532
533            status = getProvider()->readTrackInfo(
534                       /* buffer          */ buffer,
535                       /* address         */ request->address,
536                       /* addressType     */ request->addressType,
537                       /* open            */ 0,
538                       /* actualByteCount */ &request->bufferLength );
539
540            status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status;
541
542            DKIOC_COMPLETE_BUFFER(buffer);
543
544        } break;
545
546        case DKIOCBDSPLITTRACK:                        // splitTrack(uint32_t *)
547        {
548            status = getProvider()->splitTrack(*(uint32_t *)data);
549
550        } break;
551
552        default:
553        {
554            //
555            // A foreign ioctl was received.  Ask our superclass' opinion.
556            //
557
558            error = super::ioctl(dev, cmd, data, flags, proc);
559
560        } break;
561    }
562
563    return error ? error : getProvider()->errnoFromReturn(status);
564}
565
566OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 0);
567OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 1);
568OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 2);
569OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 3);
570OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 4);
571OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 5);
572OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 6);
573OSMetaClassDefineReservedUnused(IOBDMediaBSDClient, 7);
574