Пример #1
0
static int
ch_position(struct ch_softc *sc, struct changer_position_request *cp)
{
	struct scsi_position_to_element cmd;
	u_int16_t dst;

	/*
	 * Check arguments.
	 */
	if (cp->cp_type > CHET_DT)
		return (EINVAL);
	if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
		return (ENODEV);

	/*
	 * Calculate the destination element.
	 */
	dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;

	/*
	 * Build the SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = POSITION_TO_ELEMENT;
	_lto2b(sc->sc_picker, cmd.tea);
	_lto2b(dst, cmd.dst);
	if (cp->cp_flags & CP_INVERT)
		cmd.flags |= POSITION_TO_ELEMENT_INVERT;

	/*
	 * Send command to changer.
	 */
	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
	    CHRETRIES, CHTIMEOUT, NULL, 0));
}
/* stop a scan operation in progress */
static int
mustek_rewind_scanner(struct ss_softc *ss)
{
	struct mustek_start_scan_cmd cmd;
	struct scsipi_periph *periph = ss->sc_periph;
	int error;

	if (ss->sio.scan_window_size != 0) {
		/*
		 * only if not all data has been read, the scanner has to be
		 * stopped
		 */
		memset(&cmd, 0, sizeof(cmd));
		cmd.opcode = MUSTEK_START_STOP;
		cmd.mode = MUSTEK_SCAN_STOP;

		/* send the command to the scanner */
		SC_DEBUG(periph, SCSIPI_DB1,
		    ("mustek_rewind_scanner: stop_scan\n"));
		error = scsipi_command(periph,
		    (void *)&cmd, sizeof(cmd),
		    NULL, 0,
		    MUSTEK_RETRIES, 5000, NULL, 0);
		if (error)
			return error;
	}

	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_rewind_scanner: end\n"));

	return 0;
}
Пример #3
0
/*
 * Ask the drive what it's min and max blk sizes are.
 */
static int
st_scsibus_read_block_limits(struct st_softc *st, int flags)
{
	struct scsi_block_limits cmd;
	struct scsi_block_limits_data block_limits;
	struct scsipi_periph *periph = st->sc_periph;
	int error;

	/*
	 * do a 'Read Block Limits'
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ_BLOCK_LIMITS;

	/*
	 * do the command, update the global values
	 */
	error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
	    (void *)&block_limits, sizeof(block_limits),
	    ST_RETRIES, ST_CTL_TIME, NULL,
	    flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK);
	if (error)
		return (error);

	st->blkmin = _2btol(block_limits.min_length);
	st->blkmax = _3btol(block_limits.max_length);

	SC_DEBUG(periph, SCSIPI_DB3,
	    ("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax));
	return (0);
}
Пример #4
0
static int
ch_ielem(struct ch_softc *sc)
{
	int tmo;
	struct scsi_initialize_element_status cmd;

	/*
	 * Build SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = INITIALIZE_ELEMENT_STATUS;

	/*
	 * Send command to changer.
	 *
	 * The problem is, how long to allow for the command?
	 * It can take a *really* long time, and also depends
	 * on unknowable factors such as whether there are
	 * *almost* readable labels on tapes that a barcode
	 * reader is trying to decipher.
	 *
	 * I'm going to make this long enough to allow 5 minutes
	 * per element plus an initial 10 minute wait.
	 */
	tmo =	sc->sc_counts[CHET_MT] +
		sc->sc_counts[CHET_ST] +
		sc->sc_counts[CHET_IE] +
		sc->sc_counts[CHET_DT];
	tmo *= 5 * 60 * 1000;
	tmo += (10 * 60 * 1000);

	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
	    CHRETRIES, tmo, NULL, XS_CTL_IGNORE_ILLEGAL_REQUEST));
}
Пример #5
0
static int
ch_getelemstatus(struct ch_softc *sc, int first, int count, void *data,
    size_t datalen, int scsiflags, int flags)
{
	struct scsi_read_element_status cmd;

	/*
	 * Build SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ_ELEMENT_STATUS;
	cmd.byte2 = ELEMENT_TYPE_ALL;
	if (flags & CESR_VOLTAGS)
		cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG;
	_lto2b(first, cmd.sea);
	_lto2b(count, cmd.count);
	_lto3b(datalen, cmd.len);

	/*
	 * Send command to changer.
	 */
	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd),
	    (void *)data, datalen,
	    CHRETRIES, CHTIMEOUT, NULL, scsiflags | XS_CTL_DATA_IN));
}
/*
 * check if the scanner is ready to take commands
 *   wait timeout seconds and try only every second
 *   if update, then update picture size info
 *
 *   returns EBUSY if scanner not ready
 */
