Exemple #1
0
static struct xbd_softc *
getxbd_softc(dev_t dev)
{
	int	unit = XBDUNIT(dev);

	DPRINTF_FOLLOW(("getxbd_softc(0x%x): major = %d unit = %d\n", dev,
	    major(dev), unit));
#if NXBD > 0
	if (major(dev) == xbd_major)
		return device_lookup(&xbd_cd, unit);
#endif
#if NWD > 0
	if (major(dev) == xbd_wd_major || major(dev) == xbd_wd_cdev_major)
		return device_lookup(&wd_cd, unit);
#endif
#if NSD > 0
	if (major(dev) == xbd_sd_major || major(dev) == xbd_sd_cdev_major)
		return device_lookup(&sd_cd, unit);
#endif
#if NCD > 0
	if (major(dev) == xbd_cd_major || major(dev) == xbd_cd_cdev_major)
		return device_lookup(&cd_cd, unit);
#endif
	return NULL;
}
Exemple #2
0
/*
 * device_open - open the specified device.
 *
 * Even if the target driver does not have an open
 * routine, this function does not return an error. By
 * using this mechanism, an application can check whether
 * the specific device exists or not. The open mode
 * should be handled by an each device driver if it is
 * needed.
 */
int
device_open(const char *name, int mode, struct device **devp)
{
    struct devops *ops;
    struct device *dev;
    int error;

    sched_lock();
    if ((dev = device_lookup(name)) == NULL) {
        sched_unlock();
        return ENXIO;
    }
    error = device_reference(dev);
    if (error) {
        sched_unlock();
        return error;
    }
    sched_unlock();

    ops = dev->driver->devops;
    assert(ops->open != NULL);
    error = (*ops->open)(dev, mode);
    *devp = dev;

    device_release(dev);
    return error;
}
Exemple #3
0
int
midiopen(dev_t dev, int flags, int mode, struct proc *p)
{
	struct midi_softc *sc;
	int error;

	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
	if (sc == NULL)
		return ENXIO;
	error = 0;
	if (sc->flags) {
		error = EBUSY;
		goto done;
	}
	MIDIBUF_INIT(&sc->inbuf);
	MIDIBUF_INIT(&sc->outbuf);
	sc->isbusy = 0;
	sc->rchan = sc->wchan = 0;
	sc->async = 0;
	sc->flags = flags;
	error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc);
	if (error)
		sc->flags = 0;
done:
	device_unref(&sc->dev);
	return error;
}
Exemple #4
0
int
midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
	struct midi_softc *sc;
	int error;

	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
	if (sc == NULL)
		return ENXIO;
	error = 0;
	switch(cmd) {
	case FIONBIO:
		/* All handled in the upper FS layer */
		break;
	case FIOASYNC:
		if (*(int *)addr) {
			if (sc->async) {
				error = EBUSY;
				goto done;
			}
			sc->async = p;
		} else
			sc->async = 0;
		break;
	default:
		error = ENOTTY;
	}
