1 
2 /*	$OpenBSD: linux_cdrom.c,v 1.8 2002/03/14 01:26:50 millert Exp $	*/
3 /*
4  * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
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 Niels Provos.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/proc.h>
35 #include <sys/systm.h>
36 #include <sys/file.h>
37 #include <sys/filedesc.h>
38 #include <sys/ioctl.h>
39 #include <sys/mount.h>
40 #include <sys/cdio.h>
41 
42 #include <sys/syscallargs.h>
43 
44 #include <compat/linux/linux_types.h>
45 #include <compat/linux/linux_ioctl.h>
46 #include <compat/linux/linux_signal.h>
47 #include <compat/linux/linux_syscallargs.h>
48 #include <compat/linux/linux_util.h>
49 #include <compat/linux/linux_cdrom.h>
50 
51 void bsd_addr_to_linux_addr(union msf_lba *bsd,
52     union linux_cdrom_addr *linux, int format);
53 
54 void
bsd_addr_to_linux_addr(bsd,linux,format)55 bsd_addr_to_linux_addr(bsd, linux, format)
56         union msf_lba *bsd;
57         union linux_cdrom_addr *linux;
58         int format;
59 {
60         if (format == CD_MSF_FORMAT) {
61  	        linux->msf.minute = bsd->msf.minute;
62 		linux->msf.second = bsd->msf.second;
63 		linux->msf.frame = bsd->msf.frame;
64 	} else
65 	        linux->lba = bsd->lba;
66 }
67 
68 int
linux_ioctl_cdrom(p,v,retval)69 linux_ioctl_cdrom(p, v, retval)
70 	struct proc *p;
71 	void *v;
72 	register_t *retval;
73 {
74 	struct linux_sys_ioctl_args /* {
75 		syscallarg(int) fd;
76 		syscallarg(u_long) com;
77 		syscallarg(caddr_t) data;
78 	} */ *uap = v;
79 	struct file *fp;
80 	struct filedesc *fdp;
81 	caddr_t sg;
82 	u_long com, arg;
83 	struct sys_ioctl_args ia;
84 	int error;
85 
86 	union {
87 	        struct cd_toc_entry te;
88 	        struct cd_sub_channel_info scinfo;
89 	} data;
90 	union {
91 	        struct ioc_toc_header th;
92 	        struct ioc_read_toc_entry tes;
93 	        struct ioc_play_track ti;
94 		struct ioc_play_msf msf;
95 		struct ioc_play_blocks blk;
96 	        struct ioc_read_subchannel sc;
97 		struct ioc_vol vol;
98 	} tmpb;
99 	union {
100 	        struct linux_cdrom_tochdr th;
101 	        struct linux_cdrom_tocentry te;
102 	        struct linux_cdrom_ti ti;
103 		struct linux_cdrom_msf msf;
104 		struct linux_cdrom_blk blk;
105 	        struct linux_cdrom_subchnl sc;
106 		struct linux_cdrom_volctrl vol;
107 	} tmpl;
108 
109 
110 	fdp = p->p_fd;
111 	if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
112 		return (EBADF);
113 	FREF(fp);
114 
115 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
116 		error = EBADF;
117 		goto out;
118 	}
119 
120 	com = SCARG(uap, com);
121 	retval[0] = 0;
122 
123 	switch (com) {
124 	case LINUX_CDROMREADTOCHDR:
125 	        error = (*fp->f_ops->fo_ioctl)(fp, CDIOREADTOCHEADER,
126 		    (caddr_t)&tmpb.th, p);
127 	        if (error)
128 			goto out;
129 		tmpl.th.cdth_trk0 = tmpb.th.starting_track;
130 		tmpl.th.cdth_trk1 = tmpb.th.ending_track;
131 		error = copyout(&tmpl, SCARG(uap, data), sizeof tmpl.th);
132 		goto out;
133 	case LINUX_CDROMREADTOCENTRY:
134 		error = copyin(SCARG(uap, data), &tmpl.te, sizeof tmpl.te);
135 		if (error)
136 		        goto out;
137 
138 		sg = stackgap_init(p->p_emul);
139 
140 		bzero(&tmpb.tes, sizeof tmpb.tes);
141 		tmpb.tes.starting_track = tmpl.te.cdte_track;
142 		tmpb.tes.address_format = (tmpl.te.cdte_format == LINUX_CDROM_MSF)
143 		    ? CD_MSF_FORMAT : CD_LBA_FORMAT;
144 		tmpb.tes.data_len = sizeof(struct cd_toc_entry);
145 		tmpb.tes.data = stackgap_alloc(&sg, tmpb.tes.data_len);
146 
147 	        error = (*fp->f_ops->fo_ioctl)(fp, CDIOREADTOCENTRYS,
148 		    (caddr_t)&tmpb.tes, p);
149 	        if (error)
150 			goto out;
151 		if ((error = copyin(tmpb.tes.data, &data.te, sizeof data.te)))
152 			goto out;
153 
154 		tmpl.te.cdte_ctrl = data.te.control;
155 		tmpl.te.cdte_adr = data.te.addr_type;
156 		tmpl.te.cdte_track = data.te.track;
157 		tmpl.te.cdte_datamode = CD_TRACK_INFO;
158 		bsd_addr_to_linux_addr(&data.te.addr, &tmpl.te.cdte_addr,
159 		    tmpb.tes.address_format);
160 		error = copyout(&tmpl, SCARG(uap, data), sizeof tmpl.te);
161 		goto out;
162 	case LINUX_CDROMSUBCHNL:
163 		error = copyin(SCARG(uap, data), &tmpl.sc, sizeof tmpl.sc);
164 		if (error)
165 			goto out;
166 
167 		sg = stackgap_init(p->p_emul);
168 
169 		bzero(&tmpb.sc, sizeof tmpb.sc);
170 		tmpb.sc.data_format = CD_CURRENT_POSITION;
171 		tmpb.sc.address_format = (tmpl.sc.cdsc_format == LINUX_CDROM_MSF)
172 		    ? CD_MSF_FORMAT : CD_LBA_FORMAT;
173 		tmpb.sc.data_len = sizeof(struct cd_sub_channel_info);
174 		tmpb.sc.data = stackgap_alloc(&sg, tmpb.sc.data_len);
175 
176 	        error = (*fp->f_ops->fo_ioctl)(fp, CDIOCREADSUBCHANNEL,
177 		    (caddr_t)&tmpb.sc, p);
178 	        if (error)
179 			goto out;
180 		if ((error = copyin(tmpb.sc.data, &data.scinfo, sizeof data.scinfo)))
181 			goto out;
182 
183 		tmpl.sc.cdsc_audiostatus = data.scinfo.header.audio_status;
184 		tmpl.sc.cdsc_adr = data.scinfo.what.position.addr_type;
185 		tmpl.sc.cdsc_ctrl = data.scinfo.what.position.control;
186 		tmpl.sc.cdsc_trk = data.scinfo.what.position.track_number;
187 		tmpl.sc.cdsc_ind = data.scinfo.what.position.index_number;
188 		bsd_addr_to_linux_addr(&data.scinfo.what.position.absaddr,
189 		    &tmpl.sc.cdsc_absaddr,
190 		    tmpb.sc.address_format);
191 		bsd_addr_to_linux_addr(&data.scinfo.what.position.reladdr,
192 		    &tmpl.sc.cdsc_reladdr,
193 		    tmpb.sc.address_format);
194 
195 		error = copyout(&tmpl, SCARG(uap, data), sizeof tmpl.sc);
196 		goto out;
197 	case LINUX_CDROMPLAYTRKIND:
198 		error = copyin(SCARG(uap, data), &tmpl.ti, sizeof tmpl.ti);
199 		if (error)
200 			goto out;
201 
202 		tmpb.ti.start_track = tmpl.ti.cdti_trk0;
203 		tmpb.ti.start_index = tmpl.ti.cdti_ind0;
204 		tmpb.ti.end_track = tmpl.ti.cdti_trk1;
205 		tmpb.ti.end_index = tmpl.ti.cdti_ind1;
206 	        error = (*fp->f_ops->fo_ioctl)(fp, CDIOCPLAYTRACKS,
207 		    (caddr_t)&tmpb.ti, p);
208 		goto out;
209 	case LINUX_CDROMPLAYMSF:
210 		error = copyin(SCARG(uap, data), &tmpl.msf, sizeof tmpl.msf);
211 		if (error)
212 			goto out;
213 
214 		tmpb.msf.start_m = tmpl.msf.cdmsf_min0;
215 		tmpb.msf.start_s = tmpl.msf.cdmsf_sec0;
216 		tmpb.msf.start_f = tmpl.msf.cdmsf_frame0;
217 		tmpb.msf.end_m = tmpl.msf.cdmsf_min1;
218 		tmpb.msf.end_s = tmpl.msf.cdmsf_sec1;
219 		tmpb.msf.end_f = tmpl.msf.cdmsf_frame1;
220 
221 		error = (*fp->f_ops->fo_ioctl)(fp, CDIOCPLAYMSF,
222 		    (caddr_t)&tmpb.msf, p);
223 		goto out;
224 	case LINUX_CDROMPLAYBLK:
225 		error = copyin(SCARG(uap, data), &tmpl.blk, sizeof tmpl.blk);
226 		if (error)
227 			goto out;
228 
229 		tmpb.blk.blk = tmpl.blk.from;
230 		tmpb.blk.len = tmpl.blk.len;
231 
232 		error = (*fp->f_ops->fo_ioctl)(fp, CDIOCPLAYBLOCKS,
233 		    (caddr_t)&tmpb.blk, p);
234 		goto out;
235 	case LINUX_CDROMVOLCTRL:
236 		error = copyin(SCARG(uap, data), &tmpl.vol, sizeof tmpl.vol);
237 		if (error)
238 			goto out;
239 
240 		tmpb.vol.vol[0] = tmpl.vol.channel0;
241 		tmpb.vol.vol[1] = tmpl.vol.channel1;
242 		tmpb.vol.vol[2] = tmpl.vol.channel2;
243 		tmpb.vol.vol[3] = tmpl.vol.channel3;
244 
245 		error = (*fp->f_ops->fo_ioctl)(fp, CDIOCSETVOL,
246 		    (caddr_t)&tmpb.vol, p);
247 		goto out;
248 	case LINUX_CDROMVOLREAD:
249 		error = (*fp->f_ops->fo_ioctl)(fp, CDIOCGETVOL,
250 		    (caddr_t)&tmpb.vol, p);
251 		if (error)
252 			goto out;
253 
254 		tmpl.vol.channel0 = tmpb.vol.vol[0];
255 		tmpl.vol.channel1 = tmpb.vol.vol[1];
256 		tmpl.vol.channel2 = tmpb.vol.vol[2];
257 		tmpl.vol.channel3 = tmpb.vol.vol[3];
258 
259 		error = copyout(&tmpl.vol, SCARG(uap, data), sizeof tmpl.vol);
260 		goto out;
261 	case LINUX_CDROMPAUSE:
262 		SCARG(&ia, com) = CDIOCPAUSE;
263 		break;
264 	case LINUX_CDROMRESUME:
265 		SCARG(&ia, com) = CDIOCRESUME;
266 		break;
267 	case LINUX_CDROMSTOP:
268 		SCARG(&ia, com) = CDIOCSTOP;
269 		break;
270 	case LINUX_CDROMSTART:
271 		SCARG(&ia, com) = CDIOCSTART;
272 		break;
273 	case LINUX_CDROMEJECT_SW:
274 		error = copyin(SCARG(uap, data), &arg, sizeof arg);
275 		if (error)
276 			goto out;
277 		SCARG(&ia, com) = arg ? CDIOCALLOW : CDIOCPREVENT;
278 		break;
279 	case LINUX_CDROMEJECT:
280 		SCARG(&ia, com) = CDIOCEJECT;
281 		break;
282 	case LINUX_CDROMRESET:
283 		SCARG(&ia, com) = CDIOCRESET;
284 		break;
285 	default:
286 	        printf("linux_ioctl_cdrom: invalid ioctl %08lx\n", com);
287 		error = EINVAL;
288 		goto out;
289 	}
290 
291 	SCARG(&ia, fd) = SCARG(uap, fd);
292 	SCARG(&ia, data) = SCARG(uap, data);
293 	error = sys_ioctl(p, &ia, retval);
294 
295 out:
296 	FRELE(fp);
297 	return (error);
298 }
299