Exemplo n.º 1
0
int
mcdclose(dev_t dev, int flag, int fmt, struct lwp *l)
{
	struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	int part = MCDPART(dev);
	
	MCD_TRACE("close: partition=%d\n", part);

	mutex_enter(&sc->sc_lock);

	switch (fmt) {
	case S_IFCHR:
		sc->sc_dk.dk_copenmask &= ~(1 << part);
		break;
	case S_IFBLK:
		sc->sc_dk.dk_bopenmask &= ~(1 << part);
		break;
	}
	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;

	if (sc->sc_dk.dk_openmask == 0) {
		/* XXXX Must wait for I/O to complete! */

#if 0
		(void) mcd_setmode(sc, MCD_MD_SLEEP);
#endif
		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
	}

	mutex_exit(&sc->sc_lock);
	return 0;
}
Exemplo n.º 2
0
void
mcdattach(struct device *parent, struct device *self, void *aux)
{
	struct mcd_softc *sc = (void *)self;
	struct isa_attach_args *ia = aux;
	bus_space_tag_t iot = ia->ia_iot;
	bus_space_handle_t ioh;
	struct mcd_mbox mbx;

	/* Map i/o space */
	if (bus_space_map(iot, ia->ia_io[0].ir_addr, MCD_NPORT, 0, &ioh)) {
		printf(": can't map i/o space\n");
		return;
	}

	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);

	sc->sc_iot = iot;
	sc->sc_ioh = ioh;

	sc->probe = 0;
	sc->debug = 0;

	if (!mcd_find(iot, ioh, sc)) {
		printf(": mcd_find failed\n");
		return;
	}

	bufq_alloc(&sc->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK);
	callout_init(&sc->sc_pintr_ch, 0);

	/*
	 * Initialize and attach the disk structure.
	 */
	disk_init(&sc->sc_dk, device_xname(&sc->sc_dev), &mcddkdriver);
	disk_attach(&sc->sc_dk);

	printf(": model %s\n", sc->type != 0 ? sc->type : "unknown");

	(void) mcd_setlock(sc, MCD_LK_UNLOCK);

	mbx.cmd.opcode = MCD_CMDCONFIGDRIVE;
	mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1;
	mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE;
	mbx.cmd.data.config.data1 = 0x01;
	mbx.res.length = 0;
	(void) mcd_send(sc, &mbx, 0);

	mcd_soft_reset(sc);

	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
	    IST_EDGE, IPL_BIO, mcdintr, sc);
}
Exemplo n.º 3
0
int
mcdopen(dev_t dev, int flag, int fmt, struct lwp *l)
{
	int error, part;
	struct mcd_softc *sc;

	sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	if (sc == NULL)
		return ENXIO;

	mutex_enter(&sc->sc_lock);

	if (sc->sc_dk.dk_openmask != 0) {
		/*
		 * If any partition is open, but the disk has been invalidated,
		 * disallow further opens.
		 */
		if ((sc->flags & MCDF_LOADED) == 0) {
			error = EIO;
			goto bad3;
		}
	} else {
		/*
		 * Lock the drawer.  This will also notice any pending disk
		 * change or door open indicator and clear the MCDF_LOADED bit
		 * if necessary.
		 */
		(void) mcd_setlock(sc, MCD_LK_LOCK);

		if ((sc->flags & MCDF_LOADED) == 0) {
			/* Partially reset the state. */
			sc->lastmode = MCD_MD_UNKNOWN;
			sc->lastupc = MCD_UPC_UNKNOWN;

			sc->flags |= MCDF_LOADED;

			/* Set the mode, causing the disk to spin up. */
			if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
				goto bad2;

			/* Load the physical device parameters. */
			if (mcd_get_parms(sc) != 0) {
				error = ENXIO;
				goto bad2;
			}

			/* Read the table of contents. */
			if ((error = mcd_read_toc(sc)) != 0)
				goto bad2;

			/* Fabricate a disk label. */
			mcdgetdisklabel(sc);
		}
	}

	part = MCDPART(dev);

	MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part,
	    sc->disksize, sc->blksize);

	/* Check that the partition exists. */
	if (part != RAW_PART &&
	    (part >= sc->sc_dk.dk_label->d_npartitions ||
	     sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
		error = ENXIO;
		goto bad;
	}

	/* Insure only one open at a time. */
	switch (fmt) {
	case S_IFCHR:
		sc->sc_dk.dk_copenmask |= (1 << part);
		break;
	case S_IFBLK:
		sc->sc_dk.dk_bopenmask |= (1 << part);
		break;
	}
	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;

	mutex_exit(&sc->sc_lock);
	return 0;

bad2:
	sc->flags &= ~MCDF_LOADED;

bad:
	if (sc->sc_dk.dk_openmask == 0) {
#if 0
		(void) mcd_setmode(sc, MCD_MD_SLEEP);
#endif
		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
	}

bad3:
	mutex_exit(&sc->sc_lock);
	return error;
}
Exemplo n.º 4
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
}