done:
	device_unref(&sc->dev);
	return error;
}
Exemple #5
0
int
prestoopen(dev_t dev, int flag, int fmt, struct proc *proc)
{
	int unit, part;
	struct presto_softc *sc;

	unit = DISKUNIT(dev);
	sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
	if (sc == NULL)
		return (ENXIO);

	/* only allow valid partitions */
	part = DISKPART(dev);
	if (part != RAW_PART &&
	    (part >= sc->sc_dk.dk_label->d_npartitions ||
	    sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED))
		return (ENXIO);

	/* update open masks */
	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;

	return (0);
}
Exemple #6
0
int
midipoll(dev_t dev, int events, struct proc *p)
{
	struct midi_softc *sc;
	int revents;

	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
	if (sc == NULL)
		return POLLERR;
	revents = 0;
	mtx_enter(&audio_lock);
	if (events & (POLLIN | POLLRDNORM)) {
		if (!MIDIBUF_ISEMPTY(&sc->inbuf))
			revents |= events & (POLLIN | POLLRDNORM);
	}
	if (events & (POLLOUT | POLLWRNORM)) {
		if (!MIDIBUF_ISFULL(&sc->outbuf))
			revents |= events & (POLLOUT | POLLWRNORM);
	}
	if (revents == 0) {
		if (events & (POLLIN | POLLRDNORM))
			selrecord(p, &sc->rsel);
		if (events & (POLLOUT | POLLWRNORM))
			selrecord(p, &sc->wsel);
	}
	mtx_leave(&audio_lock);
	device_unref(&sc->dev);
	return (revents);
}
struct extent *
pciaddr_search(int mem_port, bus_addr_t *startp, bus_size_t size)
{
	extern struct cfdriver pcibios_cd;
	struct pcibios_softc *sc;

	sc = (struct pcibios_softc *)device_lookup(&pcibios_cd, 0);
	if (sc && !(pcibios_flags & PCIBIOS_ADDR_FIXUP)) {
		struct extent_region *rp;
		struct extent *ex = mem_port? sc->extent_mem : sc->extent_port;

		/* Search the PCI I/O memory space extent for free
		 * space that will accommodate size.  Remember that the
		 * extent stores allocated space and we're searching
		 * for the gaps.
		 *
		 * If we're at the end or the gap between this region
		 * and the next region big enough, then we're done
		 */
		for (rp = LIST_FIRST(&ex->ex_regions);
		    rp && *startp + size > rp->er_start;
		    rp = LIST_NEXT(rp, er_link)) {
			bus_addr_t new_start;

			new_start = (rp->er_end - 1 + size) & ~(size - 1);
			if (new_start > *startp)
				*startp = new_start;
		}

		return (ex);
	}

	return (NULL);
}
Exemple #8
0
/*ARGSUSED*/
int
pcfrtc_write(dev_t dev, struct uio *uio, int flags)
{
	struct pcfrtc_softc *sc;
	u_int8_t cmdbuf[2];
	int a, error;

	if ((sc = device_lookup(&pcfrtc_cd, minor(dev))) == NULL)
		return (ENXIO);

	if (uio->uio_offset >= PCF8583_NVRAM_SIZE)
		return (EINVAL);

	if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
		return (error);

	while (uio->uio_resid && uio->uio_offset < PCF8583_NVRAM_SIZE) {
		a = (int)uio->uio_offset;
		cmdbuf[0] = a + PCF8583_NVRAM_START;
		if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0)
			break;

		if ((error = iic_exec(sc->sc_tag,
		    uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP,
		    sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) {
			printf("%s: pcfrtc_write: write failed at 0x%x\n",
			    sc->sc_dev.dv_xname, a);
			return (error);
		}
	}

	iic_release_bus(sc->sc_tag, 0);

	return (error);
}
Exemple #9
0
/*ARGSUSED*/
int
seeprom_read(dev_t dev, struct uio *uio, int flags)
{
	struct seeprom_softc *sc;
	i2c_addr_t addr;
	u_int8_t ch, cmdbuf[2];
	int a, error;

	if ((sc = device_lookup(&seeprom_cd, minor(dev))) == NULL)
		return (ENXIO);

	if (uio->uio_offset >= sc->sc_size)
		return (EINVAL);

	if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
		return (error);

	/*
	 * Even though the AT24Cxx EEPROMs support sequential
	 * reads within a page, some I2C controllers do not
	 * support anything other than single-byte transfers,
	 * so we're stuck with this lowest-common-denominator.
	 */

	while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) {
		a = (int)uio->uio_offset;
		if (sc->sc_cmdlen == 1) {
			addr = sc->sc_address + (a >> 8);
			cmdbuf[0] = a & 0xff;
		} else {
Exemple #10
0
static void demo_thread_entry(void)
{
    device_t *testser;
    char test[260];
    unsigned i = 0;
    unsigned j = 10;
    //int retcode = 1;

    printf("START TX\n");

    testser = device_lookup("uart",0);

    if (!testser) {
        printf("ERROR 1 !!!\n");
    }

    memset(test, 0, sizeof(test));

    while (1) {
        snprintf(test, sizeof(test),teststring,i++);
        j++;
        if (j > strlen(test)) {
            j = 0;
            memset(test, 0, sizeof(test));
        }
        printf("%s\n",test);
        //retcode = device_io(testser, FALSE, test, j);
        //if (retcode < 0) {
        //    printf("ERROR %d !!!\n", retcode);
        //}
        //thread_suspend();
        thread_delay(500);
    }
}
Exemple #11
0
int
ldsize(dev_t dev)
{
	struct ld_softc *sc;
	int part, unit, omask, size;

	unit = DISKUNIT(dev);
	if ((sc = device_lookup(&ld_cd, unit)) == NULL)
		return (ENODEV);
	if ((sc->sc_flags & LDF_ENABLED) == 0)
		return (ENODEV);
	part = DISKPART(dev);

	omask = sc->sc_dk.dk_openmask & (1 << part);

	if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0)
		return (-1);
	else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
		size = -1;
	else
		size = sc->sc_dk.dk_label->d_partitions[part].p_size *
		    (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
	if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0)
		return (-1);

	return (size);
}
Exemple #12
0
/*
 * lptread --retrieve printer status in IEEE1284 NIBBLE mode
 */
int
lptread(dev_t dev_id, struct uio *uio, int ioflag)
{
	size_t len = 0;
	int error = 0;
	device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
	struct lpt_softc *sc = device_private(dev);

	if(!(sc->sc_state & HAVEBUS)) {
		LPT_DPRINTF(("%s(%s): attempt to read using device which does "
			"not own the bus(%s).\n", __func__, device_xname(dev),
			device_xname(device_parent(dev))));
		return (ENODEV);
	}

	sc->sc_state &= ~INTERRUPTED;
	while (uio->uio_resid) {
		error = ppbus_read(device_parent(dev), sc->sc_outbuf,
			min(BUFSIZE, uio->uio_resid), 0, &len);

		/* If error or no more data, stop */
		if (error) {
			if (error != EWOULDBLOCK)
				sc->sc_state |= INTERRUPTED;
			break;
		}
		if (len == 0)
			break;

		if ((error = uiomove(sc->sc_outbuf, len, uio)))
			break;
	}

	return error;
}
Exemple #13
0
/* ARGSUSED */
int
ldclose(dev_t dev, int flags, int fmt, struct proc *p)
{
	struct ld_softc *sc;
	int part, unit;

	unit = DISKUNIT(dev);
	part = DISKPART(dev);
	sc = device_lookup(&ld_cd, unit);
	ldlock(sc);

	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 && sc->sc_flush != NULL)
		if ((*sc->sc_flush)(sc) != 0)
			printf("%s: unable to flush cache\n",
			    sc->sc_dv.dv_xname);

	ldunlock(sc);
	return (0);
}
Exemple #14
0
int
midikqfilter(dev_t dev, struct knote *kn)
{
	struct midi_softc *sc;
	struct klist 	  *klist;
	int error;

	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
	if (sc == NULL)
		return ENXIO;
	error = 0;
	switch (kn->kn_filter) {
	case EVFILT_READ:
		klist = &sc->rsel.si_note;
		kn->kn_fop = &midiread_filtops;
		break;
	case EVFILT_WRITE:
		klist = &sc->wsel.si_note;
		kn->kn_fop = &midiwrite_filtops;
		break;
	default:
		error = EINVAL;
		goto done;
	}
	kn->kn_hook = (void *)sc;

	mtx_enter(&audio_lock);
	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
	mtx_leave(&audio_lock);
done:
	device_unref(&sc->dev);
	return error;
}
Exemple #15
0
int
cgeightopen(dev_t dev, int flags, int mode, struct lwp *l)
{
	int unit = minor(dev);

	if (device_lookup(&cgeight_cd, unit) == NULL)
		return (ENXIO);
	return (0);
}
int
midi_unit_count(void)
{
	int i;
	for ( i = 0; i < midi_cd.cd_ndevs; ++i)
	        if (NULL == device_lookup(&midi_cd, i))
		        break;
        return i;
}
Exemple #17
0
int
midiread(dev_t dev, struct uio *uio, int ioflag)
{
	struct midi_softc *sc;
	struct midi_buffer *mb;
	size_t count;
	int error;

	sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev));
	if (sc == NULL)
		return ENXIO;
	if (!(sc->flags & FREAD)) {
		error = ENXIO;
		goto done;
	}
	mb = &sc->inbuf;

	/* if there is no data then sleep (unless IO_NDELAY flag is set) */
	error = 0;
	mtx_enter(&audio_lock);
	while (MIDIBUF_ISEMPTY(mb)) {
		if (ioflag & IO_NDELAY) {
			mtx_leave(&audio_lock);
			error = EWOULDBLOCK;
			goto done;
		}
		sc->rchan = 1;
		error = msleep(&sc->rchan, &audio_lock, PWAIT | PCATCH, "mid_rd", 0);
		if (!(sc->dev.dv_flags & DVF_ACTIVE))
			error = EIO;
		if (error) {
			mtx_leave(&audio_lock);
			goto done;
		}
	}

	/* at this stage, there is at least 1 byte */

	while (uio->uio_resid > 0 && mb->used > 0) {
		count = MIDIBUF_SIZE - mb->start;
		if (count > mb->used)
			count = mb->used;
		if (count > uio->uio_resid)
			count = uio->uio_resid;
		mtx_leave(&audio_lock);
		error = uiomove(mb->data + mb->start, count, uio);
		if (error)
			goto done;
		mtx_enter(&audio_lock);
		MIDIBUF_REMOVE(mb, count);
	}
	mtx_leave(&audio_lock);
