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