1 /* $NetBSD: linux_cdrom.c,v 1.26 2008/03/21 21:54:58 ad Exp $ */
4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: linux_cdrom.c,v 1.26 2008/03/21 21:54:58 ad Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/ioctl.h>
36 #include <sys/filedesc.h>
37 #include <sys/mount.h>
40 #include <sys/dvdio.h>
41 #include <sys/malloc.h>
43 #include <sys/syscallargs.h>
45 #include <compat/linux/common/linux_types.h>
46 #include <compat/linux/common/linux_ioctl.h>
47 #include <compat/linux/common/linux_signal.h>
48 #include <compat/linux/common/linux_util.h>
49 #include <compat/linux/common/linux_ipc.h>
50 #include <compat/linux/common/linux_sem.h>
51 #include <compat/linux/common/linux_cdrom.h>
53 #include <compat/linux/linux_syscallargs.h>
55 static int bsd_to_linux_msf_lba(unsigned address_format
, union msf_lba
*bml
,
56 union linux_cdrom_addr
*llml
);
59 #define DPRINTF(x) uprintf x
65 * XXX from dev/scsipi/cd.c
70 bsd_to_linux_msf_lba(unsigned address_format
, union msf_lba
*bml
,
71 union linux_cdrom_addr
*llml
)
73 switch (address_format
) {
78 llml
->msf
.minute
= bml
->msf
.minute
;
79 llml
->msf
.second
= bml
->msf
.second
;
80 llml
->msf
.frame
= bml
->msf
.frame
;
89 linux_ioctl_cdrom(struct lwp
*l
, const struct linux_sys_ioctl_args
*uap
, register_t
*retval
)
93 syscallarg(u_long) com;
94 syscallarg(void *) data;
99 int (*ioctlf
)(file_t
*, u_long
, void *);
102 struct linux_cdrom_blk ll_blk
;
103 struct linux_cdrom_msf ll_msf
;
104 struct linux_cdrom_ti ll_ti
;
105 struct linux_cdrom_tochdr ll_tochdr
;
106 struct linux_cdrom_tocentry ll_tocentry
;
107 struct linux_cdrom_subchnl ll_subchnl
;
108 struct linux_cdrom_volctrl ll_volctrl
;
109 struct linux_cdrom_multisession ll_session
;
114 #define l_blk u1->ll_blk
115 #define l_msf u1->ll_msf
116 #define l_ti u1->ll_ti
117 #define l_tochdr u1->ll_tochdr
118 #define l_tocentry u1->ll_tocentry
119 #define l_subchnl u1->ll_subchnl
120 #define l_volctrl u1->ll_volctrl
121 #define l_session u1->ll_session
123 #define dai u1->ll_dai
126 struct ioc_play_blocks tt_blocks
;
127 struct ioc_play_msf tt_msf
;
128 struct ioc_play_track tt_track
;
129 struct ioc_toc_header tt_header
;
130 struct ioc_read_toc_entry_buf tt_toc_entry
;
131 struct ioc_read_subchannel_buf tt_subchannel
;
132 struct ioc_vol tt_vol
;
135 #define t_blocks u2->tt_blocks
136 #define t_msf u2->tt_msf
137 #define t_track u2->tt_track
138 #define t_header u2->tt_header
139 #define t_toc_entry u2->tt_toc_entry
140 #define t_subchannel u2->tt_subchannel
141 #define t_vol u2->tt_vol
143 struct cd_toc_entry
*entry
;
145 if ((fp
= fd_getfile(SCARG(uap
, fd
))) == NULL
)
148 com
= SCARG(uap
, com
);
149 ioctlf
= fp
->f_ops
->fo_ioctl
;
150 retval
[0] = error
= 0;
152 u1
= malloc(sizeof(*u1
), M_TEMP
, M_WAITOK
);
153 u2
= malloc(sizeof(*u2
), M_TEMP
, M_WAITOK
);
156 case LINUX_CDROMPLAYMSF
:
157 error
= copyin(SCARG(uap
, data
), &l_msf
, sizeof l_msf
);
161 t_msf
.start_m
= l_msf
.cdmsf_min0
;
162 t_msf
.start_s
= l_msf
.cdmsf_sec0
;
163 t_msf
.start_f
= l_msf
.cdmsf_frame0
;
164 t_msf
.end_m
= l_msf
.cdmsf_min1
;
165 t_msf
.end_s
= l_msf
.cdmsf_sec1
;
166 t_msf
.end_f
= l_msf
.cdmsf_frame1
;
168 error
= ioctlf(fp
, CDIOCPLAYMSF
, &t_msf
);
171 case LINUX_CDROMPLAYTRKIND
:
172 error
= copyin(SCARG(uap
, data
), &l_ti
, sizeof l_ti
);
176 t_track
.start_track
= l_ti
.cdti_trk0
;
177 t_track
.start_index
= l_ti
.cdti_ind0
;
178 t_track
.end_track
= l_ti
.cdti_trk1
;
179 t_track
.end_index
= l_ti
.cdti_ind1
;
181 error
= ioctlf(fp
, CDIOCPLAYTRACKS
, &t_track
);
184 case LINUX_CDROMREADTOCHDR
:
185 error
= ioctlf(fp
, CDIOREADTOCHEADER
, &t_header
);
189 l_tochdr
.cdth_trk0
= t_header
.starting_track
;
190 l_tochdr
.cdth_trk1
= t_header
.ending_track
;
192 error
= copyout(&l_tochdr
, SCARG(uap
, data
), sizeof l_tochdr
);
195 case LINUX_CDROMREADTOCENTRY
:
196 error
= copyin(SCARG(uap
, data
), &l_tocentry
,
201 t_toc_entry
.req
.address_format
= l_tocentry
.cdte_format
;
202 t_toc_entry
.req
.starting_track
= l_tocentry
.cdte_track
;
203 t_toc_entry
.req
.data_len
= sizeof *entry
;
204 t_toc_entry
.req
.data
= NULL
;
206 error
= ioctlf(fp
, CDIOREADTOCENTRIES_BUF
, &t_toc_entry
);
210 l_tocentry
.cdte_adr
= t_toc_entry
.entry
[0].addr_type
;
211 l_tocentry
.cdte_ctrl
= t_toc_entry
.entry
[0].control
;
212 if (bsd_to_linux_msf_lba(t_toc_entry
.entry
[0].addr_type
,
213 &t_toc_entry
.entry
[0].addr
, &l_tocentry
.cdte_addr
) < 0) {
214 DPRINTF(("linux_ioctl: unknown format msf/lba\n"));
219 error
= copyout(&l_tocentry
, SCARG(uap
, data
),
223 case LINUX_CDROMVOLCTRL
:
224 error
= copyin(SCARG(uap
, data
), &l_volctrl
, sizeof l_volctrl
);
228 t_vol
.vol
[0] = l_volctrl
.channel0
;
229 t_vol
.vol
[1] = l_volctrl
.channel1
;
230 t_vol
.vol
[2] = l_volctrl
.channel2
;
231 t_vol
.vol
[3] = l_volctrl
.channel3
;
233 error
= ioctlf(fp
, CDIOCSETVOL
, &t_vol
);
236 case LINUX_CDROMVOLREAD
:
237 error
= ioctlf(fp
, CDIOCGETVOL
, &t_vol
);
241 l_volctrl
.channel0
= t_vol
.vol
[0];
242 l_volctrl
.channel1
= t_vol
.vol
[1];
243 l_volctrl
.channel2
= t_vol
.vol
[2];
244 l_volctrl
.channel3
= t_vol
.vol
[3];
246 error
= copyout(&l_volctrl
, SCARG(uap
, data
), sizeof l_volctrl
);
249 case LINUX_CDROMSUBCHNL
:
250 error
= copyin(SCARG(uap
, data
), &l_subchnl
, sizeof l_subchnl
);
254 t_subchannel
.req
.address_format
= CD_MSF_FORMAT
;
255 t_subchannel
.req
.track
= 0;
256 t_subchannel
.req
.data_format
= l_subchnl
.cdsc_format
;
257 t_subchannel
.req
.data_len
= sizeof t_subchannel
.info
;
258 t_subchannel
.req
.data
= NULL
;
259 DPRINTF(("linux_ioctl: CDROMSUBCHNL %d %d\n",
260 l_subchnl
.cdsc_format
, l_subchnl
.cdsc_trk
));
262 error
= ioctlf(fp
, CDIOCREADSUBCHANNEL_BUF
, &t_subchannel
);
266 l_subchnl
.cdsc_audiostatus
= t_subchannel
.info
.header
.audio_status
;
267 l_subchnl
.cdsc_adr
= t_subchannel
.info
.what
.position
.addr_type
;
268 l_subchnl
.cdsc_ctrl
= t_subchannel
.info
.what
.position
.control
;
269 l_subchnl
.cdsc_ind
= t_subchannel
.info
.what
.position
.index_number
;
271 DPRINTF(("linux_ioctl: CDIOCREADSUBCHANNEL %d %d %d\n",
272 t_subchannel
.info
.header
.audio_status
,
273 t_subchannel
.info
.header
.data_len
[0],
274 t_subchannel
.info
.header
.data_len
[1]));
275 DPRINTF(("(more) %d %d %d %d %d\n",
276 t_subchannel
.info
.what
.position
.data_format
,
277 t_subchannel
.info
.what
.position
.control
,
278 t_subchannel
.info
.what
.position
.addr_type
,
279 t_subchannel
.info
.what
.position
.track_number
,
280 t_subchannel
.info
.what
.position
.index_number
));
282 if (bsd_to_linux_msf_lba(t_subchannel
.req
.address_format
,
283 &t_subchannel
.info
.what
.position
.absaddr
,
284 &l_subchnl
.cdsc_absaddr
) < 0 ||
285 bsd_to_linux_msf_lba(t_subchannel
.req
.address_format
,
286 &t_subchannel
.info
.what
.position
.reladdr
,
287 &l_subchnl
.cdsc_reladdr
) < 0) {
288 DPRINTF(("linux_ioctl: unknown format msf/lba\n"));
293 error
= copyout(&l_subchnl
, SCARG(uap
, data
), sizeof l_subchnl
);
296 case LINUX_CDROMPLAYBLK
:
297 error
= copyin(SCARG(uap
, data
), &l_blk
, sizeof l_blk
);
301 t_blocks
.blk
= l_blk
.from
;
302 t_blocks
.len
= l_blk
.len
;
304 error
= ioctlf(fp
, CDIOCPLAYBLOCKS
, &t_blocks
);
307 case LINUX_CDROMEJECT_SW
:
308 error
= copyin(SCARG(uap
, data
), &idata
, sizeof idata
);
316 error
= ioctlf(fp
, ncom
, NULL
);
319 case LINUX_CDROMPAUSE
:
320 error
= ioctlf(fp
, CDIOCPAUSE
, NULL
);
323 case LINUX_CDROMRESUME
:
324 error
= ioctlf(fp
, CDIOCRESUME
, NULL
);
327 case LINUX_CDROMSTOP
:
328 error
= ioctlf(fp
, CDIOCSTOP
, NULL
);
331 case LINUX_CDROMSTART
:
332 error
= ioctlf(fp
, CDIOCSTART
, NULL
);
335 case LINUX_CDROMEJECT
:
336 error
= ioctlf(fp
, CDIOCEJECT
, NULL
);
339 case LINUX_CDROMRESET
:
340 error
= ioctlf(fp
, CDIOCRESET
, NULL
);
343 case LINUX_CDROMMULTISESSION
:
344 error
= copyin(SCARG(uap
, data
), &l_session
, sizeof l_session
);
348 error
= ioctlf(fp
, CDIOREADTOCHEADER
, &t_header
);
352 t_toc_entry
.req
.address_format
= l_session
.addr_format
;
353 t_toc_entry
.req
.starting_track
= 0;
354 t_toc_entry
.req
.data_len
= sizeof t_toc_entry
.entry
;
355 t_toc_entry
.req
.data
= NULL
;
357 error
= ioctlf(fp
, CDIOREADTOCENTRIES_BUF
, &t_toc_entry
);
361 if (bsd_to_linux_msf_lba(l_session
.addr_format
,
362 &t_toc_entry
.entry
[0].addr
, &l_session
.addr
) < 0) {
368 t_header
.starting_track
!= t_header
.ending_track
;
370 error
= copyout(&l_session
, SCARG(uap
, data
), sizeof l_session
);
373 case LINUX_CDROMCLOSETRAY
:
374 error
= ioctlf(fp
, CDIOCCLOSE
, NULL
);
377 case LINUX_CDROM_LOCKDOOR
:
378 ncom
= SCARG(uap
, data
) != 0 ? CDIOCPREVENT
: CDIOCALLOW
;
379 error
= ioctlf(fp
, ncom
, NULL
);
382 case LINUX_CDROM_SET_OPTIONS
:
383 case LINUX_CDROM_CLEAR_OPTIONS
:
384 /* whatever you say */
387 case LINUX_CDROM_DEBUG
:
388 ncom
= SCARG(uap
, data
) != 0 ? CDIOCSETDEBUG
: CDIOCCLRDEBUG
;
389 error
= ioctlf(fp
, ncom
, NULL
);
392 case LINUX_CDROM_SELECT_SPEED
:
393 case LINUX_CDROM_SELECT_DISC
:
394 case LINUX_CDROM_MEDIA_CHANGED
:
395 case LINUX_CDROM_DRIVE_STATUS
:
396 case LINUX_CDROM_DISC_STATUS
:
397 case LINUX_CDROM_CHANGER_NSLOTS
:
398 case LINUX_CDROM_GET_CAPABILITY
:
402 case LINUX_DVD_READ_STRUCT
:
403 error
= copyin(SCARG(uap
, data
), &ds
, sizeof ds
);
406 error
= ioctlf(fp
, DVD_READ_STRUCT
, &ds
);
409 error
= copyout(&ds
, SCARG(uap
, data
), sizeof ds
);
412 case LINUX_DVD_WRITE_STRUCT
:
413 error
= copyin(SCARG(uap
, data
), &ds
, sizeof ds
);
416 error
= ioctlf(fp
, DVD_WRITE_STRUCT
, &ds
);
419 error
= copyout(&ds
, SCARG(uap
, data
), sizeof ds
);
423 error
= copyin(SCARG(uap
, data
), &dai
, sizeof dai
);
426 error
= ioctlf(fp
, DVD_AUTH
, &dai
);
429 error
= copyout(&dai
, SCARG(uap
, data
), sizeof dai
);
434 DPRINTF(("linux_ioctl: unimplemented ioctl %08lx\n", com
));
438 fd_putfile(SCARG(uap
, fd
));