1/* 2 * Copyright (c) 1998-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/IOCDMediaBSDClient.h> 27 28#define super IOMediaBSDClient 29OSDefineMetaClassAndStructors(IOCDMediaBSDClient, IOMediaBSDClient) 30 31typedef struct 32{ 33 uint64_t offset; 34 35 uint8_t sectorArea; 36 uint8_t sectorType; 37 38 uint8_t reserved0080[6]; 39 40 uint32_t bufferLength; 41 user32_addr_t buffer; 42} dk_cd_read_32_t; 43 44typedef struct 45{ 46 uint64_t offset; 47 48 uint8_t sectorArea; 49 uint8_t sectorType; 50 51 uint8_t reserved0080[10]; 52 53 uint32_t bufferLength; 54 user64_addr_t buffer; 55} dk_cd_read_64_t; 56 57typedef struct 58{ 59 uint8_t format; 60 uint8_t formatAsTime; 61 62 uint8_t reserved0016[5]; 63 64 union 65 { 66 uint8_t session; 67 uint8_t track; 68 } address; 69 70 uint8_t reserved0064[2]; 71 72 uint16_t bufferLength; 73 user32_addr_t buffer; 74} dk_cd_read_toc_32_t; 75 76typedef struct 77{ 78 uint8_t format; 79 uint8_t formatAsTime; 80 81 uint8_t reserved0016[5]; 82 83 union 84 { 85 uint8_t session; 86 uint8_t track; 87 } address; 88 89 uint8_t reserved0064[6]; 90 91 uint16_t bufferLength; 92 user64_addr_t buffer; 93} dk_cd_read_toc_64_t; 94 95typedef struct 96{ 97 uint8_t reserved0000[10]; 98 99 uint16_t bufferLength; 100 user32_addr_t buffer; 101} dk_cd_read_disc_info_32_t; 102 103typedef struct 104{ 105 uint8_t reserved0000[14]; 106 107 uint16_t bufferLength; 108 user64_addr_t buffer; 109} dk_cd_read_disc_info_64_t; 110 111typedef struct 112{ 113 uint8_t reserved0000[4]; 114 115 uint32_t address; 116 uint8_t addressType; 117 118 uint8_t reserved0072[1]; 119 120 uint16_t bufferLength; 121 user32_addr_t buffer; 122} dk_cd_read_track_info_32_t; 123 124typedef struct 125{ 126 uint8_t reserved0000[4]; 127 128 uint32_t address; 129 uint8_t addressType; 130 131 uint8_t reserved0072[5]; 132 133 uint16_t bufferLength; 134 user64_addr_t buffer; 135} dk_cd_read_track_info_64_t; 136 137#define DKIOCCDREAD32 _IOWR('d', 96, dk_cd_read_32_t) 138#define DKIOCCDREAD64 _IOWR('d', 96, dk_cd_read_64_t) 139 140#define DKIOCCDREADTOC32 _IOWR('d', 100, dk_cd_read_toc_32_t) 141#define DKIOCCDREADTOC64 _IOWR('d', 100, dk_cd_read_toc_64_t) 142 143#define DKIOCCDREADDISCINFO32 _IOWR('d', 101, dk_cd_read_disc_info_32_t) 144#define DKIOCCDREADDISCINFO64 _IOWR('d', 101, dk_cd_read_disc_info_64_t) 145#define DKIOCCDREADTRACKINFO32 _IOWR('d', 102, dk_cd_read_track_info_32_t) 146#define DKIOCCDREADTRACKINFO64 _IOWR('d', 102, dk_cd_read_track_info_64_t) 147 148static bool DKIOC_IS_RESERVED(caddr_t data, uint32_t reserved) 149{ 150 UInt32 index; 151 152 for ( index = 0; index < sizeof(reserved) * 8; index++, reserved >>= 1 ) 153 { 154 if ( (reserved & 1) ) 155 { 156 if ( data[index] ) return true; 157 } 158 } 159 160 return false; 161} 162 163static IOMemoryDescriptor * DKIOC_PREPARE_BUFFER( user_addr_t address, 164 UInt32 length, 165 IODirection direction, 166 proc_t proc ) 167{ 168 IOMemoryDescriptor * buffer = 0; 169 170 if ( address && length ) 171 { 172 buffer = IOMemoryDescriptor::withAddressRange( // (create the buffer) 173 /* address */ address, 174 /* length */ length, 175 /* options */ direction, 176 /* task */ (proc == kernproc) ? kernel_task : current_task() ); 177 } 178 179 if ( buffer ) 180 { 181 if ( buffer->prepare() != kIOReturnSuccess ) // (prepare the buffer) 182 { 183 buffer->release(); 184 buffer = 0; 185 } 186 } 187 188 return buffer; 189} 190 191static void DKIOC_COMPLETE_BUFFER(IOMemoryDescriptor * buffer) 192{ 193 if ( buffer ) 194 { 195 buffer->complete(); // (complete the buffer) 196 buffer->release(); // (release the buffer) 197 } 198} 199 200IOCDMedia * IOCDMediaBSDClient::getProvider() const 201{ 202 // 203 // Obtain this object's provider. We override the superclass's method 204 // to return a more specific subclass of IOService -- IOCDMedia. This 205 // method serves simply as a convenience to subclass developers. 206 // 207 208 return (IOCDMedia *) IOService::getProvider(); 209} 210 211int IOCDMediaBSDClient::ioctl( dev_t dev, 212 u_long cmd, 213 caddr_t data, 214 int flags, 215 proc_t proc ) 216{ 217 // 218 // Process a CD-specific ioctl. 219 // 220 221 IOMemoryDescriptor * buffer = 0; 222 int error = 0; 223 IOReturn status = kIOReturnSuccess; 224 225 switch ( cmd ) 226 { 227 case DKIOCCDREAD32: // (dk_cd_read_32_t *) 228 { 229 UInt64 actualByteCount = 0; 230 dk_cd_read_32_t * request = (dk_cd_read_32_t *) data; 231 232 if ( proc_is64bit(proc) ) { error = ENOTTY; break; } 233 234 if ( DKIOC_IS_RESERVED(data, 0xFC00) ) { error = EINVAL; break; } 235 236 buffer = DKIOC_PREPARE_BUFFER( 237 /* address */ request->buffer, 238 /* length */ request->bufferLength, 239 /* direction */ kIODirectionIn, 240 /* proc */ proc ); 241 242 status = getProvider()->readCD( 243 /* client */ this, 244 /* byteStart */ request->offset, 245 /* buffer */ buffer, 246 /* sectorArea */ (CDSectorArea) request->sectorArea, 247 /* sectorType */ (CDSectorType) request->sectorType, 248#ifdef __LP64__ 249 /* attributes */ NULL, 250#endif /* __LP64__ */ 251 /* actualByteCount */ &actualByteCount ); 252 253 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 254 255 request->bufferLength = (UInt32) actualByteCount; 256 257 DKIOC_COMPLETE_BUFFER(buffer); 258 259 } break; 260 261 case DKIOCCDREAD64: // (dk_cd_read_64_t *) 262 { 263 UInt64 actualByteCount = 0; 264 dk_cd_read_64_t * request = (dk_cd_read_64_t *) data; 265 266 if ( proc_is64bit(proc) == 0 ) { error = ENOTTY; break; } 267 268 if ( DKIOC_IS_RESERVED(data, 0xFFC00) ) { error = EINVAL; break; } 269 270 buffer = DKIOC_PREPARE_BUFFER( 271 /* address */ request->buffer, 272 /* length */ request->bufferLength, 273 /* direction */ kIODirectionIn, 274 /* proc */ proc ); 275 276 status = getProvider()->readCD( 277 /* client */ this, 278 /* byteStart */ request->offset, 279 /* buffer */ buffer, 280 /* sectorArea */ (CDSectorArea) request->sectorArea, 281 /* sectorType */ (CDSectorType) request->sectorType, 282#ifdef __LP64__ 283 /* attributes */ NULL, 284#endif /* __LP64__ */ 285 /* actualByteCount */ &actualByteCount ); 286 287 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 288 289 request->bufferLength = (UInt32) actualByteCount; 290 291 DKIOC_COMPLETE_BUFFER(buffer); 292 293 } break; 294 295 case DKIOCCDREADISRC: // (dk_cd_read_isrc_t *) 296 { 297 dk_cd_read_isrc_t * request = (dk_cd_read_isrc_t *) data; 298 299 if ( DKIOC_IS_RESERVED(data, 0xC000) ) { error = EINVAL; break; } 300 301 status = getProvider()->readISRC(request->track, request->isrc); 302 303 } break; 304 305 case DKIOCCDREADMCN: // (dk_cd_read_mcn_t *) 306 { 307 dk_cd_read_mcn_t * request = (dk_cd_read_mcn_t *) data; 308 309 if ( DKIOC_IS_RESERVED(data, 0xC000) ) { error = EINVAL; break; } 310 311 status = getProvider()->readMCN(request->mcn); 312 313 } break; 314 315 case DKIOCCDGETSPEED: // (uint16_t *) 316 { 317 status = getProvider()->getSpeed((uint16_t *)data); 318 319 } break; 320 321 case DKIOCCDSETSPEED: // (uint16_t *) 322 { 323 status = getProvider()->setSpeed(*(uint16_t *)data); 324 325 } break; 326 327 case DKIOCCDREADTOC32: // (dk_cd_read_toc_32_t *) 328 { 329 dk_cd_read_toc_32_t * request = (dk_cd_read_toc_32_t *) data; 330 331 if ( proc_is64bit(proc) ) { error = ENOTTY; break; } 332 333 if ( DKIOC_IS_RESERVED(data, 0x37C) ) { error = EINVAL; break; } 334 335 buffer = DKIOC_PREPARE_BUFFER( 336 /* address */ request->buffer, 337 /* length */ request->bufferLength, 338 /* direction */ kIODirectionIn, 339 /* proc */ proc ); 340 341 status = getProvider()->readTOC( 342 /* buffer */ buffer, 343 /* format */ request->format, 344 /* formatAsTime */ request->formatAsTime, 345 /* address */ request->address.session, 346 /* actualByteCount */ &request->bufferLength ); 347 348 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 349 350 DKIOC_COMPLETE_BUFFER(buffer); 351 352 } break; 353 354 case DKIOCCDREADTOC64: // (dk_cd_read_toc_64_t *) 355 { 356 dk_cd_read_toc_64_t * request = (dk_cd_read_toc_64_t *) data; 357 358 if ( proc_is64bit(proc) == 0 ) { error = ENOTTY; break; } 359 360 if ( DKIOC_IS_RESERVED(data, 0x3F7C) ) { error = EINVAL; break; } 361 362 buffer = DKIOC_PREPARE_BUFFER( 363 /* address */ request->buffer, 364 /* length */ request->bufferLength, 365 /* direction */ kIODirectionIn, 366 /* proc */ proc ); 367 368 status = getProvider()->readTOC( 369 /* buffer */ buffer, 370 /* format */ request->format, 371 /* formatAsTime */ request->formatAsTime, 372 /* address */ request->address.session, 373 /* actualByteCount */ &request->bufferLength ); 374 375 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 376 377 DKIOC_COMPLETE_BUFFER(buffer); 378 379 } break; 380 381 case DKIOCCDREADDISCINFO32: // (dk_cd_read_disc_info_32_t *) 382 { 383 dk_cd_read_disc_info_32_t * request; 384 385 request = (dk_cd_read_disc_info_32_t *) data; 386 387 if ( proc_is64bit(proc) ) { error = ENOTTY; break; } 388 389 if ( DKIOC_IS_RESERVED(data, 0x3FF) ) { error = EINVAL; break; } 390 391 buffer = DKIOC_PREPARE_BUFFER( 392 /* address */ request->buffer, 393 /* length */ request->bufferLength, 394 /* direction */ kIODirectionIn, 395 /* proc */ proc ); 396 397 status = getProvider()->readDiscInfo( 398 /* buffer */ buffer, 399 /* actualByteCount */ &request->bufferLength ); 400 401 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 402 403 DKIOC_COMPLETE_BUFFER(buffer); 404 405 } break; 406 407 case DKIOCCDREADDISCINFO64: // (dk_cd_read_disc_info_64_t *) 408 { 409 dk_cd_read_disc_info_64_t * request; 410 411 request = (dk_cd_read_disc_info_64_t *) data; 412 413 if ( proc_is64bit(proc) == 0 ) { error = ENOTTY; break; } 414 415 if ( DKIOC_IS_RESERVED(data, 0x3FFF) ) { error = EINVAL; break; } 416 417 buffer = DKIOC_PREPARE_BUFFER( 418 /* address */ request->buffer, 419 /* length */ request->bufferLength, 420 /* direction */ kIODirectionIn, 421 /* proc */ proc ); 422 423 status = getProvider()->readDiscInfo( 424 /* buffer */ buffer, 425 /* actualByteCount */ &request->bufferLength ); 426 427 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 428 429 DKIOC_COMPLETE_BUFFER(buffer); 430 431 } break; 432 433 case DKIOCCDREADTRACKINFO32: // (dk_cd_read_track_info_32_t *) 434 { 435 dk_cd_read_track_info_32_t * request; 436 437 request = (dk_cd_read_track_info_32_t *) data; 438 439 if ( proc_is64bit(proc) ) { error = ENOTTY; break; } 440 441 if ( DKIOC_IS_RESERVED(data, 0x20F) ) { error = EINVAL; break; } 442 443 buffer = DKIOC_PREPARE_BUFFER( 444 /* address */ request->buffer, 445 /* length */ request->bufferLength, 446 /* direction */ kIODirectionIn, 447 /* proc */ proc ); 448 449 status = getProvider()->readTrackInfo( 450 /* buffer */ buffer, 451 /* address */ request->address, 452 /* addressType */ request->addressType, 453 /* actualByteCount */ &request->bufferLength ); 454 455 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 456 457 DKIOC_COMPLETE_BUFFER(buffer); 458 459 } break; 460 461 case DKIOCCDREADTRACKINFO64: // (dk_cd_read_track_info_64_t *) 462 { 463 dk_cd_read_track_info_64_t * request; 464 465 request = (dk_cd_read_track_info_64_t *) data; 466 467 if ( proc_is64bit(proc) == 0 ) { error = ENOTTY; break; } 468 469 if ( DKIOC_IS_RESERVED(data, 0x3E0F) ) { 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()->readTrackInfo( 478 /* buffer */ buffer, 479 /* address */ request->address, 480 /* addressType */ request->addressType, 481 /* actualByteCount */ &request->bufferLength ); 482 483 status = (status == kIOReturnUnderrun) ? kIOReturnSuccess : status; 484 485 DKIOC_COMPLETE_BUFFER(buffer); 486 487 } break; 488 489 default: 490 { 491 // 492 // A foreign ioctl was received. Ask our superclass' opinion. 493 // 494 495 error = super::ioctl(dev, cmd, data, flags, proc); 496 497 } break; 498 } 499 500 return error ? error : getProvider()->errnoFromReturn(status); 501} 502 503OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 0); 504OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 1); 505OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 2); 506OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 3); 507OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 4); 508OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 5); 509OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 6); 510OSMetaClassDefineReservedUnused(IOCDMediaBSDClient, 7); 511