Exemplo n.º 1
0
Arquivo: mcd.c Projeto: MarginC/kame
static int
mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
	struct mcd_softc *sc;
	int retry,r;

	sc = (struct mcd_softc *)dev->si_drv1;

	if (mcd_getstat(sc, 1) == -1) /* detect disk change too */
		return (EIO);
MCD_TRACE("ioctl called 0x%lx\n", cmd);

	switch (cmd) {
	case CDIOCSETPATCH:
	case CDIOCGETVOL:
	case CDIOCSETVOL:
	case CDIOCSETMONO:
	case CDIOCSETSTERIO:
	case CDIOCSETMUTE:
	case CDIOCSETLEFT:
	case CDIOCSETRIGHT:
		return (EINVAL);
	case CDIOCEJECT:
		return mcd_eject(sc);
	case CDIOCSETDEBUG:
		sc->data.debug = 1;
		return (0);
	case CDIOCCLRDEBUG:
		sc->data.debug = 0;
		return (0);
	case CDIOCRESET:
		return mcd_hard_reset(sc);
	case CDIOCALLOW:
		return mcd_lock_door(sc, MCD_LK_UNLOCK);
	case CDIOCPREVENT:
		return mcd_lock_door(sc, MCD_LK_LOCK);
	case CDIOCCLOSE:
		return mcd_inject(sc);
	}

	if (!(sc->data.flags & MCDVALID)) {
		if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
		    || !(sc->data.status & MCDDSKIN))
			for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
				(void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC);
				if ((r = mcd_getstat(sc, 1)) == -1)
					return (EIO);
				if (r != -2)
					break;
			}
		if (   (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG))
		    || !(sc->data.status & MCDDSKIN)
		    || mcdsize(dev) < 0
		   )
			return (ENXIO);
		sc->data.flags |= MCDVALID;
		sc->data.partflags |= MCDREADRAW;
		(void) mcd_lock_door(sc, MCD_LK_LOCK);
		if (!(sc->data.flags & MCDVALID))
			return (ENXIO);
	}

	switch (cmd) {
	case DIOCGMEDIASIZE:
		*(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize;
		return (0);
		break;
	case DIOCGSECTORSIZE:
		*(u_int *)addr = sc->data.blksize;
		return (0);
		break;

	case CDIOCPLAYTRACKS:
		return mcd_playtracks(sc, (struct ioc_play_track *) addr);
	case CDIOCPLAYBLOCKS:
		return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
	case CDIOCPLAYMSF:
		return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
	case CDIOCREADSUBCHANNEL:
		return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
	case CDIOREADTOCHEADER:
		return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
	case CDIOREADTOCENTRYS:
		return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr);
	case CDIOCRESUME:
		return mcd_resume(sc);
	case CDIOCPAUSE:
		return mcd_pause(sc);
	case CDIOCSTART:
		if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
			return (EIO);
		return (0);
	case CDIOCSTOP:
		return mcd_stop(sc);
	default:
		return (ENOTTY);
	}
	/*NOTREACHED*/
}
Exemplo n.º 2
0
int
mcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
	struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	int error;
	int part;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif
	
	MCD_TRACE("ioctl: cmd=0x%lx\n", cmd);

	if ((sc->flags & MCDF_LOADED) == 0)
		return EIO;

	error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l);
	if (error != EPASSTHROUGH)
		return error;

	part = MCDPART(dev);
	switch (cmd) {
	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
	{
		struct disklabel *lp;

		if ((flag & FWRITE) == 0)
			return EBADF;

#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = addr;

		mutex_enter(&sc->sc_lock);
		sc->flags |= MCDF_LABELLING;

		error = setdisklabel(sc->sc_dk.dk_label,
		    lp, /*sc->sc_dk.dk_openmask : */0,
		    sc->sc_dk.dk_cpulabel);
		if (error == 0) {
		}

		sc->flags &= ~MCDF_LABELLING;
		mutex_exit(&sc->sc_lock);
		return error;
	}

	case DIOCWLABEL:
		return EBADF;

	case DIOCGDEFLABEL:
		mcdgetdefaultlabel(sc, addr);
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		mcdgetdefaultlabel(sc, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
		return 0;
#endif

	case CDIOCPLAYTRACKS:
		return mcd_playtracks(sc, addr);
	case CDIOCPLAYMSF:
		return mcd_playmsf(sc, addr);
	case CDIOCPLAYBLOCKS:
		return mcd_playblocks(sc, addr);
	case CDIOCREADSUBCHANNEL: {
		struct cd_sub_channel_info info;
		error = mcd_read_subchannel(sc, addr, &info);
		if (error != 0) {
			struct ioc_read_subchannel *ch = addr;
			error = copyout(&info, ch->data, ch->data_len);
		}
		return error;
	}
	case CDIOCREADSUBCHANNEL_BUF:
		return mcd_read_subchannel(sc, addr,
		    &((struct ioc_read_subchannel_buf *)addr)->info);
	case CDIOREADTOCHEADER:
		return mcd_toc_header(sc, addr);
	case CDIOREADTOCENTRYS: {
		struct cd_toc_entry entries[MCD_MAXTOCS];
		struct ioc_read_toc_entry *te = addr;
		int count;
		if (te->data_len > sizeof entries)
			return EINVAL;
		error = mcd_toc_entries(sc, te, entries, &count);
		if (error == 0)
			/* Copy the data back. */
			error = copyout(entries, te->data, min(te->data_len,
					count * sizeof(struct cd_toc_entry)));
		return error;
	}
	case CDIOREADTOCENTRIES_BUF: {
		struct ioc_read_toc_entry_buf *te = addr;
		int count;
		if (te->req.data_len > sizeof te->entry)
			return EINVAL;
		return mcd_toc_entries(sc, &te->req, te->entry, &count);
	}
	case CDIOCSETPATCH:
	case CDIOCGETVOL:
	case CDIOCSETVOL:
	case CDIOCSETMONO:
	case CDIOCSETSTEREO:
	case CDIOCSETMUTE:
	case CDIOCSETLEFT:
	case CDIOCSETRIGHT:
		return EINVAL;
	case CDIOCRESUME:
		return mcd_resume(sc);
	case CDIOCPAUSE:
		return mcd_pause(sc);
	case CDIOCSTART:
		return EINVAL;
	case CDIOCSTOP:
		return mcd_stop(sc);
	case DIOCEJECT:
		if (*(int *)addr == 0) {
			/*
			 * Don't force eject: check that we are the only
			 * partition open. If so, unlock it.
			 */
			if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
			    sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask ==
			    sc->sc_dk.dk_openmask) {
				error = mcd_setlock(sc, MCD_LK_UNLOCK);
				if (error)
					return (error);
			} else {
				return (EBUSY);
			}
		}
		/* FALLTHROUGH */
	case CDIOCEJECT: /* FALLTHROUGH */
	case ODIOCEJECT:
		return mcd_eject(sc);
	case CDIOCALLOW:
		return mcd_setlock(sc, MCD_LK_UNLOCK);
	case CDIOCPREVENT:
		return mcd_setlock(sc, MCD_LK_LOCK);
	case DIOCLOCK:
		return mcd_setlock(sc,
		    (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK);
	case CDIOCSETDEBUG:
		sc->debug = 1;
		return 0;
	case CDIOCCLRDEBUG:
		sc->debug = 0;
		return 0;
	case CDIOCRESET:
		return mcd_hard_reset(sc);

	default:
		return ENOTTY;
	}

#ifdef DIAGNOSTIC
	panic("mcdioctl: impossible");
#endif
}