static int
mustek_get_status(struct ss_softc *ss, int timeout, int update)
{
	struct mustek_get_status_cmd cmd;
	struct mustek_get_status_data data;
	struct scsipi_periph *periph = ss->sc_periph;
	int error, lines, bytes_per_line;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = MUSTEK_GET_STATUS;
	cmd.length = sizeof(data);

	while (1) {
		SC_DEBUG(periph, SCSIPI_DB1, ("mustek_get_status: stat_cmd\n"));
		error = scsipi_command(periph, (void *)&cmd, sizeof(cmd),
		    (void *)&data, sizeof(data),
		    MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_IN);
		if (error)
			return error;
		if ((data.ready_busy == MUSTEK_READY) ||
		    (timeout-- <= 0))
			break;
		/* please wait a second */
		tsleep((void *)mustek_get_status, PRIBIO + 1, "mtkrdy", hz);
	}

	if (update) {
		bytes_per_line = _2ltol(data.bytes_per_line);
		lines = _3ltol(data.lines);
		if (lines != ss->sio.scan_lines) {
			printf("mustek: lines actual(%d) != computed(%ld)\n",
			    lines, ss->sio.scan_lines);
			return EIO;
		}
		if (bytes_per_line * lines != ss->sio.scan_window_size) {
			printf("mustek: win-size actual(%d) != computed(%ld)\n",
			    bytes_per_line * lines, ss->sio.scan_window_size);
		    return EIO;
		}

		SC_DEBUG(periph, SCSIPI_DB1,
		    ("mustek_get_size: bpl=%ld, lines=%ld\n",
		    (ss->sio.scan_pixels_per_line * ss->sio.scan_bits_per_pixel)
		    / 8, ss->sio.scan_lines));
		SC_DEBUG(periph, SCSIPI_DB1, ("window size = %ld\n",
		    ss->sio.scan_window_size));
	}

	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_get_status: end\n"));
	if (data.ready_busy == MUSTEK_READY)
		return 0;
	else
		return EBUSY;
}
Пример #7
0
static int
ch_exchange(struct ch_softc *sc, struct changer_exchange_request *ce)
{
	struct scsi_exchange_medium cmd;
	u_int16_t src, dst1, dst2;

	/*
	 * Check arguments.
	 */
	if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
	    (ce->ce_sdsttype > CHET_DT))
		return (EINVAL);
	if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
	    (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
	    (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
		return (ENODEV);

	/*
	 * Check the request against the changer's capabilities.
	 */
	if (((sc->sc_exchangemask[ce->ce_srctype] &
	     (1 << ce->ce_fdsttype)) == 0) ||
	    ((sc->sc_exchangemask[ce->ce_fdsttype] &
	     (1 << ce->ce_sdsttype)) == 0))
		return (ENODEV);

	/*
	 * Calculate the source and destination elements.
	 */
	src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
	dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
	dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;

	/*
	 * Build the SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = EXCHANGE_MEDIUM;
	_lto2b(sc->sc_picker, cmd.tea);
	_lto2b(src, cmd.src);
	_lto2b(dst1, cmd.fdst);
	_lto2b(dst2, cmd.sdst);
	if (ce->ce_flags & CE_INVERT1)
		cmd.flags |= EXCHANGE_MEDIUM_INV1;
	if (ce->ce_flags & CE_INVERT2)
		cmd.flags |= EXCHANGE_MEDIUM_INV2;

	/*
	 * Send command to changer.
	 */
	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
	    CHRETRIES, CHTIMEOUT, NULL, 0));
}
Пример #8
0
/*
 * Do a scsi operation, asking a device to run as SCSI-II if it can.
 */
int
scsi_change_def(struct scsipi_periph *periph, int flags)
{
	struct scsi_changedef cmd;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = SCSI_CHANGE_DEFINITION;
	cmd.how = SC_SCSI_2;

	return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
	    SCSIPIRETRIES, 100000, NULL, flags));
}
Пример #9
0
/*
 * Do a synchronous read.  Used to read responses to control messages.
 */