done:
	device_unref(&sc->dev);
	return error;
}
Exemple #18
0
/*
 * Take a dump.
 */
int
lddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
{
	struct ld_softc *sc;
	struct disklabel *lp;
	int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv;
	static int dumping;

	unit = DISKUNIT(dev);
	if ((sc = device_lookup(&ld_cd, unit)) == NULL)
		return (ENXIO);
	if ((sc->sc_flags & LDF_ENABLED) == 0)
		return (ENODEV);
	if (sc->sc_dump == NULL)
		return (ENXIO);

	/* Check if recursive dump; if so, punt. */
	if (dumping)
		return (EFAULT);
	dumping = 1;

	/* Convert to disk sectors.  Request must be a multiple of size. */
	part = DISKPART(dev);
	lp = sc->sc_dk.dk_label;
	if ((size % lp->d_secsize) != 0)
		return (EFAULT);
	towrt = size / lp->d_secsize;
	blkno = dbtob(blkno) / lp->d_secsize;	/* blkno in DEV_BSIZE units */

	nsects = lp->d_partitions[part].p_size;
	sectoff = lp->d_partitions[part].p_offset;

	/* Check transfer bounds against partition size. */
	if ((blkno < 0) || ((blkno + towrt) > nsects))
		return (EINVAL);

	/* Offset block number to start of partition. */
	blkno += sectoff;

	/* Start dumping and return when done. */
	maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1;
	while (towrt > 0) {
		nblk = min(maxblkcnt, towrt);

		if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0)
			return (rv);

		towrt -= nblk;
		blkno += nblk;
		va += nblk * sc->sc_secsize;
	}

	dumping = 0;
	return (0);
}
static int
pciopen(dev_t dev, int flags, int mode, struct lwp *l)
{
	device_t dv;

	dv = device_lookup(&pci_cd, minor(dev));
	if (dv == NULL)
		return ENXIO;

	return 0;
}
Exemple #20
0
/*
 * Adjust the size of a transfer.
 */
