linux_cdrom.c revision 1.4 1 /* $NetBSD: linux_cdrom.c,v 1.4 1998/10/03 20:28:03 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the NetBSD
18 * Foundation, Inc. and its contributors.
19 * 4. Neither the name of The NetBSD Foundation nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/ioctl.h>
39 #include <sys/file.h>
40 #include <sys/filedesc.h>
41 #include <sys/mount.h>
42 #include <sys/proc.h>
43 #include <sys/cdio.h>
44
45 #include <sys/syscallargs.h>
46
47 #include <compat/linux/common/linux_types.h>
48 #include <compat/linux/common/linux_ioctl.h>
49 #include <compat/linux/common/linux_signal.h>
50 #include <compat/linux/common/linux_util.h>
51 #include <compat/linux/common/linux_cdrom.h>
52
53 #include <compat/linux/linux_syscallargs.h>
54
55 #if 0
56 #define DPRINTF(x) printf x
57 #else
58 #define DPRINTF(x)
59 #endif
60
61 int
62 linux_ioctl_cdrom(p, uap, retval)
63 struct proc *p;
64 struct linux_sys_ioctl_args /* {
65 syscallarg(int) fd;
66 syscallarg(u_long) com;
67 syscallarg(caddr_t) data;
68 } */ *uap;
69 register_t *retval;
70 {
71 int error, idata;
72 u_long com, ncom;
73 caddr_t sg;
74 struct file *fp;
75 struct filedesc *fdp;
76 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
77
78 struct linux_cdrom_blk l_blk;
79 struct linux_cdrom_msf l_msf;
80 struct linux_cdrom_ti l_ti;
81 struct linux_cdrom_tochdr l_tochdr;
82 struct linux_cdrom_tocentry l_tocentry;
83 struct linux_cdrom_subchnl l_subchnl;
84 struct linux_cdrom_volctrl l_volctrl;
85
86 struct ioc_play_blocks t_blocks;
87 struct ioc_play_msf t_msf;
88 struct ioc_play_track t_track;
89 struct ioc_toc_header t_header;
90 struct cd_toc_entry *entry, t_entry;
91 struct ioc_read_toc_entry t_toc_entry;
92 struct cd_sub_channel_info *info, t_info;
93 struct ioc_read_subchannel t_subchannel;
94 struct ioc_vol t_vol;
95
96 fdp = p->p_fd;
97 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
98 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
99 return (EBADF);
100
101 com = SCARG(uap, com);
102 ioctlf = fp->f_ops->fo_ioctl;
103 retval[0] = 0;
104
105 switch(com) {
106 case LINUX_CDROMPLAYMSF:
107 error = copyin(SCARG(uap, data), &l_msf, sizeof l_msf);
108 if (error)
109 return error;
110
111 t_msf.start_m = l_msf.cdmsf_min0;
112 t_msf.start_s = l_msf.cdmsf_sec0;
113 t_msf.start_f = l_msf.cdmsf_frame0;
114 t_msf.end_m = l_msf.cdmsf_min1;
115 t_msf.end_s = l_msf.cdmsf_sec1;
116 t_msf.end_f = l_msf.cdmsf_frame1;
117
118 return ioctlf(fp, CDIOCPLAYMSF, (caddr_t)&t_msf, p);
119
120 case LINUX_CDROMPLAYTRKIND:
121 error = copyin(SCARG(uap, data), &l_ti, sizeof l_ti);
122 if (error)
123 return error;
124
125 t_track.start_track = l_ti.cdti_trk0;
126 t_track.start_index = l_ti.cdti_ind0;
127 t_track.end_track = l_ti.cdti_trk1;
128 t_track.end_index = l_ti.cdti_ind1;
129
130 return ioctlf(fp, CDIOCPLAYTRACKS, (caddr_t)&t_track, p);
131
132 case LINUX_CDROMREADTOCHDR:
133 error = ioctlf(fp, CDIOREADTOCHEADER, (caddr_t)&t_header, p);
134 if (error)
135 return error;
136
137 l_tochdr.cdth_trk0 = t_header.starting_track;
138 l_tochdr.cdth_trk1 = t_header.ending_track;
139
140 return copyout(&l_tochdr, SCARG(uap, data), sizeof l_tochdr);
141
142 case LINUX_CDROMREADTOCENTRY:
143 error = copyin(SCARG(uap, data), &l_tocentry,
144 sizeof l_tocentry);
145 if (error)
146 return error;
147
148 sg = stackgap_init(p->p_emul);
149 entry = stackgap_alloc(&sg, sizeof *entry);
150 t_toc_entry.address_format = l_tocentry.cdte_format;
151 t_toc_entry.starting_track = l_tocentry.cdte_track;
152 t_toc_entry.data_len = sizeof *entry;
153 t_toc_entry.data = entry;
154
155 error = ioctlf(fp, CDIOREADTOCENTRYS, (caddr_t)&t_toc_entry,
156 p);
157 if (error)
158 return error;
159
160 error = copyin(entry, &t_entry, sizeof t_entry);
161 if (error)
162 return error;
163
164 l_tocentry.cdte_adr = t_entry.addr_type;
165 l_tocentry.cdte_ctrl = t_entry.control;
166 switch (t_toc_entry.address_format) {
167 case CD_LBA_FORMAT:
168 l_tocentry.cdte_addr.lba = t_entry.addr.lba;
169 break;
170 case CD_MSF_FORMAT:
171 l_tocentry.cdte_addr.msf.minute =
172 t_entry.addr.msf.minute;
173 l_tocentry.cdte_addr.msf.second =
174 t_entry.addr.msf.second;
175 l_tocentry.cdte_addr.msf.frame =
176 t_entry.addr.msf.frame;
177 break;
178 default:
179 printf("linux_ioctl: unknown format msf/lba\n");
180 return EINVAL;
181 }
182
183 return copyout(&l_tocentry, SCARG(uap, data),
184 sizeof l_tocentry);
185
186 case LINUX_CDROMVOLCTRL:
187 error = copyin(SCARG(uap, data), &l_volctrl, sizeof l_volctrl);
188 if (error)
189 return error;
190
191 t_vol.vol[0] = l_volctrl.channel0;
192 t_vol.vol[1] = l_volctrl.channel1;
193 t_vol.vol[2] = l_volctrl.channel2;
194 t_vol.vol[3] = l_volctrl.channel3;
195
196 return ioctlf(fp, CDIOCSETVOL, (caddr_t)&t_vol, p);
197
198 case LINUX_CDROMVOLREAD:
199 error = ioctlf(fp, CDIOCGETVOL, (caddr_t)&t_vol, p);
200 if (error)
201 return error;
202
203 l_volctrl.channel0 = t_vol.vol[0];
204 l_volctrl.channel1 = t_vol.vol[1];
205 l_volctrl.channel2 = t_vol.vol[2];
206 l_volctrl.channel3 = t_vol.vol[3];
207
208 return copyout(&l_volctrl, SCARG(uap, data), sizeof l_volctrl);
209
210 case LINUX_CDROMSUBCHNL:
211 error = copyin(SCARG(uap, data), &l_subchnl, sizeof l_subchnl);
212 if (error)
213 return error;
214
215 sg = stackgap_init(p->p_emul);
216 info = stackgap_alloc(&sg, sizeof *info);
217 t_subchannel.address_format = l_subchnl.cdsc_format;
218 t_subchannel.data_format = CD_CURRENT_POSITION;
219 t_subchannel.track = l_subchnl.cdsc_trk;
220 t_subchannel.data_len = sizeof *info;
221 t_subchannel.data = info;
222 DPRINTF(("linux_ioctl: CDROMSUBCHNL %d %d\n",
223 l_subchnl.cdsc_format, l_subchnl.cdsc_trk));
224
225 error = ioctlf(fp, CDIOCREADSUBCHANNEL, (caddr_t)&t_subchannel,
226 p);
227 if (error)
228 return error;
229
230 error = copyin(info, &t_info, sizeof t_info);
231 if (error)
232 return error;
233
234 l_subchnl.cdsc_audiostatus = t_info.header.audio_status;
235 l_subchnl.cdsc_adr = t_info.what.position.addr_type;
236 l_subchnl.cdsc_ctrl = t_info.what.position.control;
237 l_subchnl.cdsc_ind = t_info.what.position.index_number;
238
239 DPRINTF(("linux_ioctl: CDIOCREADSUBCHANNEL %d %d %d\n",
240 t_info.header.audio_status,
241 t_info.header.data_len[0],
242 t_info.header.data_len[1]));
243 DPRINTF(("(more) %d %d %d %d %d\n",
244 t_info.what.position.data_format,
245 t_info.what.position.control,
246 t_info.what.position.addr_type,
247 t_info.what.position.track_number,
248 t_info.what.position.index_number));
249
250 switch (t_subchannel.address_format) {
251 case CD_LBA_FORMAT:
252 l_subchnl.cdsc_absaddr.lba =
253 t_info.what.position.absaddr.lba;
254 l_subchnl.cdsc_reladdr.lba =
255 t_info.what.position.reladdr.lba;
256 DPRINTF(("LBA: %d %d\n",
257 t_info.what.position.absaddr.lba,
258 t_info.what.position.reladdr.lba));
259 break;
260
261 case CD_MSF_FORMAT:
262 l_subchnl.cdsc_absaddr.msf.minute =
263 t_info.what.position.absaddr.msf.minute;
264 l_subchnl.cdsc_absaddr.msf.second =
265 t_info.what.position.absaddr.msf.second;
266 l_subchnl.cdsc_absaddr.msf.frame =
267 t_info.what.position.absaddr.msf.frame;
268
269 l_subchnl.cdsc_reladdr.msf.minute =
270 t_info.what.position.reladdr.msf.minute;
271 l_subchnl.cdsc_reladdr.msf.second =
272 t_info.what.position.reladdr.msf.second;
273 l_subchnl.cdsc_reladdr.msf.frame =
274 t_info.what.position.reladdr.msf.frame;
275 DPRINTF(("MSF: %d %d %d %d\n",
276 t_info.what.position.absaddr.msf.minute,
277 t_info.what.position.absaddr.msf.second,
278 t_info.what.position.reladdr.msf.minute,
279 t_info.what.position.reladdr.msf.second));
280 break;
281
282 default:
283 DPRINTF(("linux_ioctl: unknown format msf/lba\n"));
284 return EINVAL;
285 }
286
287 return copyout(&l_subchnl, SCARG(uap, data), sizeof l_subchnl);
288
289 case LINUX_CDROMPLAYBLK:
290 error = copyin(SCARG(uap, data), &l_blk, sizeof l_blk);
291 if (error)
292 return error;
293
294 t_blocks.blk = l_blk.from;
295 t_blocks.len = l_blk.len;
296
297 return ioctlf(fp, CDIOCPLAYBLOCKS, (caddr_t)&t_blocks, p);
298
299 case LINUX_CDROMEJECT_SW:
300 error = copyin(SCARG(uap, data), &idata, sizeof idata);
301 if (error)
302 return error;
303
304 if (idata == 1)
305 ncom = CDIOCALLOW;
306 else
307 ncom = CDIOCPREVENT;
308 break;
309
310 case LINUX_CDROMPAUSE:
311 ncom = CDIOCPAUSE;
312 break;
313
314 case LINUX_CDROMRESUME:
315 ncom = CDIOCRESUME;
316 break;
317
318 case LINUX_CDROMSTOP:
319 ncom = CDIOCSTOP;
320 break;
321
322 case LINUX_CDROMSTART:
323 ncom = CDIOCSTART;
324 break;
325
326 case LINUX_CDROMEJECT:
327 ncom = CDIOCEJECT;
328 break;
329
330 case LINUX_CDROMRESET:
331 ncom = CDIOCRESET;
332 break;
333
334 default:
335 DPRINTF(("linux_ioctl: unimplemented ioctl %08lx\n", com));
336 return EINVAL;
337 }
338
339 return ioctlf(fp, ncom, NULL, p);
340 }
341