static int
scanjet_ctl_read(struct ss_softc *ss, char *tbuf, u_int size)
{
	struct scsi_rw_scanner cmd;
	int flags;

	flags = 0;
	if ((ss->flags & SSF_AUTOCONF) != 0)
		flags |= XS_CTL_DISCOVERY;

	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = READ;
	_lto3b(size, cmd.len);

	return (scsipi_command(ss->sc_periph,
	    (void *)&cmd, sizeof(cmd), (void *)tbuf, size, 0, 100000, NULL,
	    flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK));
}
Пример #10
0
static int
ch_move(struct ch_softc *sc, struct changer_move_request *cm)
{
	struct scsi_move_medium cmd;
	u_int16_t fromelem, toelem;

	/*
	 * Check arguments.
	 */
	if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
		return (EINVAL);
	if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
	    (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
		return (ENODEV);

	/*
	 * Check the request against the changer's capabilities.
	 */
	if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
		return (ENODEV);

	/*
	 * Calculate the source and destination elements.
	 */
	fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
	toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;

	/*
	 * Build the SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = MOVE_MEDIUM;
	_lto2b(sc->sc_picker, cmd.tea);
	_lto2b(fromelem, cmd.src);
	_lto2b(toelem, cmd.dst);
	if (cm->cm_flags & CM_INVERT)
		cmd.flags |= MOVE_MEDIUM_INVERT;

	/*
	 * Send command to changer.
	 */
	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
	    CHRETRIES, CHTIMEOUT, NULL, 0));
}
Пример #11
0
/* Pseudo strategy function
 * Called by scsipi_do_ioctl() via physio/physstrat if there is to
 * be data transfered, and directly if there is no data transfer.
 *
 * Should I reorganize this so it returns to physio instead
 * of sleeping in scsiio_scsipi_cmd?  Is there any advantage, other
 * than avoiding the probable duplicate wakeup in iodone? [PD]
 *
 * No, seems ok to me... [JRE]
 * (I don't see any duplicate wakeups)
 *
 * Can't be used with block devices or raw_read/raw_write directly
 * from the cdevsw/bdevsw tables because they couldn't have added
 * the screq structure. [JRE]
 */
static void
scsistrategy(struct buf *bp)
{
	struct scsi_ioctl *si;
	scsireq_t *screq;
	struct scsipi_periph *periph;
	int error;
	int flags = 0;

	si = si_find(bp);
	if (si == NULL) {
		printf("scsistrategy: "
		    "No matching ioctl request found in queue\n");
		error = EINVAL;
		goto done;
	}
	screq = &si->si_screq;
	periph = si->si_periph;
	SC_DEBUG(periph, SCSIPI_DB2, ("user_strategy\n"));

	/*
	 * We're in trouble if physio tried to break up the transfer.
	 */
	if (bp->b_bcount != screq->datalen) {
		scsipi_printaddr(periph);
		printf("physio split the request.. cannot proceed\n");
		error = EIO;
		goto done;
	}

	if (screq->timeout == 0) {
		error = EINVAL;
		goto done;
	}

	if (screq->cmdlen > sizeof(struct scsipi_generic)) {
		scsipi_printaddr(periph);
		printf("cmdlen too big\n");
		error = EFAULT;
		goto done;
	}

	if ((screq->flags & SCCMD_READ) && screq->datalen > 0)
		flags |= XS_CTL_DATA_IN;
	if ((screq->flags & SCCMD_WRITE) && screq->datalen > 0)
		flags |= XS_CTL_DATA_OUT;
	if (screq->flags & SCCMD_TARGET)
		flags |= XS_CTL_TARGET;
	if (screq->flags & SCCMD_ESCAPE)
		flags |= XS_CTL_ESCAPE;

	error = scsipi_command(periph, (void *)screq->cmd, screq->cmdlen,
	    (void *)bp->b_data, screq->datalen,
	    0, /* user must do the retries *//* ignored */
	    screq->timeout, bp, flags | XS_CTL_USERCMD);

done:
	if (error)
		bp->b_resid = bp->b_bcount;
	bp->b_error = error;
	biodone(bp);
	return;
}
Пример #12
0
/*
 * trigger the scanner to start a scan operation
 * this includes sending the mode- and window-data, starting the scanner
 * and getting the image size info
 */