static void
ldminphys(struct buf *bp)
{
	struct ld_softc *sc;

	sc = device_lookup(&ld_cd, DISKUNIT(bp->b_dev));

	if (bp->b_bcount > sc->sc_maxxfer)
		bp->b_bcount = sc->sc_maxxfer;
	minphys(bp);
}
Exemple #21
0
/*ARGSUSED*/
int
pcfrtc_close(dev_t dev, int flag, int fmt, struct proc *p)
{
	struct pcfrtc_softc *sc;

	if ((sc = device_lookup(&pcfrtc_cd, minor(dev))) == NULL)
		return (ENXIO);

	sc->sc_open = 0;
	return (0);
}
Exemple #22
0
/* ARGSUSED */
static void
ldshutdown(void *cookie)
{
	struct ld_softc *sc;
	int i;

	for (i = 0; i < ld_cd.cd_ndevs; i++) {
		if ((sc = device_lookup(&ld_cd, i)) == NULL)
			continue;
		if (sc->sc_flush != NULL && (*sc->sc_flush)(sc) != 0)
			printf("%s: unable to flush cache\n",
			    sc->sc_dv.dv_xname);
	}
}
Exemple #23
0
/*ARGSUSED*/
int
pcfrtc_open(dev_t dev, int flag, int fmt, struct proc *p)
{
	struct pcfrtc_softc *sc;

	if ((sc = device_lookup(&pcfrtc_cd, minor(dev))) == NULL)
		return (ENXIO);

	/* XXX: Locking */

	if (sc->sc_open)
		return (EBUSY);

	sc->sc_open = 1;
	return (0);
}
Exemple #24
0
void
prestostrategy(struct buf *bp)
{
	int unit, part;
	struct presto_softc *sc;
	size_t offset, count;
	int s;

	unit = DISKUNIT(bp->b_dev);
	sc = (struct presto_softc *)device_lookup(&presto_cd, unit);

	/* Sort rogue requests out */
	if (sc == NULL || bp->b_blkno < 0 ||
	    (bp->b_bcount % sc->sc_dk.dk_label->d_secsize) != 0) {
		bp->b_error = EINVAL;
		goto bad;
	}

	/* Do not write on "no trespassing" areas... */
	part = DISKPART(bp->b_dev);
	if (part != RAW_PART &&
	    bounds_check_with_label(bp, sc->sc_dk.dk_label,
	    sc->sc_dk.dk_cpulabel, 1) <= 0)
		goto bad;

	/* Bound the request size, then move data between buf and nvram */
	bp->b_resid = bp->b_bcount;
	offset = (bp->b_blkno << DEV_BSHIFT) + PSERVE_OFFSET;
	count = bp->b_bcount;
	if (count > (sc->sc_memsize - offset))
		count = (sc->sc_memsize - offset);
	if (ISSET(bp->b_flags, B_READ))
		bcopy(sc->sc_mem + offset, bp->b_data, count);
	else
		bcopy(bp->b_data, sc->sc_mem + offset, count);
	bp->b_resid -= count;
	goto done;

bad:
	bp->b_flags |= B_ERROR;
	bp->b_resid = bp->b_bcount;

done:
	s = splbio();
	biodone(bp);
	splx(s);
}
Exemple #25
0
void
ldstrategy(struct buf *bp)
{
	struct ld_softc *sc;
	int s;

	sc = device_lookup(&ld_cd, DISKUNIT(bp->b_dev));

	s = splbio();
	if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) {
		BUFQ_INSERT_TAIL(&sc->sc_bufq, bp);
		splx(s);
		return;
	}
	splx(s);
	ldstart(sc, bp);
}
Exemple #26
0
/*
 * lptclose -- close the device, free the local line buffer.
 *
 * Check for interrupted write call added.
 */
