Annotation of Gnu-Mach/i386/i386at/gpl/linux/scsi/sr_ioctl.c, revision 1.1

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:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.