static int
mustek_trigger_scanner(struct ss_softc *ss)
{
	struct mustek_mode_select_cmd mode_cmd;
	struct mustek_mode_select_data mode_data;
	struct mustek_set_window_cmd window_cmd;
	struct mustek_set_window_data window_data;
	struct mustek_start_scan_cmd start_scan_cmd;
	struct scsipi_periph *periph = ss->sc_periph;
	int pixel_tlx, pixel_tly, pixel_brx, pixel_bry, paperlength;
	int error;

	mustek_compute_sizes(ss);

	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner\n"));

	/* set the window params and send the scsi command */
	memset(&window_cmd, 0, sizeof(window_cmd));
	window_cmd.opcode = MUSTEK_SET_WINDOW;
	window_cmd.length = sizeof(window_data);

	memset(&window_data, 0, sizeof(window_data));
	window_data.frame.header = MUSTEK_LINEART_BACKGROUND | MUSTEK_UNIT_SPEC;
#ifdef MUSTEK_INCH_SPEC
	/* the positional values are all 1 byte because 256 / 8 = 32" */
	pixel_tlx = ss->sio.scan_x_origin / 150;
	pixel_tly = ss->sio.scan_y_origin / 150;
	pixel_brx = pixel_tlx + ss->sio.scan_width / 150;
	pixel_bry = pixel_tly + ss->sio.scan_height / 150;
#else
	pixel_tlx = (ss->sio.scan_x_origin * ss->sio.scan_x_resolution) / 1200;
	pixel_tly = (ss->sio.scan_y_origin * ss->sio.scan_y_resolution) / 1200;
	pixel_brx = pixel_tlx +
	    (ss->sio.scan_width * ss->sio.scan_x_resolution) / 1200;
	pixel_bry = pixel_tly +
	    (ss->sio.scan_height * ss->sio.scan_y_resolution) / 1200;
#endif
	_lto2l(pixel_tlx, window_data.frame.tl_x);
	_lto2l(pixel_tly, window_data.frame.tl_y);
	_lto2l(pixel_brx, window_data.frame.br_x);
	_lto2l(pixel_bry, window_data.frame.br_y);

#if MUSTEK_WINDOWS >= 1
	window_data.window1 = window_data.frame;
	window_data.window1.header = MUSTEK_WINDOW_MASK | MUSTEK_UNIT_SPEC;
#endif

	/* send the set window command to the scanner */
	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_set_parms: set_window\n"));
	error = scsipi_command(periph, (void *)&window_cmd, sizeof(window_cmd),
	    (void *)&window_data, sizeof(window_data),
	    MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT);
	if (error)
		return error;

	/*
	 * do what it takes to actualize the mode
	 */
	memset(&mode_cmd, 0, sizeof(mode_cmd));
	mode_cmd.opcode = MUSTEK_MODE_SELECT;
	_lto2b(sizeof(mode_data), mode_cmd.length);

	memset(&mode_data, 0, sizeof(mode_data));
	mode_data.mode =
	    MUSTEK_MODE_MASK | MUSTEK_HT_PATTERN_BUILTIN | MUSTEK_UNIT_SPEC;
	if (ss->sio.scan_x_resolution <= 300)
		mode_data.resolution = ss->sio.scan_x_resolution / 3;
	else
		/*
		 * the resolution values is computed by modulo 100, but not
		 * for 600dpi, where the value is 100 (a bit tricky, but ...)
		 */
		mode_data.resolution =
		    ((ss->sio.scan_x_resolution - 1) % 100) + 1;

	mode_data.brightness = (ss->sio.scan_brightness - 64) / 3;
	mode_data.contrast = (ss->sio.scan_contrast - 16) / 7;
	mode_data.grain = 0;
	mode_data.velocity = ss->sio.scan_quality / 20 - 1;
#ifdef MUSTEK_INCH_SPEC
	paperlength = 14 * 8;	/* 14" */
#else
	paperlength = 14 * ss->sio.scan_y_resolution;	/* 14" */
#endif
	_lto2l(paperlength, mode_data.paperlength);

	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: mode_select\n"));
	/* send the command to the scanner */
	error = scsipi_command(periph, (void *)&mode_cmd, sizeof(mode_cmd),
	    (void *)&mode_data, sizeof(mode_data),
	    MUSTEK_RETRIES, 5000, NULL, XS_CTL_DATA_OUT);
	if (error)
		return error;

	/*
	 * now construct and send the start command
	 */
	memset(&start_scan_cmd, 0, sizeof(start_scan_cmd));
	start_scan_cmd.opcode = MUSTEK_START_STOP;
	start_scan_cmd.mode = MUSTEK_SCAN_START;
	if (ss->sio.scan_x_resolution <= 300)
		start_scan_cmd.mode |= MUSTEK_RES_STEP_1;
	else
		start_scan_cmd.mode |= MUSTEK_RES_STEP_10;
	switch (ss->sio.scan_image_mode) {
	case SIM_BINARY_MONOCHROME:
	case SIM_DITHERED_MONOCHROME:
		start_scan_cmd.mode |= MUSTEK_BIT_MODE | MUSTEK_GRAY_FILTER;
		break;
	case SIM_GRAYSCALE:
		start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GRAY_FILTER;
		break;
	case SIM_RED:
		start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_RED_FILTER;
		break;
	case SIM_GREEN:
		start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_GREEN_FILTER;
		break;
	case SIM_BLUE:
		start_scan_cmd.mode |= MUSTEK_GRAY_MODE | MUSTEK_BLUE_FILTER;
		break;
	}

	/* send the command to the scanner */
	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: start_scan\n"));
	error = scsipi_command(periph,
	    (void *)&start_scan_cmd, sizeof(start_scan_cmd), NULL, 0,
	    MUSTEK_RETRIES, 5000, NULL, 0);
	if (error)
		return error;

	/*
	 * now check if scanner ready this time with update of size info
	 * we wait here so that if the user issues a read directly afterwards,
	 * the scanner will respond directly (otherwise we had to sleep with
	 * a buffer locked in memory)
	 */
	SC_DEBUG(periph, SCSIPI_DB1, ("mustek_trigger_scanner: get_status\n"));
	error = mustek_get_status(ss, 60, 1);
	if (error)
		return error;

	return 0;
}
Пример #13
0
static int
ch_setvoltag(struct ch_softc *sc, struct changer_set_voltag_request *csvr)
{
	struct scsi_send_volume_tag cmd;
	struct changer_volume_tag voltag;
	void *data = NULL;
	size_t datalen = 0;
	int error;
	u_int16_t dst;

	/*
	 * Check arguments.
	 */
	if (csvr->csvr_type > CHET_DT)
		return (EINVAL);
	if (csvr->csvr_unit > (sc->sc_counts[csvr->csvr_type] - 1))
		return (ENODEV);

	dst = sc->sc_firsts[csvr->csvr_type] + csvr->csvr_unit;

	/*
	 * Build the SCSI command.
	 */
	memset(&cmd, 0, sizeof(cmd));
	cmd.opcode = SEND_VOLUME_TAG;
	_lto2b(dst, cmd.eaddr);

#define	ALTERNATE	(csvr->csvr_flags & CSVR_ALTERNATE)

	switch (csvr->csvr_flags & CSVR_MODE_MASK) {
	case CSVR_MODE_SET:
		cmd.sac = ALTERNATE ? SAC_ASSERT_ALT : SAC_ASSERT_PRIMARY;
		break;

	case CSVR_MODE_REPLACE:
		cmd.sac = ALTERNATE ? SAC_REPLACE_ALT : SAC_REPLACE_PRIMARY;
		break;

	case CSVR_MODE_CLEAR:
		cmd.sac = ALTERNATE ? SAC_UNDEFINED_ALT : SAC_UNDEFINED_PRIMARY;
		break;

	default:
		return (EINVAL);
	}

#undef ALTERNATE

	if (cmd.sac < SAC_UNDEFINED_PRIMARY) {
		error = ch_voltag_convert_out(&csvr->csvr_voltag, &voltag);
		if (error)
			return (error);
		data = &voltag;
		datalen = sizeof(voltag);
		_lto2b(datalen, cmd.length);
	}

	/*
	 * Send command to changer.
	 */
	return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd),
	    (void *)data, datalen, CHRETRIES, CHTIMEOUT, NULL,
	    datalen ? XS_CTL_DATA_OUT : 0));
}