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