1 /* $NetBSD: linux_cdrom.c,v 1.6 2000/12/10 14:12:16 fvdl 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 #include <sys/dvdio.h> 45 46 #include <sys/syscallargs.h> 47 48 #include <compat/linux/common/linux_types.h> 49 #include <compat/linux/common/linux_ioctl.h> 50 #include <compat/linux/common/linux_signal.h> 51 #include <compat/linux/common/linux_util.h> 52 #include <compat/linux/common/linux_cdrom.h> 53 54 #include <compat/linux/linux_syscallargs.h> 55 56 static int bsd_to_linux_msf_lba(unsigned address_format, union msf_lba *bml, 57 union linux_cdrom_addr *llml); 58 59 #if 0 60 #define DPRINTF(x) printf x 61 #else 62 #define DPRINTF(x) 63 #endif 64 65 /* 66 * XXX from dev/scsipi/cd.c 67 */ 68 #define MAXTRACK 99 69 70 static int 71 bsd_to_linux_msf_lba(unsigned address_format, union msf_lba *bml, 72 union linux_cdrom_addr *llml) 73 { 74 switch (address_format) { 75 case CD_LBA_FORMAT: 76 llml->lba = bml->lba; 77 break; 78 case CD_MSF_FORMAT: 79 llml->msf.minute = bml->msf.minute; 80 llml->msf.second = bml->msf.second; 81 llml->msf.frame = bml->msf.frame; 82 break; 83 default: 84 return -1; 85 } 86 return 0; 87 } 88 89 int 90 linux_ioctl_cdrom(p, uap, retval) 91 struct proc *p; 92 struct linux_sys_ioctl_args /* { 93 syscallarg(int) fd; 94 syscallarg(u_long) com; 95 syscallarg(caddr_t) data; 96 } */ *uap; 97 register_t *retval; 98 { 99 int error, idata; 100 u_long com, ncom; 101 caddr_t sg; 102 struct file *fp; 103 struct filedesc *fdp; 104 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)); 105 106 struct linux_cdrom_blk l_blk; 107 struct linux_cdrom_msf l_msf; 108 struct linux_cdrom_ti l_ti; 109 struct linux_cdrom_tochdr l_tochdr; 110 struct linux_cdrom_tocentry l_tocentry; 111 struct linux_cdrom_subchnl l_subchnl; 112 struct linux_cdrom_volctrl l_volctrl; 113 struct linux_cdrom_multisession l_session; 114 115 struct ioc_play_blocks t_blocks; 116 struct ioc_play_msf t_msf; 117 struct ioc_play_track t_track; 118 struct ioc_toc_header t_header; 119 struct cd_toc_entry *entry, t_entry; 120 struct ioc_read_toc_entry t_toc_entry; 121 struct cd_sub_channel_info *info, t_info; 122 struct ioc_read_subchannel t_subchannel; 123 struct ioc_vol t_vol; 124 125 dvd_struct ds; 126 dvd_authinfo dai; 127 128 fdp = p->p_fd; 129 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 130 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 131 (fp->f_iflags & FIF_WANTCLOSE) != 0) 132 return (EBADF); 133 134 FILE_USE(fp); 135 136 com = SCARG(uap, com); 137 ioctlf = fp->f_ops->fo_ioctl; 138 retval[0] = error = 0; 139 140 switch(com) { 141 case LINUX_CDROMPLAYMSF: 142 error = copyin(SCARG(uap, data), &l_msf, sizeof l_msf); 143 if (error) 144 break; 145 146 t_msf.start_m = l_msf.cdmsf_min0; 147 t_msf.start_s = l_msf.cdmsf_sec0; 148 t_msf.start_f = l_msf.cdmsf_frame0; 149 t_msf.end_m = l_msf.cdmsf_min1; 150 t_msf.end_s = l_msf.cdmsf_sec1; 151 t_msf.end_f = l_msf.cdmsf_frame1; 152 153 error = ioctlf(fp, CDIOCPLAYMSF, (caddr_t)&t_msf, p); 154 break; 155 156 case LINUX_CDROMPLAYTRKIND: 157 error = copyin(SCARG(uap, data), &l_ti, sizeof l_ti); 158 if (error) 159 break; 160 161 t_track.start_track = l_ti.cdti_trk0; 162 t_track.start_index = l_ti.cdti_ind0; 163 t_track.end_track = l_ti.cdti_trk1; 164 t_track.end_index = l_ti.cdti_ind1; 165 166 error = ioctlf(fp, CDIOCPLAYTRACKS, (caddr_t)&t_track, p); 167 break; 168 169 case LINUX_CDROMREADTOCHDR: 170 error = ioctlf(fp, CDIOREADTOCHEADER, (caddr_t)&t_header, p); 171 if (error) 172 break; 173 174 l_tochdr.cdth_trk0 = t_header.starting_track; 175 l_tochdr.cdth_trk1 = t_header.ending_track; 176 177 error = copyout(&l_tochdr, SCARG(uap, data), sizeof l_tochdr); 178 break; 179 180 case LINUX_CDROMREADTOCENTRY: 181 error = copyin(SCARG(uap, data), &l_tocentry, 182 sizeof l_tocentry); 183 if (error) 184 break; 185 186 sg = stackgap_init(p->p_emul); 187 entry = stackgap_alloc(&sg, sizeof *entry); 188 t_toc_entry.address_format = l_tocentry.cdte_format; 189 t_toc_entry.starting_track = l_tocentry.cdte_track; 190 t_toc_entry.data_len = sizeof *entry; 191 t_toc_entry.data = entry; 192 193 error = ioctlf(fp, CDIOREADTOCENTRIES, (caddr_t)&t_toc_entry, 194 p); 195 if (error) 196 break; 197 198 error = copyin(entry, &t_entry, sizeof t_entry); 199 if (error) 200 break; 201 202 l_tocentry.cdte_adr = t_entry.addr_type; 203 l_tocentry.cdte_ctrl = t_entry.control; 204 if (bsd_to_linux_msf_lba(t_entry.addr_type, &t_entry.addr, 205 &l_tocentry.cdte_addr) < 0) { 206 printf("linux_ioctl: unknown format msf/lba\n"); 207 error = EINVAL; 208 break; 209 } 210 211 error = copyout(&l_tocentry, SCARG(uap, data), 212 sizeof l_tocentry); 213 break; 214 215 case LINUX_CDROMVOLCTRL: 216 error = copyin(SCARG(uap, data), &l_volctrl, sizeof l_volctrl); 217 if (error) 218 break; 219 220 t_vol.vol[0] = l_volctrl.channel0; 221 t_vol.vol[1] = l_volctrl.channel1; 222 t_vol.vol[2] = l_volctrl.channel2; 223 t_vol.vol[3] = l_volctrl.channel3; 224 225 error = ioctlf(fp, CDIOCSETVOL, (caddr_t)&t_vol, p); 226 break; 227 228 case LINUX_CDROMVOLREAD: 229 error = ioctlf(fp, CDIOCGETVOL, (caddr_t)&t_vol, p); 230 if (error) 231 break; 232 233 l_volctrl.channel0 = t_vol.vol[0]; 234 l_volctrl.channel1 = t_vol.vol[1]; 235 l_volctrl.channel2 = t_vol.vol[2]; 236 l_volctrl.channel3 = t_vol.vol[3]; 237 238 error = copyout(&l_volctrl, SCARG(uap, data), sizeof l_volctrl); 239 break; 240 241 case LINUX_CDROMSUBCHNL: 242 error = copyin(SCARG(uap, data), &l_subchnl, sizeof l_subchnl); 243 if (error) 244 break; 245 246 sg = stackgap_init(p->p_emul); 247 info = stackgap_alloc(&sg, sizeof *info); 248 t_subchannel.address_format = l_subchnl.cdsc_format; 249 t_subchannel.data_format = CD_CURRENT_POSITION; 250 t_subchannel.track = l_subchnl.cdsc_trk; 251 t_subchannel.data_len = sizeof *info; 252 t_subchannel.data = info; 253 DPRINTF(("linux_ioctl: CDROMSUBCHNL %d %d\n", 254 l_subchnl.cdsc_format, l_subchnl.cdsc_trk)); 255 256 error = ioctlf(fp, CDIOCREADSUBCHANNEL, (caddr_t)&t_subchannel, 257 p); 258 if (error) 259 break; 260 261 error = copyin(info, &t_info, sizeof t_info); 262 if (error) 263 break; 264 265 l_subchnl.cdsc_audiostatus = t_info.header.audio_status; 266 l_subchnl.cdsc_adr = t_info.what.position.addr_type; 267 l_subchnl.cdsc_ctrl = t_info.what.position.control; 268 l_subchnl.cdsc_ind = t_info.what.position.index_number; 269 270 DPRINTF(("linux_ioctl: CDIOCREADSUBCHANNEL %d %d %d\n", 271 t_info.header.audio_status, 272 t_info.header.data_len[0], 273 t_info.header.data_len[1])); 274 DPRINTF(("(more) %d %d %d %d %d\n", 275 t_info.what.position.data_format, 276 t_info.what.position.control, 277 t_info.what.position.addr_type, 278 t_info.what.position.track_number, 279 t_info.what.position.index_number)); 280 281 if (bsd_to_linux_msf_lba(t_subchannel.address_format, 282 &t_info.what.position.absaddr, 283 &l_subchnl.cdsc_absaddr) < 0 || 284 bsd_to_linux_msf_lba(t_subchannel.address_format, 285 &t_info.what.position.reladdr, 286 &l_subchnl.cdsc_reladdr) < 0) { 287 DPRINTF(("linux_ioctl: unknown format msf/lba\n")); 288 error = EINVAL; 289 break; 290 } 291 292 error = copyout(&l_subchnl, SCARG(uap, data), sizeof l_subchnl); 293 break; 294 295 case LINUX_CDROMPLAYBLK: 296 error = copyin(SCARG(uap, data), &l_blk, sizeof l_blk); 297 if (error) 298 break; 299 300 t_blocks.blk = l_blk.from; 301 t_blocks.len = l_blk.len; 302 303 error = ioctlf(fp, CDIOCPLAYBLOCKS, (caddr_t)&t_blocks, p); 304 break; 305 306 case LINUX_CDROMEJECT_SW: 307 error = copyin(SCARG(uap, data), &idata, sizeof idata); 308 if (error) 309 break; 310 311 if (idata == 1) 312 ncom = CDIOCALLOW; 313 else 314 ncom = CDIOCPREVENT; 315 error = ioctlf(fp, ncom, NULL, p); 316 break; 317 318 case LINUX_CDROMPAUSE: 319 error = ioctlf(fp, CDIOCPAUSE, NULL, p); 320 break; 321 322 case LINUX_CDROMRESUME: 323 error = ioctlf(fp, CDIOCRESUME, NULL, p); 324 break; 325 326 case LINUX_CDROMSTOP: 327 error = ioctlf(fp, CDIOCSTOP, NULL, p); 328 break; 329 330 case LINUX_CDROMSTART: 331 error = ioctlf(fp, CDIOCSTART, NULL, p); 332 break; 333 334 case LINUX_CDROMEJECT: 335 error = ioctlf(fp, CDIOCEJECT, NULL, p); 336 break; 337 338 case LINUX_CDROMRESET: 339 error = ioctlf(fp, CDIOCRESET, NULL, p); 340 break; 341 342 case LINUX_CDROMMULTISESSION: 343 error = copyin(SCARG(uap, data), &l_session, sizeof l_session); 344 if (error) 345 break; 346 347 error = ioctlf(fp, CDIOREADTOCHEADER, (caddr_t)&t_header, p); 348 if (error) 349 break; 350 351 sg = stackgap_init(p->p_emul); 352 entry = stackgap_alloc(&sg, sizeof *entry); 353 t_toc_entry.address_format = l_session.addr_format; 354 t_toc_entry.starting_track = 0; 355 t_toc_entry.data_len = sizeof *entry; 356 t_toc_entry.data = entry; 357 358 error = ioctlf(fp, CDIOREADTOCENTRIES, 359 (caddr_t)&t_toc_entry, p); 360 if (error) 361 break; 362 363 error = copyin(entry, &t_entry, sizeof t_entry); 364 if (error) 365 break; 366 367 if (bsd_to_linux_msf_lba(l_session.addr_format, 368 &t_entry.addr, &l_session.addr) < 0) { 369 error = EINVAL; 370 break; 371 } 372 373 l_session.xa_flag = 374 t_header.starting_track != t_header.ending_track; 375 376 error = copyout(&l_session, SCARG(uap, data), sizeof l_session); 377 break; 378 379 case LINUX_CDROMCLOSETRAY: 380 error = ioctlf(fp, CDIOCCLOSE, NULL, p); 381 break; 382 383 case LINUX_CDROM_LOCKDOOR: 384 ncom = SCARG(uap, data) != 0 ? CDIOCPREVENT : CDIOCALLOW; 385 error = ioctlf(fp, ncom, NULL, p); 386 break; 387 388 case LINUX_CDROM_SET_OPTIONS: 389 case LINUX_CDROM_CLEAR_OPTIONS: 390 /* whatever you say */ 391 break; 392 393 case LINUX_CDROM_DEBUG: 394 ncom = SCARG(uap, data) != 0 ? CDIOCSETDEBUG : CDIOCCLRDEBUG; 395 error = ioctlf(fp, ncom, NULL, p); 396 break; 397 398 case LINUX_CDROM_SELECT_SPEED: 399 case LINUX_CDROM_SELECT_DISC: 400 case LINUX_CDROM_MEDIA_CHANGED: 401 case LINUX_CDROM_DRIVE_STATUS: 402 case LINUX_CDROM_DISC_STATUS: 403 case LINUX_CDROM_CHANGER_NSLOTS: 404 case LINUX_CDROM_GET_CAPABILITY: 405 error = EINVAL; 406 break; 407 408 case LINUX_DVD_READ_STRUCT: 409 error = copyin(SCARG(uap, data), &ds, sizeof ds); 410 if (error) 411 break; 412 error = ioctlf(fp, DVD_READ_STRUCT, (caddr_t)&ds, p); 413 if (error) 414 break; 415 error = copyout(&ds, SCARG(uap, data), sizeof ds); 416 break; 417 418 case LINUX_DVD_WRITE_STRUCT: 419 error = copyin(SCARG(uap, data), &ds, sizeof ds); 420 if (error) 421 break; 422 error = ioctlf(fp, DVD_WRITE_STRUCT, (caddr_t)&ds, p); 423 if (error) 424 break; 425 error = copyout(&ds, SCARG(uap, data), sizeof ds); 426 break; 427 428 case LINUX_DVD_AUTH: 429 error = copyin(SCARG(uap, data), &dai, sizeof dai); 430 if (error) 431 break; 432 error = ioctlf(fp, DVD_AUTH, (caddr_t)&dai, p); 433 if (error) 434 break; 435 error = copyout(&dai, SCARG(uap, data), sizeof dai); 436 break; 437 438 439 default: 440 DPRINTF(("linux_ioctl: unimplemented ioctl %08lx\n", com)); 441 error = EINVAL; 442 } 443 444 FILE_UNUSE(fp, p); 445 return error; 446 } 447