diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index 012e3a27a5b2..11a64a752e1b 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -1909,7 +1909,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) struct cam_periph *periph; struct cd_softc *softc; - int error; + int error, nocopyout; periph = (struct cam_periph *)dp->d_drv1; if (periph == NULL) @@ -1940,6 +1940,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) } } + nocopyout = 0; switch (cmd) { case CDIOCPLAYTRACKS: @@ -2098,6 +2099,9 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) error = cdplay(periph, args->blk, args->len); } break; + case CDIOCREADSUBCHANNEL_SYSSPACE: + nocopyout = 1; + /* Fallthrough */ case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args @@ -2138,8 +2142,12 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) len = min(len, ((data->header.data_len[0] << 8) + data->header.data_len[1] + sizeof(struct cd_sub_channel_header))); - if (copyout(data, args->data, len) != 0) { - error = EFAULT; + if (nocopyout == 0) { + if (copyout(data, args->data, len) != 0) { + error = EFAULT; + } + } else { + bcopy(data, args->data, len); } free(data, M_TEMP); } diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index beb9e0c0aea6..20a2aa92f1b5 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -1490,30 +1490,29 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) case LINUX_CDROMSUBCHNL: { struct linux_cdrom_subchnl sc; struct ioc_read_subchannel bsdsc; - struct cd_sub_channel_info *bsdinfo; - caddr_t sg = stackgap_init(); - bsdinfo = stackgap_alloc(&sg, sizeof(*bsdinfo)); + struct cd_sub_channel_info bsdinfo; + bsdsc.address_format = CD_LBA_FORMAT; bsdsc.data_format = CD_CURRENT_POSITION; bsdsc.track = 0; - bsdsc.data_len = sizeof(*bsdinfo); - bsdsc.data = bsdinfo; - error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, - td->td_ucred, td); + bsdsc.data_len = sizeof(bsdinfo); + bsdsc.data = &bsdinfo; + error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE, + (caddr_t)&bsdsc, td->td_ucred, td); if (error) break; error = copyin((void *)args->arg, &sc, sizeof(sc)); if (error) break; - sc.cdsc_audiostatus = bsdinfo->header.audio_status; - sc.cdsc_adr = bsdinfo->what.position.addr_type; - sc.cdsc_ctrl = bsdinfo->what.position.control; - sc.cdsc_trk = bsdinfo->what.position.track_number; - sc.cdsc_ind = bsdinfo->what.position.index_number; + sc.cdsc_audiostatus = bsdinfo.header.audio_status; + sc.cdsc_adr = bsdinfo.what.position.addr_type; + sc.cdsc_ctrl = bsdinfo.what.position.control; + sc.cdsc_trk = bsdinfo.what.position.track_number; + sc.cdsc_ind = bsdinfo.what.position.index_number; set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format, - bsdinfo->what.position.absaddr.lba); + bsdinfo.what.position.absaddr.lba); set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format, - bsdinfo->what.position.reladdr.lba); + bsdinfo.what.position.reladdr.lba); error = copyout(&sc, (void *)args->arg, sizeof(sc)); break; } diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 9b86948c4ffc..4a7df8083459 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -553,7 +553,7 @@ static int acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct thread *td) { struct acd_softc *cdp = pp->geom->softc; - int error = 0; + int error = 0, nocopyout; if (!cdp) return ENXIO; @@ -574,6 +574,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct cdp->flags |= F_LOCKED; break; } + nocopyout = 0; switch (cmd) { case CDIOCRESUME: @@ -738,6 +739,9 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct } break; + case CDIOCREADSUBCHANNEL_SYSSPACE: + nocopyout = 1; + /* Fallthrough */ case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args = @@ -782,7 +786,12 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct break; } } - error = copyout(&cdp->subchan, args->data, args->data_len); + if (nocopyout == 0) { + error = copyout(&cdp->subchan, args->data, args->data_len); + } else { + error = 0; + bcopy(&cdp->subchan, args->data, args->data_len); + } } break; diff --git a/sys/dev/mcd/mcd.c b/sys/dev/mcd/mcd.c index db351909c652..e9cc575ecf2a 100644 --- a/sys/dev/mcd/mcd.c +++ b/sys/dev/mcd/mcd.c @@ -135,7 +135,8 @@ static void mcd_soft_reset(struct mcd_softc *); static int mcd_hard_reset(struct mcd_softc *); static int mcd_setmode(struct mcd_softc *, int mode); static int mcd_getqchan(struct mcd_softc *, struct mcd_qchninfo *q); -static int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc); +static int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc, + int nocopyout); static int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *th); static int mcd_read_toc(struct mcd_softc *); static int mcd_toc_entrys(struct mcd_softc *, struct ioc_read_toc_entry *te); @@ -440,8 +441,10 @@ MCD_TRACE("ioctl called 0x%lx\n", cmd); return mcd_playblocks(sc, (struct ioc_play_blocks *) addr); case CDIOCPLAYMSF: return mcd_playmsf(sc, (struct ioc_play_msf *) addr); + case CDIOCREADSUBCHANNEL_SYSSPACE: + return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); case CDIOCREADSUBCHANNEL: - return mcd_subchan(sc, (struct ioc_read_subchannel *) addr); + return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); case CDIOREADTOCHEADER: return mcd_toc_header(sc, (struct ioc_toc_header *) addr); case CDIOREADTOCENTRYS: @@ -1357,7 +1360,7 @@ mcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q) } static int -mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch) +mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) { struct mcd_qchninfo q; struct cd_sub_channel_info data; @@ -1423,7 +1426,10 @@ mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch) break; } - return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); + if (nocopyout == 0) + return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); + bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); + return (0) } static int diff --git a/sys/dev/scd/scd.c b/sys/dev/scd/scd.c index 1b00e02d2ae2..2c5f7966f506 100644 --- a/sys/dev/scd/scd.c +++ b/sys/dev/scd/scd.c @@ -131,7 +131,7 @@ static int scd_resume(struct scd_softc *); static int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt); static int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf); static int scd_play(struct scd_softc *, struct ioc_play_msf *msf); -static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch); +static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch, int nocopyout); static int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch); /* for xcdplayer */ @@ -350,8 +350,10 @@ scdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *t return (EINVAL); case CDIOCPLAYMSF: return scd_playmsf(sc, (struct ioc_play_msf *) addr); + case CDIOCREADSUBCHANNEL_SYSSPACE: + return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); case CDIOCREADSUBCHANNEL: - return scd_subchan(sc, (struct ioc_read_subchannel *) addr); + return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); case CDIOREADTOCHEADER: return scd_toc_header (sc, (struct ioc_toc_header *) addr); case CDIOREADTOCENTRYS: @@ -544,7 +546,7 @@ scd_eject(struct scd_softc *sc) } static int -scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch) +scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) { struct sony_subchannel_position_data q; struct cd_sub_channel_info data; @@ -573,8 +575,12 @@ scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch) data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1]); data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2]); - if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) - return (EFAULT); + if (nocopyout == 0) { + if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) + return (EFAULT); + } else { + bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); + } return (0); } diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h index a3eb271a7514..3614d19ee0d2 100644 --- a/sys/sys/cdio.h +++ b/sys/sys/cdio.h @@ -274,4 +274,11 @@ struct ioc_capability { /*<2>*/ #define CDIOCCAPABILITY _IOR('c',30,struct ioc_capability) /*<2>*/ +/* + * Special version of CDIOCREADSUBCHANNEL which assumes that + * ioc_read_subchannel->data points to the kernel memory. For + * use in compatibility layers. + */ +#define CDIOCREADSUBCHANNEL_SYSSPACE _IOWR('c', 31, struct ioc_read_subchannel) + #endif /* !_SYS_CDIO_H_ */