This source file includes following definitions.
- sr_ioctl_done
- do_ioctl
- sr_ioctl
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 "../block/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
18
19 #define IOCTL_TIMEOUT 3000
20
21 extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
22
23 static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
24 {
25 struct request * req;
26
27 req = &SCpnt->request;
28 req->dev = 0xfffe;
29
30 if (req->sem != NULL) {
31 up(req->sem);
32 }
33 }
34
35
36
37
38
39 static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
40 {
41 Scsi_Cmnd * SCpnt;
42 int result;
43
44 SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
45 scsi_do_cmd(SCpnt,
46 (void *) sr_cmd, buffer, buflength, sr_ioctl_done,
47 IOCTL_TIMEOUT, IOCTL_RETRIES);
48
49
50 if (SCpnt->request.dev != 0xfffe){
51 struct semaphore sem = MUTEX_LOCKED;
52 SCpnt->request.sem = &sem;
53 down(&sem);
54
55 while (SCpnt->request.dev != 0xfffe) schedule();
56 };
57
58 result = SCpnt->result;
59
60
61 if(driver_byte(result) != 0)
62 switch(SCpnt->sense_buffer[2] & 0xf) {
63 case UNIT_ATTENTION:
64 scsi_CDs[target].device->changed = 1;
65 printk("Disc change detected.\n");
66 break;
67 case NOT_READY:
68 printk("CDROM not ready. Make sure there is a disc in the drive.\n");
69 break;
70 case ILLEGAL_REQUEST:
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.dev = -1;
88 wake_up(&SCpnt->device->device_wait);
89
90 return result;
91 }
92
93 int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
94 {
95 u_char sr_cmd[10];
96
97 int 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
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 memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
137
138 sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
139 sr_cmd[1] = scsi_CDs[target].device->lun << 5;
140 sr_cmd[2] = 0;
141 sr_cmd[3] = msf.cdmsf_min0;
142 sr_cmd[4] = msf.cdmsf_sec0;
143 sr_cmd[5] = msf.cdmsf_frame0;
144 sr_cmd[6] = msf.cdmsf_min1;
145 sr_cmd[7] = msf.cdmsf_sec1;
146 sr_cmd[8] = msf.cdmsf_frame1;
147 sr_cmd[9] = 0;
148
149 result = do_ioctl(target, sr_cmd, NULL, 255);
150 return result;
151 }
152
153 case CDROMPLAYTRKIND:
154 {
155 struct cdrom_ti ti;
156 memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
157
158 sr_cmd[0] = SCMD_PLAYAUDIO_TI;
159 sr_cmd[1] = scsi_CDs[target].device->lun << 5;
160 sr_cmd[2] = 0;
161 sr_cmd[3] = 0;
162 sr_cmd[4] = ti.cdti_trk0;
163 sr_cmd[5] = ti.cdti_ind0;
164 sr_cmd[6] = 0;
165 sr_cmd[7] = ti.cdti_trk1;
166 sr_cmd[8] = ti.cdti_ind1;
167 sr_cmd[9] = 0;
168
169 result = do_ioctl(target, sr_cmd, NULL, 255);
170
171 return result;
172 }
173
174 case CDROMREADTOCHDR:
175 {
176 struct cdrom_tochdr tochdr;
177 char * buffer;
178
179 sr_cmd[0] = SCMD_READ_TOC;
180 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;
181 sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
182 sr_cmd[6] = 0;
183 sr_cmd[7] = 0;
184 sr_cmd[8] = 12;
185 sr_cmd[9] = 0;
186
187 buffer = (unsigned char *) scsi_malloc(512);
188 if(!buffer) return -ENOMEM;
189
190 result = do_ioctl(target, sr_cmd, buffer, 12);
191
192 tochdr.cdth_trk0 = buffer[2];
193 tochdr.cdth_trk1 = buffer[3];
194
195 scsi_free(buffer, 512);
196
197 err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
198 if (err)
199 return err;
200 memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
201
202 return result;
203 }
204
205 case CDROMREADTOCENTRY:
206 {
207 struct cdrom_tocentry tocentry;
208 char * buffer;
209
210 verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
211 memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
212
213 sr_cmd[0] = SCMD_READ_TOC;
214 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;
215 sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
216 sr_cmd[6] = tocentry.cdte_track;
217 sr_cmd[7] = 0;
218 sr_cmd[8] = 12;
219 sr_cmd[9] = 0;
220
221 buffer = (unsigned char *) scsi_malloc(512);
222 if(!buffer) return -ENOMEM;
223
224 result = do_ioctl (target, sr_cmd, buffer, 12);
225
226 if (tocentry.cdte_format == CDROM_MSF) {
227 tocentry.cdte_addr.msf.minute = buffer[9];
228 tocentry.cdte_addr.msf.second = buffer[10];
229 tocentry.cdte_addr.msf.frame = buffer[11];
230 tocentry.cdte_ctrl = buffer[5] & 0xf;
231 }
232 else
233 tocentry.cdte_addr.lba = (int) buffer[0];
234
235 scsi_free(buffer, 512);
236
237 err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
238 if (err)
239 return err;
240 memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
241
242 return result;
243 }
244
245 case CDROMSTOP:
246 sr_cmd[0] = START_STOP;
247 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
248 sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
249 sr_cmd[4] = 0;
250
251 result = do_ioctl(target, sr_cmd, NULL, 255);
252 return result;
253
254 case CDROMSTART:
255 sr_cmd[0] = START_STOP;
256 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
257 sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
258 sr_cmd[4] = 1;
259
260 result = do_ioctl(target, sr_cmd, NULL, 255);
261 return result;
262
263 case CDROMEJECT:
264 if (scsi_CDs[target].device -> access_count != 1)
265 return -EBUSY;
266
267 sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
268 sr_cmd[0] = START_STOP;
269 sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
270 sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
271 sr_cmd[4] = 0x02;
272
273 if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
274 scsi_CDs[target].device -> changed = 1;
275
276 return result;
277
278 case CDROMVOLCTRL:
279 {
280 char * buffer, * mask;
281 struct cdrom_volctrl volctrl;
282
283 verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
284 memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
285
286
287
288 sr_cmd[0] = MODE_SENSE;
289 sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
290 sr_cmd[2] = 0xe;
291 sr_cmd[3] = 0;
292 sr_cmd[4] = 28;
293 sr_cmd[5] = 0;
294
295 buffer = (unsigned char *) scsi_malloc(512);
296 if(!buffer) return -ENOMEM;
297
298 if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
299 printk ("Hosed while obtaining audio mode page\n");
300 scsi_free(buffer, 512);
301 return result;
302 }
303
304 sr_cmd[0] = MODE_SENSE;
305 sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
306 sr_cmd[2] = 0x4e;
307 sr_cmd[3] = 0;
308 sr_cmd[4] = 28;
309 sr_cmd[5] = 0;
310
311 mask = (unsigned char *) scsi_malloc(512);
312 if(!mask) {
313 scsi_free(buffer, 512);
314 return -ENOMEM;
315 };
316
317 if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
318 printk ("Hosed while obtaining mask for audio mode page\n");
319 scsi_free(buffer, 512);
320 scsi_free(mask, 512);
321 return result;
322 }
323
324
325 buffer[0] = 0;
326
327 buffer[21] = volctrl.channel0 & mask[21];
328 buffer[23] = volctrl.channel1 & mask[23];
329 buffer[25] = volctrl.channel2 & mask[25];
330 buffer[27] = volctrl.channel3 & mask[27];
331
332 sr_cmd[0] = MODE_SELECT;
333 sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;
334 sr_cmd[2] = sr_cmd[3] = 0;
335 sr_cmd[4] = 28;
336 sr_cmd[5] = 0;
337
338 result = do_ioctl (target, sr_cmd, buffer, 28);
339 scsi_free(buffer, 512);
340 scsi_free(mask, 512);
341 return result;
342 }
343
344 case CDROMSUBCHNL:
345 {
346 struct cdrom_subchnl subchnl;
347 char * buffer;
348
349 sr_cmd[0] = SCMD_READ_SUBCHANNEL;
350 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;
351 sr_cmd[2] = 0x40;
352 sr_cmd[3] = 0x01;
353 sr_cmd[4] = sr_cmd[5] = 0;
354 sr_cmd[6] = 0;
355 sr_cmd[7] = 0;
356 sr_cmd[8] = 16;
357 sr_cmd[9] = 0;
358
359 buffer = (unsigned char*) scsi_malloc(512);
360 if(!buffer) return -ENOMEM;
361
362 result = do_ioctl(target, sr_cmd, buffer, 16);
363
364 subchnl.cdsc_audiostatus = buffer[1];
365 subchnl.cdsc_format = CDROM_MSF;
366 subchnl.cdsc_ctrl = buffer[5] & 0xf;
367 subchnl.cdsc_trk = buffer[6];
368 subchnl.cdsc_ind = buffer[7];
369
370 subchnl.cdsc_reladdr.msf.minute = buffer[13];
371 subchnl.cdsc_reladdr.msf.second = buffer[14];
372 subchnl.cdsc_reladdr.msf.frame = buffer[15];
373 subchnl.cdsc_absaddr.msf.minute = buffer[9];
374 subchnl.cdsc_absaddr.msf.second = buffer[10];
375 subchnl.cdsc_absaddr.msf.frame = buffer[11];
376
377 scsi_free(buffer, 512);
378
379 err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
380 if (err)
381 return err;
382 memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
383 return result;
384 }
385
386 case CDROMREADMODE2:
387 return -EINVAL;
388 case CDROMREADMODE1:
389 return -EINVAL;
390
391
392 case CDROMMULTISESSION:
393 {
394 struct cdrom_multisession ms_info;
395 long lba;
396
397 err = verify_area(VERIFY_READ, (void *) arg,
398 sizeof(struct cdrom_multisession));
399 if (err) return (err);
400
401 memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
402
403 if (ms_info.addr_format==CDROM_MSF) {
404 lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
405 ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
406 lba %= CD_SECS*CD_FRAMES;
407 ms_info.addr.msf.second = lba / CD_FRAMES;
408 ms_info.addr.msf.frame = lba % CD_FRAMES;
409 } else if (ms_info.addr_format==CDROM_LBA)
410 ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
411 else return (-EINVAL);
412
413 ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
414
415 err=verify_area(VERIFY_WRITE,(void *) arg,
416 sizeof(struct cdrom_multisession));
417 if (err) return (err);
418
419 memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
420 return (0);
421 }
422
423 case BLKRASET:
424 if(!suser()) return -EACCES;
425 if(!inode->i_rdev) return -EINVAL;
426 if(arg > 0xff) return -EINVAL;
427 read_ahead[MAJOR(inode->i_rdev)] = arg;
428 return 0;
429 RO_IOCTLS(dev,arg);
430 default:
431 return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
432 }
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450