|
|
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.