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; }
/* * 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); }
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)); }
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; }
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)); }
/* * 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)); }
/* * 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)); }
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)); }
/* 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; }
/* * 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; }
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)); }