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