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 sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
266
267 sr_cmd[0] = START_STOP;
268 sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
269 sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
270 sr_cmd[4] = 0x02;
271
272 if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
273 scsi_CDs[target].device -> changed = 1;
274
275 return result;
276
277 case CDROMVOLCTRL:
278 {
279 char * buffer, * mask;
280 struct cdrom_volctrl volctrl;
281
282 verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
283 memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
284
285
286
287 sr_cmd[0] = MODE_SENSE;
288 sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
289 sr_cmd[2] = 0xe;
290 sr_cmd[3] = 0;
291 sr_cmd[4] = 28;
292 sr_cmd[5] = 0;
293
294 buffer = (unsigned char *) scsi_malloc(512);
295 if(!buffer) return -ENOMEM;
296
297 if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
298 printk ("Hosed while obtaining audio mode page\n");
299 scsi_free(buffer, 512);
300 return result;
301 }
302
303 sr_cmd[0] = MODE_SENSE;
304 sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
305 sr_cmd[2] = 0x4e;
306 sr_cmd[3] = 0;
307 sr_cmd[4] = 28;
308 sr_cmd[5] = 0;
309
310 mask = (unsigned char *) scsi_malloc(512);
311 if(!mask) {
312 scsi_free(buffer, 512);
313 return -ENOMEM;
314 };
315
316 if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
317 printk ("Hosed while obtaining mask for audio mode page\n");
318 scsi_free(buffer, 512);
319 scsi_free(mask, 512);
320 return result;
321 }
322
323
324 buffer[0] = 0;
325
326 buffer[21] = volctrl.channel0 & mask[21];
327 buffer[23] = volctrl.channel1 & mask[23];
328 buffer[25] = volctrl.channel2 & mask[25];
329 buffer[27] = volctrl.channel3 & mask[27];
330
331 sr_cmd[0] = MODE_SELECT;
332 sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;
333 sr_cmd[2] = sr_cmd[3] = 0;
334 sr_cmd[4] = 28;
335 sr_cmd[5] = 0;
336
337 result = do_ioctl (target, sr_cmd, buffer, 28);
338 scsi_free(buffer, 512);
339 scsi_free(mask, 512);
340 return result;
341 }
342
343 case CDROMSUBCHNL:
344 {
345 struct cdrom_subchnl subchnl;
346 char * buffer;
347
348 sr_cmd[0] = SCMD_READ_SUBCHANNEL;
349 sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;
350 sr_cmd[2] = 0x40;
351 sr_cmd[3] = 0x01;
352 sr_cmd[4] = sr_cmd[5] = 0;
353 sr_cmd[6] = 0;
354 sr_cmd[7] = 0;
355 sr_cmd[8] = 16;
356 sr_cmd[9] = 0;
357
358 buffer = (unsigned char*) scsi_malloc(512);
359 if(!buffer) return -ENOMEM;
360
361 result = do_ioctl(target, sr_cmd, buffer, 16);
362
363 subchnl.cdsc_audiostatus = buffer[1];
364 subchnl.cdsc_format = CDROM_MSF;
365 subchnl.cdsc_ctrl = buffer[5] & 0xf;
366 subchnl.cdsc_trk = buffer[6];
367 subchnl.cdsc_ind = buffer[7];
368
369 subchnl.cdsc_reladdr.msf.minute = buffer[13];
370 subchnl.cdsc_reladdr.msf.second = buffer[14];
371 subchnl.cdsc_reladdr.msf.frame = buffer[15];
372 subchnl.cdsc_absaddr.msf.minute = buffer[9];
373 subchnl.cdsc_absaddr.msf.second = buffer[10];
374 subchnl.cdsc_absaddr.msf.frame = buffer[11];
375
376 scsi_free(buffer, 512);
377
378 err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
379 if (err)
380 return err;
381 memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
382 return result;
383 }
384
385 case CDROMREADMODE2:
386 return -EINVAL;
387 case CDROMREADMODE1:
388 return -EINVAL;
389
390
391 case CDROMMULTISESSION:
392 {
393 struct cdrom_multisession ms_info;
394 long lba;
395
396 err = verify_area(VERIFY_READ, (void *) arg,
397 sizeof(struct cdrom_multisession));
398 if (err) return (err);
399
400 memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
401
402 if (ms_info.addr_format==CDROM_MSF) {
403 lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
404 ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
405 lba %= CD_SECS*CD_FRAMES;
406 ms_info.addr.msf.second = lba / CD_FRAMES;
407 ms_info.addr.msf.frame = lba % CD_FRAMES;
408 } else if (ms_info.addr_format==CDROM_LBA)
409 ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
410 else return (-EINVAL);
411
412 ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
413
414 err=verify_area(VERIFY_WRITE,(void *) arg,
415 sizeof(struct cdrom_multisession));
416 if (err) return (err);
417
418 memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
419 return (0);
420 }
421
422 case BLKRASET:
423 if(!suser()) return -EACCES;
424 if(!inode->i_rdev) return -EINVAL;
425 if(arg > 0xff) return -EINVAL;
426 read_ahead[MAJOR(inode->i_rdev)] = arg;
427 return 0;
428 RO_IOCTLS(dev,arg);
429 default:
430 return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
431 }
432 }
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449