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