int
lptclose(dev_t dev_id, int flags, int fmt, struct lwp *l)
{
	device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
	struct lpt_softc *sc = device_private(dev);
	int err;

	err = lpt_release_ppbus(sc, PPBUS_WAIT|PPBUS_INTR);
	if(err) {
		LPT_DPRINTF(("%s(%s): error (%d) while releasing ppbus.\n",
			__func__, device_xname(dev), err));
	}

	sc->sc_state = 0;

	return err;
}
Exemple #27
0
int
prestosize(dev_t dev)
{
	struct presto_softc *sc;
	int unit, part;

	unit = DISKUNIT(dev);
	sc = (struct presto_softc *)device_lookup(&presto_cd, unit);
	if (sc == NULL)
		return (0);

	part = DISKPART(dev);
	if (part >= sc->sc_dk.dk_label->d_npartitions)
		return (0);
	else
		return (sc->sc_dk.dk_label->d_partitions[part].p_size *
		    (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE));
}
Exemple #28
0
unsigned dodismount(int argc,char *argv[],int qualc,char *qualv[])
{
    struct DEV *dev;
    // note that device lookup interface has changed, fix later
    register int sts = device_lookup(strlen(argv[1]),argv[1],0,&dev);
    if (sts & 1)
    {
        if (dev->vcb != NULL)
        {
            sts = dismount(dev->vcb);
        }
        else
        {
            sts = SS$_DEVNOTMOUNT;
        }
    }
    if ((sts & 1) == 0) printf("%%DISMOUNT-E-STATUS Error: %d\n",sts);
    return sts;
}
Exemple #29
0
int
prestoioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *proc)
{
	struct presto_softc *sc;
	int unit;
	int error;

	unit = DISKUNIT(dev);
	sc = (struct presto_softc *)device_lookup(&presto_cd, unit);

	switch (cmd) {
	case DIOCGDINFO:
		bcopy(sc->sc_dk.dk_label, data, sizeof(struct disklabel));
		return (0);

	case DIOCSDINFO:
		if ((flag & FWRITE) == 0)
			return (EBADF);

		error = setdisklabel(sc->sc_dk.dk_label,
		    (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0,
		    sc->sc_dk.dk_cpulabel);
		return (error);

	case DIOCWDINFO:
		if ((flag & FWRITE) == 0)
			return (EBADF);

		error = setdisklabel(sc->sc_dk.dk_label,
		    (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0,
		    sc->sc_dk.dk_cpulabel);
		if (error == 0) {
			error = writedisklabel(DISKLABELDEV(dev),
			    prestostrategy, sc->sc_dk.dk_label,
			    sc->sc_dk.dk_cpulabel);
		}

		return (error);
	default:
		return (EINVAL);
	}
}
Exemple #30
0
/*
 * lptwrite --copy a line from user space to a local buffer, then call
 * putc to get the chars moved to the output queue.
 *
 * Flagging of interrupted write added.
 */
int
lptwrite(dev_t dev_id, struct uio * uio, int ioflag)
{
	int error=0;
	size_t n, cnt;
	device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id));
	struct lpt_softc * sc = device_private(dev);

	/* Check state and flags */
	if(!(sc->sc_state & HAVEBUS)) {
		LPT_DPRINTF(("%s(%s): attempt to write using device which does "
			"not own the bus(%s).\n", __func__, device_xname(dev),
			device_xname(device_parent(dev))));
		return EINVAL;
	}

	LPT_VPRINTF(("%s(%s): writing %zu bytes\n", __func__,
	    device_xname(dev), uio->uio_resid));

	/* Write the data */
	sc->sc_state &= ~INTERRUPTED;
	while (uio->uio_resid) {
		n = MIN(BUFSIZE, uio->uio_resid);
		error = uiomove(sc->sc_inbuf, n, uio);
		if (error)
			break;

		error = ppbus_write(device_parent(dev), sc->sc_inbuf, n, ioflag,
			&cnt);
		if (error) {
			if (error != EWOULDBLOCK)
				sc->sc_state |= INTERRUPTED;
			break;
		}
	}

	LPT_VPRINTF(("%s(%s): transfer finished, error %d.\n", __func__,
	    device_xname(dev), error));

	return error;
}