|
|
1.1 ! root 1: #include <linux/kernel.h> ! 2: #include <linux/sched.h> ! 3: #include <linux/mm.h> ! 4: #include <linux/fs.h> ! 5: #include <asm/segment.h> ! 6: #include <linux/errno.h> ! 7: ! 8: #include <linux/blk.h> ! 9: #include "scsi.h" ! 10: #include "hosts.h" ! 11: #include "sr.h" ! 12: #include "scsi_ioctl.h" ! 13: ! 14: #include <linux/cdrom.h> ! 15: ! 16: #define IOCTL_RETRIES 3 ! 17: /* The CDROM is fairly slow, so we need a little extra time */ ! 18: /* In fact, it is very slow if it has to spin up first */ ! 19: #define IOCTL_TIMEOUT 3000 ! 20: ! 21: static void sr_ioctl_done(Scsi_Cmnd * SCpnt) ! 22: { ! 23: struct request * req; ! 24: ! 25: req = &SCpnt->request; ! 26: req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ ! 27: ! 28: if (req->sem != NULL) { ! 29: up(req->sem); ! 30: } ! 31: } ! 32: ! 33: /* We do our own retries because we want to know what the specific ! 34: error code is. Normally the UNIT_ATTENTION code will automatically ! 35: clear after one error */ ! 36: ! 37: static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength) ! 38: { ! 39: Scsi_Cmnd * SCpnt; ! 40: int result; ! 41: ! 42: SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1); ! 43: { ! 44: struct semaphore sem = MUTEX_LOCKED; ! 45: SCpnt->request.sem = &sem; ! 46: scsi_do_cmd(SCpnt, ! 47: (void *) sr_cmd, buffer, buflength, sr_ioctl_done, ! 48: IOCTL_TIMEOUT, IOCTL_RETRIES); ! 49: down(&sem); ! 50: } ! 51: ! 52: result = SCpnt->result; ! 53: ! 54: /* Minimal error checking. Ignore cases we know about, and report the rest. */ ! 55: if(driver_byte(result) != 0) ! 56: switch(SCpnt->sense_buffer[2] & 0xf) { ! 57: case UNIT_ATTENTION: ! 58: scsi_CDs[target].device->changed = 1; ! 59: printk("Disc change detected.\n"); ! 60: break; ! 61: case NOT_READY: /* This happens if there is no disc in drive */ ! 62: printk("CDROM not ready. Make sure there is a disc in the drive.\n"); ! 63: break; ! 64: case ILLEGAL_REQUEST: ! 65: printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n"); ! 66: break; ! 67: default: ! 68: printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", ! 69: scsi_CDs[target].device->host->host_no, ! 70: scsi_CDs[target].device->id, ! 71: scsi_CDs[target].device->lun, ! 72: result); ! 73: printk("\tSense class %x, sense error %x, extended sense %x\n", ! 74: sense_class(SCpnt->sense_buffer[0]), ! 75: sense_error(SCpnt->sense_buffer[0]), ! 76: SCpnt->sense_buffer[2] & 0xf); ! 77: ! 78: }; ! 79: ! 80: result = SCpnt->result; ! 81: SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */ ! 82: wake_up(&SCpnt->device->device_wait); ! 83: /* Wake up a process waiting for device*/ ! 84: return result; ! 85: } ! 86: ! 87: int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) ! 88: { ! 89: u_char sr_cmd[10]; ! 90: ! 91: kdev_t dev = inode->i_rdev; ! 92: int result, target, err; ! 93: ! 94: target = MINOR(dev); ! 95: ! 96: if (target >= sr_template.nr_dev || ! 97: !scsi_CDs[target].device) return -ENXIO; ! 98: ! 99: switch (cmd) ! 100: { ! 101: /* Sun-compatible */ ! 102: case CDROMPAUSE: ! 103: ! 104: sr_cmd[0] = SCMD_PAUSE_RESUME; ! 105: sr_cmd[1] = scsi_CDs[target].device->lun << 5; ! 106: sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; ! 107: sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; ! 108: sr_cmd[8] = 0; ! 109: sr_cmd[9] = 0; ! 110: ! 111: result = do_ioctl(target, sr_cmd, NULL, 255); ! 112: return result; ! 113: ! 114: case CDROMRESUME: ! 115: ! 116: sr_cmd[0] = SCMD_PAUSE_RESUME; ! 117: sr_cmd[1] = scsi_CDs[target].device->lun << 5; ! 118: sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; ! 119: sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; ! 120: sr_cmd[8] = 1; ! 121: sr_cmd[9] = 0; ! 122: ! 123: result = do_ioctl(target, sr_cmd, NULL, 255); ! 124: ! 125: return result; ! 126: ! 127: case CDROMPLAYMSF: ! 128: { ! 129: struct cdrom_msf msf; ! 130: ! 131: err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf)); ! 132: if (err) return err; ! 133: ! 134: memcpy_fromfs(&msf, (void *) arg, sizeof(msf)); ! 135: ! 136: sr_cmd[0] = SCMD_PLAYAUDIO_MSF; ! 137: sr_cmd[1] = scsi_CDs[target].device->lun << 5; ! 138: sr_cmd[2] = 0; ! 139: sr_cmd[3] = msf.cdmsf_min0; ! 140: sr_cmd[4] = msf.cdmsf_sec0; ! 141: sr_cmd[5] = msf.cdmsf_frame0; ! 142: sr_cmd[6] = msf.cdmsf_min1; ! 143: sr_cmd[7] = msf.cdmsf_sec1; ! 144: sr_cmd[8] = msf.cdmsf_frame1; ! 145: sr_cmd[9] = 0; ! 146: ! 147: result = do_ioctl(target, sr_cmd, NULL, 255); ! 148: return result; ! 149: } ! 150: ! 151: case CDROMPLAYBLK: ! 152: { ! 153: struct cdrom_blk blk; ! 154: ! 155: err = verify_area (VERIFY_READ, (void *) arg, sizeof (blk)); ! 156: if (err) return err; ! 157: ! 158: memcpy_fromfs(&blk, (void *) arg, sizeof(blk)); ! 159: ! 160: sr_cmd[0] = SCMD_PLAYAUDIO10; ! 161: sr_cmd[1] = scsi_CDs[target].device->lun << 5; ! 162: sr_cmd[2] = blk.from >> 24; ! 163: sr_cmd[3] = blk.from >> 16; ! 164: sr_cmd[4] = blk.from >> 8; ! 165: sr_cmd[5] = blk.from; ! 166: sr_cmd[6] = 0; ! 167: sr_cmd[7] = blk.len >> 8; ! 168: sr_cmd[8] = blk.len; ! 169: sr_cmd[9] = 0; ! 170: ! 171: result = do_ioctl(target, sr_cmd, NULL, 255); ! 172: return result; ! 173: } ! 174: ! 175: case CDROMPLAYTRKIND: ! 176: { ! 177: struct cdrom_ti ti; ! 178: ! 179: err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti)); ! 180: if (err) return err; ! 181: ! 182: memcpy_fromfs(&ti, (void *) arg, sizeof(ti)); ! 183: ! 184: sr_cmd[0] = SCMD_PLAYAUDIO_TI; ! 185: sr_cmd[1] = scsi_CDs[target].device->lun << 5; ! 186: sr_cmd[2] = 0; ! 187: sr_cmd[3] = 0; ! 188: sr_cmd[4] = ti.cdti_trk0; ! 189: sr_cmd[5] = ti.cdti_ind0; ! 190: sr_cmd[6] = 0; ! 191: sr_cmd[7] = ti.cdti_trk1; ! 192: sr_cmd[8] = ti.cdti_ind1; ! 193: sr_cmd[9] = 0; ! 194: ! 195: result = do_ioctl(target, sr_cmd, NULL, 255); ! 196: ! 197: return result; ! 198: } ! 199: ! 200: case CDROMREADTOCHDR: ! 201: { ! 202: struct cdrom_tochdr tochdr; ! 203: char * buffer; ! 204: ! 205: sr_cmd[0] = SCMD_READ_TOC; ! 206: sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ ! 207: sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; ! 208: sr_cmd[6] = 0; ! 209: sr_cmd[7] = 0; /* MSB of length (12) */ ! 210: sr_cmd[8] = 12; /* LSB of length */ ! 211: sr_cmd[9] = 0; ! 212: ! 213: buffer = (unsigned char *) scsi_malloc(512); ! 214: if(!buffer) return -ENOMEM; ! 215: ! 216: result = do_ioctl(target, sr_cmd, buffer, 12); ! 217: ! 218: tochdr.cdth_trk0 = buffer[2]; ! 219: tochdr.cdth_trk1 = buffer[3]; ! 220: ! 221: scsi_free(buffer, 512); ! 222: ! 223: err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr)); ! 224: if (err) ! 225: return err; ! 226: memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr)); ! 227: ! 228: return result; ! 229: } ! 230: ! 231: case CDROMREADTOCENTRY: ! 232: { ! 233: struct cdrom_tocentry tocentry; ! 234: char * buffer; ! 235: ! 236: err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry)); ! 237: if (err) return err; ! 238: ! 239: memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry)); ! 240: ! 241: sr_cmd[0] = SCMD_READ_TOC; ! 242: sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ ! 243: sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; ! 244: sr_cmd[6] = tocentry.cdte_track; ! 245: sr_cmd[7] = 0; /* MSB of length (12) */ ! 246: sr_cmd[8] = 12; /* LSB of length */ ! 247: sr_cmd[9] = 0; ! 248: ! 249: buffer = (unsigned char *) scsi_malloc(512); ! 250: if(!buffer) return -ENOMEM; ! 251: ! 252: result = do_ioctl (target, sr_cmd, buffer, 12); ! 253: ! 254: if (tocentry.cdte_format == CDROM_MSF) { ! 255: tocentry.cdte_addr.msf.minute = buffer[9]; ! 256: tocentry.cdte_addr.msf.second = buffer[10]; ! 257: tocentry.cdte_addr.msf.frame = buffer[11]; ! 258: tocentry.cdte_ctrl = buffer[5] & 0xf; ! 259: } ! 260: else ! 261: tocentry.cdte_addr.lba = (int) buffer[0]; ! 262: ! 263: scsi_free(buffer, 512); ! 264: ! 265: err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry)); ! 266: if (err) ! 267: return err; ! 268: memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry)); ! 269: ! 270: return result; ! 271: } ! 272: ! 273: case CDROMSTOP: ! 274: sr_cmd[0] = START_STOP; ! 275: sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; ! 276: sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; ! 277: sr_cmd[4] = 0; ! 278: ! 279: result = do_ioctl(target, sr_cmd, NULL, 255); ! 280: return result; ! 281: ! 282: case CDROMSTART: ! 283: sr_cmd[0] = START_STOP; ! 284: sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; ! 285: sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; ! 286: sr_cmd[4] = 1; ! 287: ! 288: result = do_ioctl(target, sr_cmd, NULL, 255); ! 289: return result; ! 290: ! 291: case CDROMEJECT: ! 292: /* ! 293: * Allow 0 for access count for auto-eject feature. ! 294: */ ! 295: if (scsi_CDs[target].device -> access_count > 1) ! 296: return -EBUSY; ! 297: ! 298: sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); ! 299: sr_cmd[0] = START_STOP; ! 300: sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1; ! 301: sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; ! 302: sr_cmd[4] = 0x02; ! 303: ! 304: if (!(result = do_ioctl(target, sr_cmd, NULL, 255))) ! 305: scsi_CDs[target].device -> changed = 1; ! 306: ! 307: return result; ! 308: ! 309: case CDROMEJECT_SW: ! 310: scsi_CDs[target].auto_eject = !!arg; ! 311: return 0; ! 312: ! 313: case CDROMVOLCTRL: ! 314: { ! 315: char * buffer, * mask; ! 316: struct cdrom_volctrl volctrl; ! 317: ! 318: err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl)); ! 319: if (err) return err; ! 320: ! 321: memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl)); ! 322: ! 323: /* First we get the current params so we can just twiddle the volume */ ! 324: ! 325: sr_cmd[0] = MODE_SENSE; ! 326: sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; ! 327: sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ ! 328: sr_cmd[3] = 0; ! 329: sr_cmd[4] = 28; ! 330: sr_cmd[5] = 0; ! 331: ! 332: buffer = (unsigned char *) scsi_malloc(512); ! 333: if(!buffer) return -ENOMEM; ! 334: ! 335: if ((result = do_ioctl (target, sr_cmd, buffer, 28))) { ! 336: printk ("Hosed while obtaining audio mode page\n"); ! 337: scsi_free(buffer, 512); ! 338: return result; ! 339: } ! 340: ! 341: sr_cmd[0] = MODE_SENSE; ! 342: sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; ! 343: sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */ ! 344: sr_cmd[3] = 0; ! 345: sr_cmd[4] = 28; ! 346: sr_cmd[5] = 0; ! 347: ! 348: mask = (unsigned char *) scsi_malloc(512); ! 349: if(!mask) { ! 350: scsi_free(buffer, 512); ! 351: return -ENOMEM; ! 352: }; ! 353: ! 354: if ((result = do_ioctl (target, sr_cmd, mask, 28))) { ! 355: printk ("Hosed while obtaining mask for audio mode page\n"); ! 356: scsi_free(buffer, 512); ! 357: scsi_free(mask, 512); ! 358: return result; ! 359: } ! 360: ! 361: /* Now mask and substitute our own volume and reuse the rest */ ! 362: buffer[0] = 0; /* Clear reserved field */ ! 363: ! 364: buffer[21] = volctrl.channel0 & mask[21]; ! 365: buffer[23] = volctrl.channel1 & mask[23]; ! 366: buffer[25] = volctrl.channel2 & mask[25]; ! 367: buffer[27] = volctrl.channel3 & mask[27]; ! 368: ! 369: sr_cmd[0] = MODE_SELECT; ! 370: sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */ ! 371: sr_cmd[2] = sr_cmd[3] = 0; ! 372: sr_cmd[4] = 28; ! 373: sr_cmd[5] = 0; ! 374: ! 375: result = do_ioctl (target, sr_cmd, buffer, 28); ! 376: scsi_free(buffer, 512); ! 377: scsi_free(mask, 512); ! 378: return result; ! 379: } ! 380: ! 381: case CDROMSUBCHNL: ! 382: { ! 383: struct cdrom_subchnl subchnl; ! 384: char * buffer; ! 385: ! 386: sr_cmd[0] = SCMD_READ_SUBCHANNEL; ! 387: sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ ! 388: sr_cmd[2] = 0x40; /* I do want the subchannel info */ ! 389: sr_cmd[3] = 0x01; /* Give me current position info */ ! 390: sr_cmd[4] = sr_cmd[5] = 0; ! 391: sr_cmd[6] = 0; ! 392: sr_cmd[7] = 0; ! 393: sr_cmd[8] = 16; ! 394: sr_cmd[9] = 0; ! 395: ! 396: buffer = (unsigned char*) scsi_malloc(512); ! 397: if(!buffer) return -ENOMEM; ! 398: ! 399: result = do_ioctl(target, sr_cmd, buffer, 16); ! 400: ! 401: subchnl.cdsc_audiostatus = buffer[1]; ! 402: subchnl.cdsc_format = CDROM_MSF; ! 403: subchnl.cdsc_ctrl = buffer[5] & 0xf; ! 404: subchnl.cdsc_trk = buffer[6]; ! 405: subchnl.cdsc_ind = buffer[7]; ! 406: ! 407: subchnl.cdsc_reladdr.msf.minute = buffer[13]; ! 408: subchnl.cdsc_reladdr.msf.second = buffer[14]; ! 409: subchnl.cdsc_reladdr.msf.frame = buffer[15]; ! 410: subchnl.cdsc_absaddr.msf.minute = buffer[9]; ! 411: subchnl.cdsc_absaddr.msf.second = buffer[10]; ! 412: subchnl.cdsc_absaddr.msf.frame = buffer[11]; ! 413: ! 414: scsi_free(buffer, 512); ! 415: ! 416: err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl)); ! 417: if (err) ! 418: return err; ! 419: memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)); ! 420: return result; ! 421: } ! 422: ! 423: case CDROMREADMODE2: ! 424: return -EINVAL; ! 425: case CDROMREADMODE1: ! 426: return -EINVAL; ! 427: ! 428: /* block-copy from ../block/sbpcd.c with some adjustments... */ ! 429: case CDROMMULTISESSION: /* tell start-of-last-session to user */ ! 430: { ! 431: struct cdrom_multisession ms_info; ! 432: long lba; ! 433: ! 434: err = verify_area(VERIFY_READ, (void *) arg, ! 435: sizeof(struct cdrom_multisession)); ! 436: if (err) return (err); ! 437: ! 438: memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession)); ! 439: ! 440: if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */ ! 441: lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET; ! 442: ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES); ! 443: lba %= CD_SECS*CD_FRAMES; ! 444: ms_info.addr.msf.second = lba / CD_FRAMES; ! 445: ms_info.addr.msf.frame = lba % CD_FRAMES; ! 446: } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */ ! 447: ms_info.addr.lba=scsi_CDs[target].mpcd_sector; ! 448: else return (-EINVAL); ! 449: ! 450: ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01; ! 451: ! 452: err=verify_area(VERIFY_WRITE,(void *) arg, ! 453: sizeof(struct cdrom_multisession)); ! 454: if (err) return (err); ! 455: ! 456: memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession)); ! 457: return (0); ! 458: } ! 459: ! 460: case BLKRASET: ! 461: if(!suser()) return -EACCES; ! 462: if(!(inode->i_rdev)) return -EINVAL; ! 463: if(arg > 0xff) return -EINVAL; ! 464: read_ahead[MAJOR(inode->i_rdev)] = arg; ! 465: return 0; ! 466: RO_IOCTLS(dev,arg); ! 467: default: ! 468: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); ! 469: } ! 470: } ! 471: ! 472: /* ! 473: * Overrides for Emacs so that we follow Linus's tabbing style. ! 474: * Emacs will notice this stuff at the end of the file and automatically ! 475: * adjust the settings for this buffer only. This must remain at the end ! 476: * of the file. ! 477: * --------------------------------------------------------------------------- ! 478: * Local variables: ! 479: * c-indent-level: 4 ! 480: * c-brace-imaginary-offset: 0 ! 481: * c-brace-offset: -4 ! 482: * c-argdecl-indent: 4 ! 483: * c-label-offset: -4 ! 484: * c-continued-statement-offset: 4 ! 485: * c-continued-brace-offset: 0 ! 486: * indent-tabs-mode: nil ! 487: * tab-width: 8 ! 488: * End: ! 489: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.