Index: head/sys/cam/scsi/scsi_da.c =================================================================== --- head/sys/cam/scsi/scsi_da.c (revision 155062) +++ head/sys/cam/scsi/scsi_da.c (revision 155063) @@ -1,1981 +1,1989 @@ /*- * Implementation of SCSI Direct Access Peripheral driver for CAM. * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #ifdef _KERNEL #include #include #include #include #include #endif /* _KERNEL */ #include #include #include #include #include #include #include #include #include #ifndef _KERNEL #include #include #endif /* _KERNEL */ #include #include #include #include #include #ifndef _KERNEL #include #endif /* !_KERNEL */ #ifdef _KERNEL typedef enum { DA_STATE_PROBE, DA_STATE_PROBE2, DA_STATE_NORMAL } da_state; typedef enum { DA_FLAG_PACK_INVALID = 0x001, DA_FLAG_NEW_PACK = 0x002, DA_FLAG_PACK_LOCKED = 0x004, DA_FLAG_PACK_REMOVABLE = 0x008, DA_FLAG_TAGGED_QUEUING = 0x010, DA_FLAG_NEED_OTAG = 0x020, DA_FLAG_WENT_IDLE = 0x040, DA_FLAG_RETRY_UA = 0x080, DA_FLAG_OPEN = 0x100, DA_FLAG_SCTX_INIT = 0x200 } da_flags; typedef enum { DA_Q_NONE = 0x00, DA_Q_NO_SYNC_CACHE = 0x01, DA_Q_NO_6_BYTE = 0x02, DA_Q_NO_PREVENT = 0x04 } da_quirks; typedef enum { DA_CCB_PROBE = 0x01, DA_CCB_PROBE2 = 0x02, DA_CCB_BUFFER_IO = 0x03, DA_CCB_WAITING = 0x04, DA_CCB_DUMP = 0x05, DA_CCB_TYPE_MASK = 0x0F, DA_CCB_RETRY_UA = 0x10 } da_ccb_state; /* Offsets into our private area for storing information */ #define ccb_state ppriv_field0 #define ccb_bp ppriv_ptr1 struct disk_params { u_int8_t heads; u_int32_t cylinders; u_int8_t secs_per_track; u_int32_t secsize; /* Number of bytes/sector */ u_int64_t sectors; /* total number sectors */ }; struct da_softc { struct bio_queue_head bio_queue; SLIST_ENTRY(da_softc) links; LIST_HEAD(, ccb_hdr) pending_ccbs; da_state state; da_flags flags; da_quirks quirks; int minimum_cmd_size; int ordered_tag_count; int outstanding_cmds; struct disk_params params; struct disk *disk; union ccb saved_ccb; struct task sysctl_task; struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; }; struct da_quirk_entry { struct scsi_inquiry_pattern inq_pat; da_quirks quirks; }; static const char quantum[] = "QUANTUM"; static const char microp[] = "MICROP"; static struct da_quirk_entry da_quirk_table[] = { /* SPI, FC devices */ { /* * Fujitsu M2513A MO drives. * Tested devices: M2513A2 firmware versions 1200 & 1300. * (dip switch selects whether T_DIRECT or T_OPTICAL device) * Reported by: W.Scholten */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* See above. */ {T_OPTICAL, SIP_MEDIA_REMOVABLE, "FUJITSU", "M2513A", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * This particular Fujitsu drive doesn't like the * synchronize cache command. * Reported by: Tom Jackson */ {T_DIRECT, SIP_MEDIA_FIXED, "FUJITSU", "M2954*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * This drive doesn't like the synchronize cache command * either. Reported by: Matthew Jacob * in NetBSD PR kern/6027, August 24, 1998. */ {T_DIRECT, SIP_MEDIA_FIXED, microp, "2217*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * This drive doesn't like the synchronize cache command * either. Reported by: Hellmuth Michaelis (hm@kts.org) * (PR 8882). */ {T_DIRECT, SIP_MEDIA_FIXED, microp, "2112*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Doesn't like the synchronize cache command. * Reported by: Blaz Zupan */ {T_DIRECT, SIP_MEDIA_FIXED, "NEC", "D3847*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Doesn't like the synchronize cache command. * Reported by: Blaz Zupan */ {T_DIRECT, SIP_MEDIA_FIXED, quantum, "MAVERICK 540S", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Doesn't like the synchronize cache command. */ {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS525S", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Doesn't like the synchronize cache command. * Reported by: walter@pelissero.de */ {T_DIRECT, SIP_MEDIA_FIXED, quantum, "LPS540S", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Doesn't work correctly with 6 byte reads/writes. * Returns illegal request, and points to byte 9 of the * 6-byte CDB. * Reported by: Adam McDougall */ {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 4*", "*"}, /*quirks*/ DA_Q_NO_6_BYTE }, { /* See above. */ {T_DIRECT, SIP_MEDIA_FIXED, quantum, "VIKING 2*", "*"}, /*quirks*/ DA_Q_NO_6_BYTE }, { /* * Doesn't like the synchronize cache command. * Reported by: walter@pelissero.de */ {T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CP3500*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * The CISS RAID controllers do not support SYNC_CACHE */ {T_DIRECT, SIP_MEDIA_FIXED, "COMPAQ", "RAID*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, /* USB mass storage devices supported by umass(4) */ { /* * EXATELECOM (Sigmatel) i-Bead 100/105 USB Flash MP3 Player * PR: kern/51675 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "EXATEL", "i-BEAD10*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Power Quotient Int. (PQI) USB flash key * PR: kern/53067 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "USB Flash Disk*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Creative Nomad MUVO mp3 player (USB) * PR: kern/53094 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "NOMAD_MUVO", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT }, { /* * Jungsoft NEXDISK USB flash key * PR: kern/54737 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "JUNGSOFT", "NEXDISK*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * FreeDik USB Mini Data Drive * PR: kern/54786 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "FreeDik*", "Mini Data Drive", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Sigmatel USB Flash MP3 Player * PR: kern/57046 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "SigmaTel", "MSCN", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT }, { /* * Neuros USB Digital Audio Computer * PR: kern/63645 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "NEUROS", "dig. audio comp.", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * SEAGRAND NP-900 MP3 Player * PR: kern/64563 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "SEAGRAND", "NP-900*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT }, { /* * iRiver iFP MP3 player (with UMS Firmware) * PR: kern/54881, i386/63941, kern/66124 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "iRiver", "iFP*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Frontier Labs NEX IA+ Digital Audio Player, rev 1.10/0.01 * PR: kern/70158 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "FL" , "Nex*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * ZICPlay USB MP3 Player with FM * PR: kern/75057 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "ACTIONS*" , "USB DISK*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * TEAC USB floppy mechanisms */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "TEAC" , "FD-05*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Kingston DataTraveler II+ USB Pen-Drive. * Reported by: Pawel Jakub Dawidek */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston" , "DataTraveler II+", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Motorola E398 Mobile Phone (TransFlash memory card). * Reported by: Wojciech A. Koszek * PR: usb/89889 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "Motorola" , "Motorola Phone", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Qware BeatZkey! Pro * PR: usb/79164 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "GENERIC", "USB DISK DEVICE", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Time DPA20B 1GB MP3 Player * PR: usb/81846 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB2.0*", "(FS) FLASH DISK*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Samsung USB key 128Mb * PR: usb/90081 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "USB-DISK", "FreeDik-FlashUsb", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Kingston DataTraveler 2.0 USB Flash memory. * PR: usb/89196 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "Kingston", "DataTraveler 2.0", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * Creative MUVO Slim mp3 player (USB) * PR: usb/86131 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "CREATIVE", "MuVo Slim", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT }, { /* * United MP5512 Portable MP3 Player (2-in-1 USB DISK/MP3) * PR: usb/80487 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "MUSIC DISK", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * SanDisk Micro Cruzer 128MB * PR: usb/75970 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "SanDisk" , "Micro Cruzer", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, { /* * PNY USB Flash keys * PR: usb/75578, usb/72344, usb/65436 */ {T_DIRECT, SIP_MEDIA_REMOVABLE, "*" , "USB DISK*", "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE }, + { + /* + * Genesys 6-in-1 Card Reader + * No PR, reported by anders + */ + {T_DIRECT, SIP_MEDIA_REMOVABLE, "Generic*", "STORAGE DEVICE*", + "*"}, /*quirks*/ DA_Q_NO_SYNC_CACHE + }, }; static disk_strategy_t dastrategy; static dumper_t dadump; static periph_init_t dainit; static void daasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); static void dasysctlinit(void *context, int pending); static int dacmdsizesysctl(SYSCTL_HANDLER_ARGS); static periph_ctor_t daregister; static periph_dtor_t dacleanup; static periph_start_t dastart; static periph_oninv_t daoninvalidate; static void dadone(struct cam_periph *periph, union ccb *done_ccb); static int daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags); static void daprevent(struct cam_periph *periph, int action); static int dagetcapacity(struct cam_periph *periph); static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector); static timeout_t dasendorderedtag; static void dashutdown(void *arg, int howto); #ifndef DA_DEFAULT_TIMEOUT #define DA_DEFAULT_TIMEOUT 60 /* Timeout in seconds */ #endif #ifndef DA_DEFAULT_RETRY #define DA_DEFAULT_RETRY 4 #endif static int da_retry_count = DA_DEFAULT_RETRY; static int da_default_timeout = DA_DEFAULT_TIMEOUT; SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW, &da_retry_count, 0, "Normal I/O retry count"); TUNABLE_INT("kern.cam.da.retry_count", &da_retry_count); SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RW, &da_default_timeout, 0, "Normal I/O timeout (in seconds)"); TUNABLE_INT("kern.cam.da.default_timeout", &da_default_timeout); /* * DA_ORDEREDTAG_INTERVAL determines how often, relative * to the default timeout, we check to see whether an ordered * tagged transaction is appropriate to prevent simple tag * starvation. Since we'd like to ensure that there is at least * 1/2 of the timeout length left for a starved transaction to * complete after we've sent an ordered tag, we must poll at least * four times in every timeout period. This takes care of the worst * case where a starved transaction starts during an interval that * meets the requirement "don't send an ordered tag" test so it takes * us two intervals to determine that a tag must be sent. */ #ifndef DA_ORDEREDTAG_INTERVAL #define DA_ORDEREDTAG_INTERVAL 4 #endif static struct periph_driver dadriver = { dainit, "da", TAILQ_HEAD_INITIALIZER(dadriver.units), /* generation */ 0 }; PERIPHDRIVER_DECLARE(da, dadriver); static SLIST_HEAD(,da_softc) softc_list; static int daopen(struct disk *dp) { struct cam_periph *periph; struct da_softc *softc; int unit; int error; int s; s = splsoftcam(); periph = (struct cam_periph *)dp->d_drv1; if (periph == NULL) { splx(s); return (ENXIO); } unit = periph->unit_number; softc = (struct da_softc *)periph->softc; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("daopen: disk=%s%d (unit %d)\n", dp->d_name, dp->d_unit, unit)); if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) return (error); /* error code from tsleep */ if (cam_periph_acquire(periph) != CAM_REQ_CMP) return(ENXIO); softc->flags |= DA_FLAG_OPEN; if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) { /* Invalidate our pack information. */ softc->flags &= ~DA_FLAG_PACK_INVALID; } splx(s); error = dagetcapacity(periph); if (error == 0) { softc->disk->d_sectorsize = softc->params.secsize; softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors; /* XXX: these are not actually "firmware" values, so they may be wrong */ softc->disk->d_fwsectors = softc->params.secs_per_track; softc->disk->d_fwheads = softc->params.heads; softc->disk->d_devstat->block_size = softc->params.secsize; softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE; } if (error == 0) { if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 && (softc->quirks & DA_Q_NO_PREVENT) == 0) daprevent(periph, PR_PREVENT); } else { softc->flags &= ~DA_FLAG_OPEN; cam_periph_release(periph); } cam_periph_unlock(periph); return (error); } static int daclose(struct disk *dp) { struct cam_periph *periph; struct da_softc *softc; int error; periph = (struct cam_periph *)dp->d_drv1; if (periph == NULL) return (ENXIO); softc = (struct da_softc *)periph->softc; if ((error = cam_periph_lock(periph, PRIBIO)) != 0) { return (error); /* error code from tsleep */ } if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) { union ccb *ccb; ccb = cam_periph_getccb(periph, /*priority*/1); scsi_synchronize_cache(&ccb->csio, /*retries*/1, /*cbfcnp*/dadone, MSG_SIMPLE_Q_TAG, /*begin_lba*/0,/* Cover the whole disk */ /*lb_count*/0, SSD_FULL_SIZE, 5 * 60 * 1000); cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA, softc->disk->d_devstat); if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) { int asc, ascq; int sense_key, error_code; scsi_extract_sense(&ccb->csio.sense_data, &error_code, &sense_key, &asc, &ascq); if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&ccb->csio); } else { xpt_print_path(periph->path); printf("Synchronize cache failed, status " "== 0x%x, scsi status == 0x%x\n", ccb->csio.ccb_h.status, ccb->csio.scsi_status); } } if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); xpt_release_ccb(ccb); } if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) { if ((softc->quirks & DA_Q_NO_PREVENT) == 0) daprevent(periph, PR_ALLOW); /* * If we've got removeable media, mark the blocksize as * unavailable, since it could change when new media is * inserted. */ softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE; } softc->flags &= ~DA_FLAG_OPEN; cam_periph_unlock(periph); cam_periph_release(periph); return (0); } /* * Actually translate the requested transfer into one the physical driver * can understand. The transfer is described by a buf and will include * only one physical transfer. */ static void dastrategy(struct bio *bp) { struct cam_periph *periph; struct da_softc *softc; int s; periph = (struct cam_periph *)bp->bio_disk->d_drv1; if (periph == NULL) { biofinish(bp, NULL, ENXIO); return; } softc = (struct da_softc *)periph->softc; #if 0 /* * check it's not too big a transfer for our adapter */ scsi_minphys(bp,&sd_switch); #endif /* * Mask interrupts so that the pack cannot be invalidated until * after we are in the queue. Otherwise, we might not properly * clean up one of the buffers. */ s = splbio(); /* * If the device has been made invalid, error out */ if ((softc->flags & DA_FLAG_PACK_INVALID)) { splx(s); biofinish(bp, NULL, ENXIO); return; } /* * Place it in the queue of disk activities for this disk */ bioq_disksort(&softc->bio_queue, bp); splx(s); /* * Schedule ourselves for performing the work. */ xpt_schedule(periph, /* XXX priority */1); return; } static int dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length) { struct cam_periph *periph; struct da_softc *softc; u_int secsize; struct ccb_scsiio csio; struct disk *dp; dp = arg; periph = dp->d_drv1; if (periph == NULL) return (ENXIO); softc = (struct da_softc *)periph->softc; secsize = softc->params.secsize; if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) return (ENXIO); if (length > 0) { xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1); csio.ccb_h.ccb_state = DA_CCB_DUMP; scsi_read_write(&csio, /*retries*/1, dadone, MSG_ORDERED_Q_TAG, /*read*/FALSE, /*byte2*/0, /*minimum_cmd_size*/ softc->minimum_cmd_size, offset / secsize, length / secsize, /*data_ptr*/(u_int8_t *) virtual, /*dxfer_len*/length, /*sense_len*/SSD_FULL_SIZE, DA_DEFAULT_TIMEOUT * 1000); xpt_polled_action((union ccb *)&csio); if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { printf("Aborting dump due to I/O error.\n"); if ((csio.ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) scsi_sense_print(&csio); else printf("status == 0x%x, scsi status == 0x%x\n", csio.ccb_h.status, csio.scsi_status); return(EIO); } return(0); } /* * Sync the disk cache contents to the physical media. */ if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) { xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1); csio.ccb_h.ccb_state = DA_CCB_DUMP; scsi_synchronize_cache(&csio, /*retries*/1, /*cbfcnp*/dadone, MSG_SIMPLE_Q_TAG, /*begin_lba*/0,/* Cover the whole disk */ /*lb_count*/0, SSD_FULL_SIZE, 5 * 60 * 1000); xpt_polled_action((union ccb *)&csio); if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if ((csio.ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) { int asc, ascq; int sense_key, error_code; scsi_extract_sense(&csio.sense_data, &error_code, &sense_key, &asc, &ascq); if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&csio); } else { xpt_print_path(periph->path); printf("Synchronize cache failed, status " "== 0x%x, scsi status == 0x%x\n", csio.ccb_h.status, csio.scsi_status); } } } return (0); } static void dainit(void) { cam_status status; struct cam_path *path; SLIST_INIT(&softc_list); /* * Install a global async callback. This callback will * receive async callbacks like "new device found". */ status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); if (status == CAM_REQ_CMP) { struct ccb_setasync csa; xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_FOUND_DEVICE; csa.callback = daasync; csa.callback_arg = NULL; xpt_action((union ccb *)&csa); status = csa.ccb_h.status; xpt_free_path(path); } if (status != CAM_REQ_CMP) { printf("da: Failed to attach master async callback " "due to status 0x%x!\n", status); } else { /* * Schedule a periodic event to occasionally send an * ordered tag to a device. */ timeout(dasendorderedtag, NULL, (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL); /* Register our shutdown event handler */ if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) printf("dainit: shutdown event registration failed!\n"); } } static void daoninvalidate(struct cam_periph *periph) { int s; struct da_softc *softc; struct ccb_setasync csa; softc = (struct da_softc *)periph->softc; /* * De-register any async callbacks. */ xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = 0; csa.callback = daasync; csa.callback_arg = periph; xpt_action((union ccb *)&csa); softc->flags |= DA_FLAG_PACK_INVALID; /* * Although the oninvalidate() routines are always called at * splsoftcam, we need to be at splbio() here to keep the buffer * queue from being modified while we traverse it. */ s = splbio(); /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. */ bioq_flush(&softc->bio_queue, NULL, ENXIO); splx(s); SLIST_REMOVE(&softc_list, softc, da_softc, links); disk_gone(softc->disk); xpt_print_path(periph->path); printf("lost device\n"); } static void dacleanup(struct cam_periph *periph) { struct da_softc *softc; softc = (struct da_softc *)periph->softc; xpt_print_path(periph->path); printf("removing device entry\n"); /* * If we can't free the sysctl tree, oh well... */ if ((softc->flags & DA_FLAG_SCTX_INIT) != 0 && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { xpt_print_path(periph->path); printf("can't remove sysctl context\n"); } disk_destroy(softc->disk); free(softc, M_DEVBUF); } static void daasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) { struct cam_periph *periph; periph = (struct cam_periph *)callback_arg; switch (code) { case AC_FOUND_DEVICE: { struct ccb_getdev *cgd; cam_status status; cgd = (struct ccb_getdev *)arg; if (cgd == NULL) break; if (SID_TYPE(&cgd->inq_data) != T_DIRECT && SID_TYPE(&cgd->inq_data) != T_RBC && SID_TYPE(&cgd->inq_data) != T_OPTICAL) break; /* * Allocate a peripheral instance for * this device and start the probe * process. */ status = cam_periph_alloc(daregister, daoninvalidate, dacleanup, dastart, "da", CAM_PERIPH_BIO, cgd->ccb_h.path, daasync, AC_FOUND_DEVICE, cgd); if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) printf("daasync: Unable to attach to new device " "due to status 0x%x\n", status); break; } case AC_SENT_BDR: case AC_BUS_RESET: { struct da_softc *softc; struct ccb_hdr *ccbh; int s; softc = (struct da_softc *)periph->softc; s = splsoftcam(); /* * Don't fail on the expected unit attention * that will occur. */ softc->flags |= DA_FLAG_RETRY_UA; LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) ccbh->ccb_state |= DA_CCB_RETRY_UA; splx(s); /* FALLTHROUGH*/ } default: cam_periph_async(periph, code, path, arg); break; } } static void dasysctlinit(void *context, int pending) { struct cam_periph *periph; struct da_softc *softc; char tmpstr[80], tmpstr2[80]; periph = (struct cam_periph *)context; softc = (struct da_softc *)periph->softc; snprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number); snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); mtx_lock(&Giant); sysctl_ctx_init(&softc->sysctl_ctx); softc->flags |= DA_FLAG_SCTX_INIT; softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, SYSCTL_STATIC_CHILDREN(_kern_cam_da), OID_AUTO, tmpstr2, CTLFLAG_RD, 0, tmpstr); if (softc->sysctl_tree == NULL) { printf("dasysctlinit: unable to allocate sysctl tree\n"); return; } /* * Now register the sysctl handler, so the user can the value on * the fly. */ SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, &softc->minimum_cmd_size, 0, dacmdsizesysctl, "I", "Minimum CDB size"); mtx_unlock(&Giant); } static int dacmdsizesysctl(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if ((error != 0) || (req->newptr == NULL)) return (error); /* * Acceptable values here are 6, 10, 12 or 16. */ if (value < 6) value = 6; else if ((value > 6) && (value <= 10)) value = 10; else if ((value > 10) && (value <= 12)) value = 12; else if (value > 12) value = 16; *(int *)arg1 = value; return (0); } static cam_status daregister(struct cam_periph *periph, void *arg) { int s; struct da_softc *softc; struct ccb_setasync csa; struct ccb_pathinq cpi; struct ccb_getdev *cgd; char tmpstr[80]; caddr_t match; cgd = (struct ccb_getdev *)arg; if (periph == NULL) { printf("daregister: periph was NULL!!\n"); return(CAM_REQ_CMP_ERR); } if (cgd == NULL) { printf("daregister: no getdev CCB, can't register device\n"); return(CAM_REQ_CMP_ERR); } softc = (struct da_softc *)malloc(sizeof(*softc), M_DEVBUF, M_NOWAIT|M_ZERO); if (softc == NULL) { printf("daregister: Unable to probe new device. " "Unable to allocate softc\n"); return(CAM_REQ_CMP_ERR); } LIST_INIT(&softc->pending_ccbs); softc->state = DA_STATE_PROBE; bioq_init(&softc->bio_queue); if (SID_IS_REMOVABLE(&cgd->inq_data)) softc->flags |= DA_FLAG_PACK_REMOVABLE; if ((cgd->inq_data.flags & SID_CmdQue) != 0) softc->flags |= DA_FLAG_TAGGED_QUEUING; periph->softc = softc; /* * See if this device has any quirks. */ match = cam_quirkmatch((caddr_t)&cgd->inq_data, (caddr_t)da_quirk_table, sizeof(da_quirk_table)/sizeof(*da_quirk_table), sizeof(*da_quirk_table), scsi_inquiry_match); if (match != NULL) softc->quirks = ((struct da_quirk_entry *)match)->quirks; else softc->quirks = DA_Q_NONE; /* Check if the SIM does not want 6 byte commands */ xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); cpi.ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)&cpi); if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE)) softc->quirks |= DA_Q_NO_6_BYTE; TASK_INIT(&softc->sysctl_task, 0, dasysctlinit, periph); /* * RBC devices don't have to support READ(6), only READ(10). */ if (softc->quirks & DA_Q_NO_6_BYTE || SID_TYPE(&cgd->inq_data) == T_RBC) softc->minimum_cmd_size = 10; else softc->minimum_cmd_size = 6; /* * Load the user's default, if any. */ snprintf(tmpstr, sizeof(tmpstr), "kern.cam.da.%d.minimum_cmd_size", periph->unit_number); TUNABLE_INT_FETCH(tmpstr, &softc->minimum_cmd_size); /* * 6, 10, 12 and 16 are the currently permissible values. */ if (softc->minimum_cmd_size < 6) softc->minimum_cmd_size = 6; else if ((softc->minimum_cmd_size > 6) && (softc->minimum_cmd_size <= 10)) softc->minimum_cmd_size = 10; else if ((softc->minimum_cmd_size > 10) && (softc->minimum_cmd_size <= 12)) softc->minimum_cmd_size = 12; else if (softc->minimum_cmd_size > 12) softc->minimum_cmd_size = 16; /* * Block our timeout handler while we * add this softc to the dev list. */ s = splsoftclock(); SLIST_INSERT_HEAD(&softc_list, softc, links); splx(s); /* * Register this media as a disk */ softc->disk = disk_alloc(); softc->disk->d_open = daopen; softc->disk->d_close = daclose; softc->disk->d_strategy = dastrategy; softc->disk->d_dump = dadump; softc->disk->d_name = "da"; softc->disk->d_drv1 = periph; softc->disk->d_maxsize = DFLTPHYS; /* XXX: probably not arbitrary */ softc->disk->d_unit = periph->unit_number; softc->disk->d_flags = DISKFLAG_NEEDSGIANT; disk_create(softc->disk, DISK_VERSION); /* * Add async callbacks for bus reset and * bus device reset calls. I don't bother * checking if this fails as, in most cases, * the system will function just fine without * them and the only alternative would be to * not attach the device on failure. */ xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; csa.callback = daasync; csa.callback_arg = periph; xpt_action((union ccb *)&csa); /* * Lock this peripheral until we are setup. * This first call can't block */ (void)cam_periph_lock(periph, PRIBIO); xpt_schedule(periph, /*priority*/5); return(CAM_REQ_CMP); } static void dastart(struct cam_periph *periph, union ccb *start_ccb) { struct da_softc *softc; softc = (struct da_softc *)periph->softc; switch (softc->state) { case DA_STATE_NORMAL: { /* Pull a buffer from the queue and get going on it */ struct bio *bp; int s; /* * See if there is a buf with work for us to do.. */ s = splbio(); bp = bioq_first(&softc->bio_queue); if (periph->immediate_priority <= periph->pinfo.priority) { CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, ("queuing for immediate ccb\n")); start_ccb->ccb_h.ccb_state = DA_CCB_WAITING; SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; splx(s); wakeup(&periph->ccb_list); } else if (bp == NULL) { splx(s); xpt_release_ccb(start_ccb); } else { int oldspl; u_int8_t tag_code; bioq_remove(&softc->bio_queue, bp); if ((softc->flags & DA_FLAG_NEED_OTAG) != 0) { softc->flags &= ~DA_FLAG_NEED_OTAG; softc->ordered_tag_count++; tag_code = MSG_ORDERED_Q_TAG; } else { tag_code = MSG_SIMPLE_Q_TAG; } scsi_read_write(&start_ccb->csio, /*retries*/da_retry_count, /*cbfcnp*/dadone, /*tag_action*/tag_code, /*read_op*/bp->bio_cmd == BIO_READ, /*byte2*/0, softc->minimum_cmd_size, /*lba*/bp->bio_pblkno, /*block_count*/bp->bio_bcount / softc->params.secsize, /*data_ptr*/ bp->bio_data, /*dxfer_len*/ bp->bio_bcount, /*sense_len*/SSD_FULL_SIZE, /*timeout*/da_default_timeout*1000); start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO; /* * Block out any asyncronous callbacks * while we touch the pending ccb list. */ oldspl = splcam(); LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, periph_links.le); softc->outstanding_cmds++; splx(oldspl); /* We expect a unit attention from this device */ if ((softc->flags & DA_FLAG_RETRY_UA) != 0) { start_ccb->ccb_h.ccb_state |= DA_CCB_RETRY_UA; softc->flags &= ~DA_FLAG_RETRY_UA; } start_ccb->ccb_h.ccb_bp = bp; bp = bioq_first(&softc->bio_queue); splx(s); xpt_action(start_ccb); } if (bp != NULL) { /* Have more work to do, so ensure we stay scheduled */ xpt_schedule(periph, /* XXX priority */1); } break; } case DA_STATE_PROBE: { struct ccb_scsiio *csio; struct scsi_read_capacity_data *rcap; rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), M_TEMP, M_NOWAIT); if (rcap == NULL) { printf("dastart: Couldn't malloc read_capacity data\n"); /* da_free_periph??? */ break; } csio = &start_ccb->csio; scsi_read_capacity(csio, /*retries*/4, dadone, MSG_SIMPLE_Q_TAG, rcap, SSD_FULL_SIZE, /*timeout*/5000); start_ccb->ccb_h.ccb_bp = NULL; start_ccb->ccb_h.ccb_state = DA_CCB_PROBE; xpt_action(start_ccb); break; } case DA_STATE_PROBE2: { struct ccb_scsiio *csio; struct scsi_read_capacity_data_long *rcaplong; rcaplong = (struct scsi_read_capacity_data_long *) malloc(sizeof(*rcaplong), M_TEMP, M_NOWAIT); if (rcaplong == NULL) { printf("dastart: Couldn't malloc read_capacity data\n"); /* da_free_periph??? */ break; } csio = &start_ccb->csio; scsi_read_capacity_16(csio, /*retries*/ 4, /*cbfcnp*/ dadone, /*tag_action*/ MSG_SIMPLE_Q_TAG, /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, rcaplong, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); start_ccb->ccb_h.ccb_bp = NULL; start_ccb->ccb_h.ccb_state = DA_CCB_PROBE2; xpt_action(start_ccb); break; } } } static int cmd6workaround(union ccb *ccb) { struct scsi_rw_6 cmd6; struct scsi_rw_10 *cmd10; struct da_softc *softc; u_int8_t *cdb; int frozen; cdb = ccb->csio.cdb_io.cdb_bytes; /* Translation only possible if CDB is an array and cmd is R/W6 */ if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0 || (*cdb != READ_6 && *cdb != WRITE_6)) return 0; xpt_print_path(ccb->ccb_h.path); printf("READ(6)/WRITE(6) not supported, " "increasing minimum_cmd_size to 10.\n"); softc = (struct da_softc *)xpt_path_periph(ccb->ccb_h.path)->softc; softc->minimum_cmd_size = 10; bcopy(cdb, &cmd6, sizeof(struct scsi_rw_6)); cmd10 = (struct scsi_rw_10 *)cdb; cmd10->opcode = (cmd6.opcode == READ_6) ? READ_10 : WRITE_10; cmd10->byte2 = 0; scsi_ulto4b(scsi_3btoul(cmd6.addr), cmd10->addr); cmd10->reserved = 0; scsi_ulto2b(cmd6.length, cmd10->length); cmd10->control = cmd6.control; ccb->csio.cdb_len = sizeof(*cmd10); /* Requeue request, unfreezing queue if necessary */ frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0; ccb->ccb_h.status = CAM_REQUEUE_REQ; xpt_action(ccb); if (frozen) { cam_release_devq(ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); } return (ERESTART); } static void dadone(struct cam_periph *periph, union ccb *done_ccb) { struct da_softc *softc; struct ccb_scsiio *csio; softc = (struct da_softc *)periph->softc; csio = &done_ccb->csio; switch (csio->ccb_h.ccb_state & DA_CCB_TYPE_MASK) { case DA_CCB_BUFFER_IO: { struct bio *bp; int oldspl; bp = (struct bio *)done_ccb->ccb_h.ccb_bp; if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { int error; int s; int sf; if ((csio->ccb_h.ccb_state & DA_CCB_RETRY_UA) != 0) sf = SF_RETRY_UA; else sf = 0; error = daerror(done_ccb, CAM_RETRY_SELTO, sf); if (error == ERESTART) { /* * A retry was scheuled, so * just return. */ return; } if (error != 0) { s = splbio(); if (error == ENXIO) { /* * Catastrophic error. Mark our pack as * invalid. */ /* XXX See if this is really a media * change first. */ xpt_print_path(periph->path); printf("Invalidating pack\n"); softc->flags |= DA_FLAG_PACK_INVALID; } /* * return all queued I/O with EIO, so that * the client can retry these I/Os in the * proper order should it attempt to recover. */ bioq_flush(&softc->bio_queue, NULL, EIO); splx(s); bp->bio_error = error; bp->bio_resid = bp->bio_bcount; bp->bio_flags |= BIO_ERROR; } else { bp->bio_resid = csio->resid; bp->bio_error = 0; if (bp->bio_resid != 0) bp->bio_flags |= BIO_ERROR; } if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(done_ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); } else { if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) panic("REQ_CMP with QFRZN"); bp->bio_resid = csio->resid; if (csio->resid > 0) bp->bio_flags |= BIO_ERROR; } /* * Block out any asyncronous callbacks * while we touch the pending ccb list. */ oldspl = splcam(); LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); softc->outstanding_cmds--; if (softc->outstanding_cmds == 0) softc->flags |= DA_FLAG_WENT_IDLE; splx(oldspl); biodone(bp); break; } case DA_CCB_PROBE: case DA_CCB_PROBE2: { struct scsi_read_capacity_data *rdcap; struct scsi_read_capacity_data_long *rcaplong; char announce_buf[80]; rdcap = NULL; rcaplong = NULL; if (softc->state == DA_STATE_PROBE) rdcap =(struct scsi_read_capacity_data *)csio->data_ptr; else rcaplong = (struct scsi_read_capacity_data_long *) csio->data_ptr; if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { struct disk_params *dp; uint32_t block_size; uint64_t maxsector; if (softc->state == DA_STATE_PROBE) { block_size = scsi_4btoul(rdcap->length); maxsector = scsi_4btoul(rdcap->addr); /* * According to SBC-2, if the standard 10 * byte READ CAPACITY command returns 2^32, * we should issue the 16 byte version of * the command, since the device in question * has more sectors than can be represented * with the short version of the command. */ if (maxsector == 0xffffffff) { softc->state = DA_STATE_PROBE2; free(rdcap, M_TEMP); xpt_release_ccb(done_ccb); xpt_schedule(periph, /*priority*/5); return; } } else { block_size = scsi_4btoul(rcaplong->length); maxsector = scsi_8btou64(rcaplong->addr); } dasetgeom(periph, block_size, maxsector); dp = &softc->params; snprintf(announce_buf, sizeof(announce_buf), "%juMB (%ju %u byte sectors: %dH %dS/T %dC)", (uintmax_t) (((uintmax_t)dp->secsize * dp->sectors) / (1024*1024)), (uintmax_t)dp->sectors, dp->secsize, dp->heads, dp->secs_per_track, dp->cylinders); } else { int error; announce_buf[0] = '\0'; /* * Retry any UNIT ATTENTION type errors. They * are expected at boot. */ error = daerror(done_ccb, CAM_RETRY_SELTO, SF_RETRY_UA|SF_NO_PRINT); if (error == ERESTART) { /* * A retry was scheuled, so * just return. */ return; } else if (error != 0) { struct scsi_sense_data *sense; int asc, ascq; int sense_key, error_code; int have_sense; cam_status status; struct ccb_getdev cgd; /* Don't wedge this device's queue */ status = done_ccb->ccb_h.status; if ((status & CAM_DEV_QFRZN) != 0) cam_release_devq(done_ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path, /* priority */ 1); cgd.ccb_h.func_code = XPT_GDEV_TYPE; xpt_action((union ccb *)&cgd); if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) || ((status & CAM_AUTOSNS_VALID) == 0)) have_sense = FALSE; else have_sense = TRUE; if (have_sense) { sense = &csio->sense_data; scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq); } /* * Attach to anything that claims to be a * direct access or optical disk device, * as long as it doesn't return a "Logical * unit not supported" (0x25) error. */ if ((have_sense) && (asc != 0x25) && (error_code == SSD_CURRENT_ERROR)) { const char *sense_key_desc; const char *asc_desc; scsi_sense_desc(sense_key, asc, ascq, &cgd.inq_data, &sense_key_desc, &asc_desc); snprintf(announce_buf, sizeof(announce_buf), "Attempt to query device " "size failed: %s, %s", sense_key_desc, asc_desc); } else { if (have_sense) scsi_sense_print( &done_ccb->csio); else { xpt_print_path(periph->path); printf("got CAM status %#x\n", done_ccb->ccb_h.status); } xpt_print_path(periph->path); printf("fatal error, failed" " to attach to device\n"); /* * Free up resources. */ cam_periph_invalidate(periph); } } } free(csio->data_ptr, M_TEMP); if (announce_buf[0] != '\0') { xpt_announce_periph(periph, announce_buf); /* * Create our sysctl variables, now that we know * we have successfully attached. */ taskqueue_enqueue(taskqueue_thread,&softc->sysctl_task); } softc->state = DA_STATE_NORMAL; /* * Since our peripheral may be invalidated by an error * above or an external event, we must release our CCB * before releasing the probe lock on the peripheral. * The peripheral will only go away once the last lock * is removed, and we need it around for the CCB release * operation. */ xpt_release_ccb(done_ccb); cam_periph_unlock(periph); return; } case DA_CCB_WAITING: { /* Caller will release the CCB */ wakeup(&done_ccb->ccb_h.cbfcnp); return; } case DA_CCB_DUMP: /* No-op. We're polling */ return; default: break; } xpt_release_ccb(done_ccb); } static int daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) { struct da_softc *softc; struct cam_periph *periph; int error; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct da_softc *)periph->softc; /* * Automatically detect devices that do not support * READ(6)/WRITE(6) and upgrade to using 10 byte cdbs. */ error = 0; if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { error = cmd6workaround(ccb); } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { int sense_key, error_code, asc, ascq; scsi_extract_sense(&ccb->csio.sense_data, &error_code, &sense_key, &asc, &ascq); if (sense_key == SSD_KEY_ILLEGAL_REQUEST) error = cmd6workaround(ccb); } if (error == ERESTART) return (ERESTART); /* * XXX * Until we have a better way of doing pack validation, * don't treat UAs as errors. */ sense_flags |= SF_RETRY_UA; return(cam_periph_error(ccb, cam_flags, sense_flags, &softc->saved_ccb)); } static void daprevent(struct cam_periph *periph, int action) { struct da_softc *softc; union ccb *ccb; int error; softc = (struct da_softc *)periph->softc; if (((action == PR_ALLOW) && (softc->flags & DA_FLAG_PACK_LOCKED) == 0) || ((action == PR_PREVENT) && (softc->flags & DA_FLAG_PACK_LOCKED) != 0)) { return; } ccb = cam_periph_getccb(periph, /*priority*/1); scsi_prevent(&ccb->csio, /*retries*/1, /*cbcfp*/dadone, MSG_SIMPLE_Q_TAG, action, SSD_FULL_SIZE, 5000); error = cam_periph_runccb(ccb, /*error_routine*/NULL, CAM_RETRY_SELTO, SF_RETRY_UA, softc->disk->d_devstat); if (error == 0) { if (action == PR_ALLOW) softc->flags &= ~DA_FLAG_PACK_LOCKED; else softc->flags |= DA_FLAG_PACK_LOCKED; } xpt_release_ccb(ccb); } static int dagetcapacity(struct cam_periph *periph) { struct da_softc *softc; union ccb *ccb; struct scsi_read_capacity_data *rcap; struct scsi_read_capacity_data_long *rcaplong; uint32_t block_len; uint64_t maxsector; int error; softc = (struct da_softc *)periph->softc; block_len = 0; maxsector = 0; error = 0; /* Do a read capacity */ rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong), M_TEMP, M_WAITOK); ccb = cam_periph_getccb(periph, /*priority*/1); scsi_read_capacity(&ccb->csio, /*retries*/4, /*cbfncp*/dadone, MSG_SIMPLE_Q_TAG, rcap, SSD_FULL_SIZE, /*timeout*/60000); ccb->ccb_h.ccb_bp = NULL; error = cam_periph_runccb(ccb, daerror, /*cam_flags*/CAM_RETRY_SELTO, /*sense_flags*/SF_RETRY_UA, softc->disk->d_devstat); if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); if (error == 0) { block_len = scsi_4btoul(rcap->length); maxsector = scsi_4btoul(rcap->addr); if (maxsector != 0xffffffff) goto done; } else goto done; rcaplong = (struct scsi_read_capacity_data_long *)rcap; scsi_read_capacity_16(&ccb->csio, /*retries*/ 4, /*cbfcnp*/ dadone, /*tag_action*/ MSG_SIMPLE_Q_TAG, /*lba*/ 0, /*reladr*/ 0, /*pmi*/ 0, rcaplong, /*sense_len*/ SSD_FULL_SIZE, /*timeout*/ 60000); ccb->ccb_h.ccb_bp = NULL; error = cam_periph_runccb(ccb, daerror, /*cam_flags*/CAM_RETRY_SELTO, /*sense_flags*/SF_RETRY_UA, softc->disk->d_devstat); if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); if (error == 0) { block_len = scsi_4btoul(rcaplong->length); maxsector = scsi_8btou64(rcaplong->addr); } done: if (error == 0) dasetgeom(periph, block_len, maxsector); xpt_release_ccb(ccb); free(rcap, M_TEMP); return (error); } static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector) { struct ccb_calc_geometry ccg; struct da_softc *softc; struct disk_params *dp; softc = (struct da_softc *)periph->softc; dp = &softc->params; dp->secsize = block_len; dp->sectors = maxsector + 1; /* * Have the controller provide us with a geometry * for this disk. The only time the geometry * matters is when we boot and the controller * is the only one knowledgeable enough to come * up with something that will make this a bootable * device. */ xpt_setup_ccb(&ccg.ccb_h, periph->path, /*priority*/1); ccg.ccb_h.func_code = XPT_CALC_GEOMETRY; ccg.block_size = dp->secsize; ccg.volume_size = dp->sectors; ccg.heads = 0; ccg.secs_per_track = 0; ccg.cylinders = 0; xpt_action((union ccb*)&ccg); dp->heads = ccg.heads; dp->secs_per_track = ccg.secs_per_track; dp->cylinders = ccg.cylinders; } static void dasendorderedtag(void *arg) { struct da_softc *softc; int s; for (softc = SLIST_FIRST(&softc_list); softc != NULL; softc = SLIST_NEXT(softc, links)) { s = splsoftcam(); if ((softc->ordered_tag_count == 0) && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) { softc->flags |= DA_FLAG_NEED_OTAG; } if (softc->outstanding_cmds > 0) softc->flags &= ~DA_FLAG_WENT_IDLE; softc->ordered_tag_count = 0; splx(s); } /* Queue us up again */ timeout(dasendorderedtag, NULL, (da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL); } /* * Step through all DA peripheral drivers, and if the device is still open, * sync the disk cache to physical media. */ static void dashutdown(void * arg, int howto) { struct cam_periph *periph; struct da_softc *softc; TAILQ_FOREACH(periph, &dadriver.units, unit_links) { union ccb ccb; softc = (struct da_softc *)periph->softc; /* * We only sync the cache if the drive is still open, and * if the drive is capable of it.. */ if (((softc->flags & DA_FLAG_OPEN) == 0) || (softc->quirks & DA_Q_NO_SYNC_CACHE)) continue; xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); ccb.ccb_h.ccb_state = DA_CCB_DUMP; scsi_synchronize_cache(&ccb.csio, /*retries*/1, /*cbfcnp*/dadone, MSG_SIMPLE_Q_TAG, /*begin_lba*/0, /* whole disk */ /*lb_count*/0, SSD_FULL_SIZE, 60 * 60 * 1000); xpt_polled_action(&ccb); if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) && (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){ int error_code, sense_key, asc, ascq; scsi_extract_sense(&ccb.csio.sense_data, &error_code, &sense_key, &asc, &ascq); if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&ccb.csio); } else { xpt_print_path(periph->path); printf("Synchronize cache failed, status " "== 0x%x, scsi status == 0x%x\n", ccb.ccb_h.status, ccb.csio.scsi_status); } } if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, /*getcount_only*/0); } } #else /* !_KERNEL */ /* * XXX This is only left out of the kernel build to silence warnings. If, * for some reason this function is used in the kernel, the ifdefs should * be moved so it is included both in the kernel and userland. */ void scsi_format_unit(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, u_int8_t byte2, u_int16_t ileave, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout) { struct scsi_format_unit *scsi_cmd; scsi_cmd = (struct scsi_format_unit *)&csio->cdb_io.cdb_bytes; scsi_cmd->opcode = FORMAT_UNIT; scsi_cmd->byte2 = byte2; scsi_ulto2b(ileave, scsi_cmd->interleave); cam_fill_csio(csio, retries, cbfcnp, /*flags*/ (dxfer_len > 0) ? CAM_DIR_OUT : CAM_DIR_NONE, tag_action, data_ptr, dxfer_len, sense_len, sizeof(*scsi_cmd), timeout); } #endif /* _KERNEL */ Index: head/sys/dev/usb/umass.c =================================================================== --- head/sys/dev/usb/umass.c (revision 155062) +++ head/sys/dev/usb/umass.c (revision 155063) @@ -1,3196 +1,3200 @@ /*- * Copyright (c) 1999 MAEKAWA Masahide , * Nick Hibma * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * $NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $ */ /* Also already merged from NetBSD: * $NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $ * $NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $ * $NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $ * $NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $ */ /* * Universal Serial Bus Mass Storage Class specs: * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf */ /* * Ported to NetBSD by Lennart Augustsson . * Parts of the code written by Jason R. Thorpe . */ /* * The driver handles 3 Wire Protocols * - Command/Bulk/Interrupt (CBI) * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI) * - Mass Storage Bulk-Only (BBB) * (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases) * * Over these wire protocols it handles the following command protocols * - SCSI * - UFI (floppy command set) * - 8070i (ATAPI) * * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The * sc->transform method is used to convert the commands into the appropriate * format (if at all necessary). For example, UFI requires all commands to be * 12 bytes in length amongst other things. * * The source code below is marked and can be split into a number of pieces * (in this order): * * - probe/attach/detach * - generic transfer routines * - BBB * - CBI * - CBI_I (in addition to functions from CBI) * - CAM (Common Access Method) * - SCSI * - UFI * - 8070i (ATAPI) * * The protocols are implemented using a state machine, for the transfers as * well as for the resets. The state machine is contained in umass_*_state. * The state machine is started through either umass_*_transfer or * umass_*_reset. * * The reason for doing this is a) CAM performs a lot better this way and b) it * avoids using tsleep from interrupt context (for example after a failed * transfer). */ /* * The SCSI related part of this driver has been derived from the * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@freebsd.org). * * The CAM layer uses so called actions which are messages sent to the host * adapter for completion. The actions come in through umass_cam_action. The * appropriate block of routines is called depending on the transport protocol * in use. When the transfer has finished, these routines call * umass_cam_cb again to complete the CAM command. */ /* * XXX Currently CBI with CCI is not supported because it bombs the system * when the device is detached (low frequency interrupts are detached * too late. */ #undef CBI_I #include #include #include #include #include #include #include #include #include #include "usbdevs.h" #include #include #include #include #include #include #include #ifdef USB_DEBUG #define DIF(m, x) if (umassdebug & (m)) do { x ; } while (0) #define DPRINTF(m, x) if (umassdebug & (m)) logprintf x #define UDMASS_GEN 0x00010000 /* general */ #define UDMASS_SCSI 0x00020000 /* scsi */ #define UDMASS_UFI 0x00040000 /* ufi command set */ #define UDMASS_ATAPI 0x00080000 /* 8070i command set */ #define UDMASS_CMD (UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI) #define UDMASS_USB 0x00100000 /* USB general */ #define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ #define UDMASS_CBI 0x00400000 /* CBI transfers */ #define UDMASS_WIRE (UDMASS_BBB|UDMASS_CBI) #define UDMASS_ALL 0xffff0000 /* all of the above */ int umassdebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW, &umassdebug, 0, "umass debug level"); #else #define DIF(m, x) /* nop */ #define DPRINTF(m, x) /* nop */ #endif /* Generic definitions */ /* Direction for umass_*_transfer */ #define DIR_NONE 0 #define DIR_IN 1 #define DIR_OUT 2 /* device name */ #define DEVNAME "umass" #define DEVNAME_SIM "umass-sim" #define UMASS_MAX_TRANSFER_SIZE 65536 /* Approximate maximum transfer speeds (assumes 33% overhead). */ #define UMASS_FULL_TRANSFER_SPEED 1000 #define UMASS_HIGH_TRANSFER_SPEED 40000 #define UMASS_FLOPPY_TRANSFER_SPEED 20 #define UMASS_TIMEOUT 5000 /* msecs */ /* CAM specific definitions */ #define UMASS_SCSIID_MAX 1 /* maximum number of drives expected */ #define UMASS_SCSIID_HOST UMASS_SCSIID_MAX #define MS_TO_TICKS(ms) ((ms) * hz / 1000) /* Bulk-Only features */ #define UR_BBB_RESET 0xff /* Bulk-Only reset */ #define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ /* Command Block Wrapper */ typedef struct { uDWord dCBWSignature; # define CBWSIGNATURE 0x43425355 uDWord dCBWTag; uDWord dCBWDataTransferLength; uByte bCBWFlags; # define CBWFLAGS_OUT 0x00 # define CBWFLAGS_IN 0x80 uByte bCBWLUN; uByte bCDBLength; # define CBWCDBLENGTH 16 uByte CBWCDB[CBWCDBLENGTH]; } umass_bbb_cbw_t; #define UMASS_BBB_CBW_SIZE 31 /* Command Status Wrapper */ typedef struct { uDWord dCSWSignature; # define CSWSIGNATURE 0x53425355 # define CSWSIGNATURE_IMAGINATION_DBX1 0x43425355 # define CSWSIGNATURE_OLYMPUS_C1 0x55425355 uDWord dCSWTag; uDWord dCSWDataResidue; uByte bCSWStatus; # define CSWSTATUS_GOOD 0x0 # define CSWSTATUS_FAILED 0x1 # define CSWSTATUS_PHASE 0x2 } umass_bbb_csw_t; #define UMASS_BBB_CSW_SIZE 13 /* CBI features */ #define UR_CBI_ADSC 0x00 typedef unsigned char umass_cbi_cbl_t[16]; /* Command block */ typedef union { struct { unsigned char type; #define IDB_TYPE_CCI 0x00 unsigned char value; #define IDB_VALUE_PASS 0x00 #define IDB_VALUE_FAIL 0x01 #define IDB_VALUE_PHASE 0x02 #define IDB_VALUE_PERSISTENT 0x03 #define IDB_VALUE_STATUS_MASK 0x03 } common; struct { unsigned char asc; unsigned char ascq; } ufi; } umass_cbi_sbl_t; struct umass_softc; /* see below */ typedef void (*transfer_cb_f) (struct umass_softc *sc, void *priv, int residue, int status); #define STATUS_CMD_OK 0 /* everything ok */ #define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ #define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ #define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ typedef void (*wire_reset_f) (struct umass_softc *sc, int status); typedef void (*wire_transfer_f) (struct umass_softc *sc, int lun, void *cmd, int cmdlen, void *data, int datalen, int dir, u_int timeout, transfer_cb_f cb, void *priv); typedef void (*wire_state_f) (usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err); typedef int (*command_transform_f) (struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen); struct umass_devdescr_t { u_int32_t vid; # define VID_WILDCARD 0xffffffff # define VID_EOT 0xfffffffe u_int32_t pid; # define PID_WILDCARD 0xffffffff # define PID_EOT 0xfffffffe u_int32_t rid; # define RID_WILDCARD 0xffffffff # define RID_EOT 0xfffffffe /* wire and command protocol */ u_int16_t proto; # define UMASS_PROTO_BBB 0x0001 /* USB wire protocol */ # define UMASS_PROTO_CBI 0x0002 # define UMASS_PROTO_CBI_I 0x0004 # define UMASS_PROTO_WIRE 0x00ff /* USB wire protocol mask */ # define UMASS_PROTO_SCSI 0x0100 /* command protocol */ # define UMASS_PROTO_ATAPI 0x0200 # define UMASS_PROTO_UFI 0x0400 # define UMASS_PROTO_RBC 0x0800 # define UMASS_PROTO_COMMAND 0xff00 /* command protocol mask */ /* Device specific quirks */ u_int16_t quirks; # define NO_QUIRKS 0x0000 /* The drive does not support Test Unit Ready. Convert to Start Unit */ # define NO_TEST_UNIT_READY 0x0001 /* The drive does not reset the Unit Attention state after REQUEST * SENSE has been sent. The INQUIRY command does not reset the UA * either, and so CAM runs in circles trying to retrieve the initial * INQUIRY data. */ # define RS_NO_CLEAR_UA 0x0002 /* The drive does not support START STOP. */ # define NO_START_STOP 0x0004 /* Don't ask for full inquiry data (255b). */ # define FORCE_SHORT_INQUIRY 0x0008 /* Needs to be initialised the Shuttle way */ # define SHUTTLE_INIT 0x0010 /* Drive needs to be switched to alternate iface 1 */ # define ALT_IFACE_1 0x0020 /* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */ # define FLOPPY_SPEED 0x0040 /* The device can't count and gets the residue of transfers wrong */ # define IGNORE_RESIDUE 0x0080 /* No GetMaxLun call */ # define NO_GETMAXLUN 0x0100 /* The device uses a weird CSWSIGNATURE. */ # define WRONG_CSWSIG 0x0200 /* Device cannot handle INQUIRY so fake a generic response */ # define NO_INQUIRY 0x0400 /* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */ # define NO_INQUIRY_EVPD 0x0800 /* Pad all RBC requests to 12 bytes. */ # define RBC_PAD_TO_12 0x1000 }; Static struct umass_devdescr_t umass_devdescrs[] = { { USB_VENDOR_ASAHIOPTICAL, PID_WILDCARD, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, RS_NO_CLEAR_UA }, { USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, RS_NO_CLEAR_UA }, { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE_2, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, + { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB_2, RID_WILDCARD, + UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + WRONG_CSWSIG + }, { USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_USB, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, NO_INQUIRY }, { USB_VENDOR_HP, USB_PRODUCT_HP_CDW8200, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, NO_TEST_UNIT_READY | NO_START_STOP }, { USB_VENDOR_IMAGINATION, USB_PRODUCT_IMAGINATION_DBX1, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, WRONG_CSWSIG }, { USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI, NO_TEST_UNIT_READY | NO_START_STOP | ALT_IFACE_1 }, { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_IU_CD2, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_DVR_UEH8, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100, RID_WILDCARD, /* XXX This is not correct as there are Zip drives that use ATAPI. */ UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_TEST_UNIT_READY }, { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443SU2, RID_WILDCARD, UMASS_PROTO_SCSI, NO_QUIRKS }, { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443U2, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_DUBPXXG, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, { USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_CBI, NO_TEST_UNIT_READY | NO_START_STOP }, { USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_E398, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_INQUIRY_EVPD | NO_GETMAXLUN }, { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA }, { USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY2, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3260, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY }, { USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, WRONG_CSWSIG }, { USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_UCF100, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, NO_INQUIRY | NO_GETMAXLUN }, { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB20AN, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB35AN, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_PLEXTOR, USB_PRODUCT_PLEXTOR_40_12_40U, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_TEST_UNIT_READY }, { USB_VENDOR_PNY, USB_PRODUCT_PNY_ATTACHE, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_PNY, USB_PRODUCT_PNY_A256MB, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_PNY, USB_PRODUCT_PNY_DISKPRO512, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ2_256, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_128, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_256, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, NO_INQUIRY }, { USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, NO_TEST_UNIT_READY | NO_START_STOP | SHUTTLE_INIT }, { USB_VENDOR_SIGMATEL, USB_PRODUCT_SIGMATEL_I_BEAD100, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, SHUTTLE_INIT }, { USB_VENDOR_SIIG, USB_PRODUCT_SIIG_WINTERREADER, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0500, UMASS_PROTO_RBC | UMASS_PROTO_CBI, RBC_PAD_TO_12 }, { USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, RID_WILDCARD, UMASS_PROTO_RBC | UMASS_PROTO_CBI, NO_QUIRKS }, { USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, RID_WILDCARD, UMASS_PROTO_RBC | UMASS_PROTO_CBI, NO_QUIRKS }, { USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC, RID_WILDCARD, UMASS_PROTO_RBC | UMASS_PROTO_CBI, NO_QUIRKS }, { USB_VENDOR_TREK, USB_PRODUCT_TREK_THUMBDRIVE_8MB, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_BBB, IGNORE_RESIDUE }, { USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_C3310, RID_WILDCARD, UMASS_PROTO_UFI | UMASS_PROTO_CBI, NO_QUIRKS }, { USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_MDIV, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, { USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_EXTHDD, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, { USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO, RID_WILDCARD, UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, FORCE_SHORT_INQUIRY }, { VID_EOT, PID_EOT, RID_EOT, 0, 0 } }; /* the per device structure */ struct umass_softc { USBBASEDEVICE sc_dev; /* base device */ usbd_device_handle sc_udev; /* USB device */ struct cam_sim *umass_sim; /* SCSI Interface Module */ unsigned char flags; /* various device flags */ # define UMASS_FLAGS_GONE 0x01 /* devices is no more */ u_int16_t proto; /* wire and cmd protocol */ u_int16_t quirks; /* they got it almost right */ usbd_interface_handle iface; /* Mass Storage interface */ int ifaceno; /* MS iface number */ u_int8_t bulkin; /* bulk-in Endpoint Address */ u_int8_t bulkout; /* bulk-out Endpoint Address */ u_int8_t intrin; /* intr-in Endp. (CBI) */ usbd_pipe_handle bulkin_pipe; usbd_pipe_handle bulkout_pipe; usbd_pipe_handle intrin_pipe; /* Reset the device in a wire protocol specific way */ wire_reset_f reset; /* The start of a wire transfer. It prepares the whole transfer (cmd, * data, and status stage) and initiates it. It is up to the state * machine (below) to handle the various stages and errors in these */ wire_transfer_f transfer; /* The state machine, handling the various states during a transfer */ wire_state_f state; /* The command transform function is used to conver the SCSI commands * into their derivatives, like UFI, ATAPI, and friends. */ command_transform_f transform; /* command transform */ /* Bulk specific variables for transfers in progress */ umass_bbb_cbw_t cbw; /* command block wrapper */ umass_bbb_csw_t csw; /* command status wrapper*/ /* CBI specific variables for transfers in progress */ umass_cbi_cbl_t cbl; /* command block */ umass_cbi_sbl_t sbl; /* status block */ /* generic variables for transfers in progress */ /* ctrl transfer requests */ usb_device_request_t request; /* xfer handles * Most of our operations are initiated from interrupt context, so * we need to avoid using the one that is in use. We want to avoid * allocating them in the interrupt context as well. */ /* indices into array below */ # define XFER_BBB_CBW 0 /* Bulk-Only */ # define XFER_BBB_DATA 1 # define XFER_BBB_DCLEAR 2 # define XFER_BBB_CSW1 3 # define XFER_BBB_CSW2 4 # define XFER_BBB_SCLEAR 5 # define XFER_BBB_RESET1 6 # define XFER_BBB_RESET2 7 # define XFER_BBB_RESET3 8 # define XFER_CBI_CB 0 /* CBI */ # define XFER_CBI_DATA 1 # define XFER_CBI_STATUS 2 # define XFER_CBI_DCLEAR 3 # define XFER_CBI_SCLEAR 4 # define XFER_CBI_RESET1 5 # define XFER_CBI_RESET2 6 # define XFER_CBI_RESET3 7 # define XFER_NR 9 /* maximum number */ usbd_xfer_handle transfer_xfer[XFER_NR]; /* for ctrl xfers */ int transfer_dir; /* data direction */ void *transfer_data; /* data buffer */ int transfer_datalen; /* (maximum) length */ int transfer_actlen; /* actual length */ transfer_cb_f transfer_cb; /* callback */ void *transfer_priv; /* for callback */ int transfer_status; int transfer_state; # define TSTATE_ATTACH 0 /* in attach */ # define TSTATE_IDLE 1 # define TSTATE_BBB_COMMAND 2 /* CBW transfer */ # define TSTATE_BBB_DATA 3 /* Data transfer */ # define TSTATE_BBB_DCLEAR 4 /* clear endpt stall */ # define TSTATE_BBB_STATUS1 5 /* clear endpt stall */ # define TSTATE_BBB_SCLEAR 6 /* clear endpt stall */ # define TSTATE_BBB_STATUS2 7 /* CSW transfer */ # define TSTATE_BBB_RESET1 8 /* reset command */ # define TSTATE_BBB_RESET2 9 /* in clear stall */ # define TSTATE_BBB_RESET3 10 /* out clear stall */ # define TSTATE_CBI_COMMAND 11 /* command transfer */ # define TSTATE_CBI_DATA 12 /* data transfer */ # define TSTATE_CBI_STATUS 13 /* status transfer */ # define TSTATE_CBI_DCLEAR 14 /* clear ep stall */ # define TSTATE_CBI_SCLEAR 15 /* clear ep stall */ # define TSTATE_CBI_RESET1 16 /* reset command */ # define TSTATE_CBI_RESET2 17 /* in clear stall */ # define TSTATE_CBI_RESET3 18 /* out clear stall */ # define TSTATE_STATES 19 /* # of states above */ /* SCSI/CAM specific variables */ unsigned char cam_scsi_command[CAM_MAX_CDBLEN]; unsigned char cam_scsi_command2[CAM_MAX_CDBLEN]; struct scsi_sense cam_scsi_sense; struct scsi_sense cam_scsi_test_unit_ready; usb_callout_t cam_scsi_rescan_ch; int timeout; /* in msecs */ int maxlun; /* maximum LUN number */ }; #ifdef USB_DEBUG char *states[TSTATE_STATES+1] = { /* should be kept in sync with the list at transfer_state */ "Attach", "Idle", "BBB CBW", "BBB Data", "BBB Data bulk-in/-out clear stall", "BBB CSW, 1st attempt", "BBB CSW bulk-in clear stall", "BBB CSW, 2nd attempt", "BBB Reset", "BBB bulk-in clear stall", "BBB bulk-out clear stall", "CBI Command", "CBI Data", "CBI Status", "CBI Data bulk-in/-out clear stall", "CBI Status intr-in clear stall", "CBI Reset", "CBI bulk-in clear stall", "CBI bulk-out clear stall", NULL }; #endif /* If device cannot return valid inquiry data, fake it */ Static uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = { 0, /*removable*/ 0x80, SCSI_REV_2, SCSI_REV_2, /*additional_length*/ 31, 0, 0, 0 }; /* USB device probe/attach/detach functions */ USB_DECLARE_DRIVER(umass); Static int umass_match_proto (struct umass_softc *sc, usbd_interface_handle iface, usbd_device_handle udev); /* quirk functions */ Static void umass_init_shuttle (struct umass_softc *sc); /* generic transfer functions */ Static usbd_status umass_setup_transfer (struct umass_softc *sc, usbd_pipe_handle pipe, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); Static usbd_status umass_setup_ctrl_transfer (struct umass_softc *sc, usbd_device_handle udev, usb_device_request_t *req, void *buffer, int buflen, int flags, usbd_xfer_handle xfer); Static void umass_clear_endpoint_stall (struct umass_softc *sc, u_int8_t endpt, usbd_pipe_handle pipe, int state, usbd_xfer_handle xfer); Static void umass_reset (struct umass_softc *sc, transfer_cb_f cb, void *priv); /* Bulk-Only related functions */ Static void umass_bbb_reset (struct umass_softc *sc, int status); Static void umass_bbb_transfer (struct umass_softc *sc, int lun, void *cmd, int cmdlen, void *data, int datalen, int dir, u_int timeout, transfer_cb_f cb, void *priv); Static void umass_bbb_state (usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err); Static int umass_bbb_get_max_lun (struct umass_softc *sc); /* CBI related functions */ Static int umass_cbi_adsc (struct umass_softc *sc, char *buffer, int buflen, usbd_xfer_handle xfer); Static void umass_cbi_reset (struct umass_softc *sc, int status); Static void umass_cbi_transfer (struct umass_softc *sc, int lun, void *cmd, int cmdlen, void *data, int datalen, int dir, u_int timeout, transfer_cb_f cb, void *priv); Static void umass_cbi_state (usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err); /* CAM related functions */ Static void umass_cam_action (struct cam_sim *sim, union ccb *ccb); Static void umass_cam_poll (struct cam_sim *sim); Static void umass_cam_cb (struct umass_softc *sc, void *priv, int residue, int status); Static void umass_cam_sense_cb (struct umass_softc *sc, void *priv, int residue, int status); Static void umass_cam_quirk_cb (struct umass_softc *sc, void *priv, int residue, int status); Static void umass_cam_rescan_callback (struct cam_periph *periph,union ccb *ccb); Static void umass_cam_rescan (void *addr); Static int umass_cam_attach_sim (struct umass_softc *sc); Static int umass_cam_attach (struct umass_softc *sc); Static int umass_cam_detach_sim (struct umass_softc *sc); /* SCSI specific functions */ Static int umass_scsi_transform (struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen); /* UFI specific functions */ #define UFI_COMMAND_LENGTH 12 /* UFI commands are always 12 bytes */ Static int umass_ufi_transform (struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen); /* ATAPI (8070i) specific functions */ #define ATAPI_COMMAND_LENGTH 12 /* ATAPI commands are always 12 bytes */ Static int umass_atapi_transform (struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen); /* RBC specific functions */ Static int umass_rbc_transform (struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen); #ifdef USB_DEBUG /* General debugging functions */ Static void umass_bbb_dump_cbw (struct umass_softc *sc, umass_bbb_cbw_t *cbw); Static void umass_bbb_dump_csw (struct umass_softc *sc, umass_bbb_csw_t *csw); Static void umass_cbi_dump_cmd (struct umass_softc *sc, void *cmd, int cmdlen); Static void umass_dump_buffer (struct umass_softc *sc, u_int8_t *buffer, int buflen, int printlen); #endif #if defined(__FreeBSD__) MODULE_DEPEND(umass, cam, 1,1,1); #endif /* * USB device probe/attach/detach */ /* * Match the device we are seeing with the devices supported. Fill in the * description in the softc accordingly. This function is called from both * probe and attach. */ Static int umass_match_proto(struct umass_softc *sc, usbd_interface_handle iface, usbd_device_handle udev) { usb_device_descriptor_t *dd; usb_interface_descriptor_t *id; int i; int found = 0; sc->sc_udev = udev; sc->proto = 0; sc->quirks = 0; dd = usbd_get_device_descriptor(udev); /* An entry specifically for Y-E Data devices as they don't fit in the * device description table. */ if (UGETW(dd->idVendor) == USB_VENDOR_YEDATA && UGETW(dd->idProduct) == USB_PRODUCT_YEDATA_FLASHBUSTERU) { /* Revisions < 1.28 do not handle the interrupt endpoint * very well. */ if (UGETW(dd->bcdDevice) < 0x128) { sc->proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI; } else { sc->proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI_I; } /* * Revisions < 1.28 do not have the TEST UNIT READY command * Revisions == 1.28 have a broken TEST UNIT READY */ if (UGETW(dd->bcdDevice) <= 0x128) sc->quirks |= NO_TEST_UNIT_READY; sc->quirks |= RS_NO_CLEAR_UA | FLOPPY_SPEED; return(UMATCH_VENDOR_PRODUCT); } /* Check the list of supported devices for a match. While looking, * check for wildcarded and fully matched. First match wins. */ for (i = 0; umass_devdescrs[i].vid != VID_EOT && !found; i++) { if (umass_devdescrs[i].vid == VID_WILDCARD && umass_devdescrs[i].pid == PID_WILDCARD && umass_devdescrs[i].rid == RID_WILDCARD) { printf("umass: ignoring invalid wildcard quirk\n"); continue; } if ((umass_devdescrs[i].vid == UGETW(dd->idVendor) || umass_devdescrs[i].vid == VID_WILDCARD) && (umass_devdescrs[i].pid == UGETW(dd->idProduct) || umass_devdescrs[i].pid == PID_WILDCARD)) { if (umass_devdescrs[i].rid == RID_WILDCARD) { sc->proto = umass_devdescrs[i].proto; sc->quirks = umass_devdescrs[i].quirks; return (UMATCH_VENDOR_PRODUCT); } else if (umass_devdescrs[i].rid == UGETW(dd->bcdDevice)) { sc->proto = umass_devdescrs[i].proto; sc->quirks = umass_devdescrs[i].quirks; return (UMATCH_VENDOR_PRODUCT_REV); } /* else RID does not match */ } } /* Check for a standards compliant device */ id = usbd_get_interface_descriptor(iface); if (id == NULL || id->bInterfaceClass != UICLASS_MASS) return(UMATCH_NONE); switch (id->bInterfaceSubClass) { case UISUBCLASS_SCSI: sc->proto |= UMASS_PROTO_SCSI; break; case UISUBCLASS_UFI: sc->proto |= UMASS_PROTO_UFI; break; case UISUBCLASS_RBC: sc->proto |= UMASS_PROTO_RBC; break; case UISUBCLASS_SFF8020I: case UISUBCLASS_SFF8070I: sc->proto |= UMASS_PROTO_ATAPI; break; default: DPRINTF(UDMASS_GEN, ("%s: Unsupported command protocol %d\n", USBDEVNAME(sc->sc_dev), id->bInterfaceSubClass)); return(UMATCH_NONE); } switch (id->bInterfaceProtocol) { case UIPROTO_MASS_CBI: sc->proto |= UMASS_PROTO_CBI; break; case UIPROTO_MASS_CBI_I: sc->proto |= UMASS_PROTO_CBI_I; break; case UIPROTO_MASS_BBB_OLD: case UIPROTO_MASS_BBB: sc->proto |= UMASS_PROTO_BBB; break; default: DPRINTF(UDMASS_GEN, ("%s: Unsupported wire protocol %d\n", USBDEVNAME(sc->sc_dev), id->bInterfaceProtocol)); return(UMATCH_NONE); } return(UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO); } USB_MATCH(umass) { USB_MATCH_START(umass, uaa); struct umass_softc *sc = device_get_softc(self); USB_MATCH_SETUP; if (uaa->iface == NULL) return(UMATCH_NONE); return(umass_match_proto(sc, uaa->iface, uaa->device)); } USB_ATTACH(umass) { USB_ATTACH_START(umass, sc, uaa); usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; char devinfo[1024]; int i; int err; /* * the softc struct is bzero-ed in device_set_driver. We can safely * call umass_detach without specifically initialising the struct. */ usbd_devinfo(uaa->device, 0, devinfo); USB_ATTACH_SETUP; sc->iface = uaa->iface; sc->ifaceno = uaa->ifaceno; usb_callout_init(sc->cam_scsi_rescan_ch); /* initialise the proto and drive values in the umass_softc (again) */ (void) umass_match_proto(sc, sc->iface, uaa->device); id = usbd_get_interface_descriptor(sc->iface); #ifdef USB_DEBUG printf("%s: ", USBDEVNAME(sc->sc_dev)); switch (sc->proto&UMASS_PROTO_COMMAND) { case UMASS_PROTO_SCSI: printf("SCSI"); break; case UMASS_PROTO_ATAPI: printf("8070i (ATAPI)"); break; case UMASS_PROTO_UFI: printf("UFI"); break; case UMASS_PROTO_RBC: printf("RBC"); break; default: printf("(unknown 0x%02x)", sc->proto&UMASS_PROTO_COMMAND); break; } printf(" over "); switch (sc->proto&UMASS_PROTO_WIRE) { case UMASS_PROTO_BBB: printf("Bulk-Only"); break; case UMASS_PROTO_CBI: /* uses Comand/Bulk pipes */ printf("CBI"); break; case UMASS_PROTO_CBI_I: /* uses Comand/Bulk/Interrupt pipes */ printf("CBI with CCI"); #ifndef CBI_I printf(" (using CBI)"); #endif break; default: printf("(unknown 0x%02x)", sc->proto&UMASS_PROTO_WIRE); } printf("; quirks = 0x%04x\n", sc->quirks); #endif #ifndef CBI_I if (sc->proto & UMASS_PROTO_CBI_I) { /* See beginning of file for comment on the use of CBI with CCI */ sc->proto = (sc->proto & ~UMASS_PROTO_CBI_I) | UMASS_PROTO_CBI; } #endif if (sc->quirks & ALT_IFACE_1) { err = usbd_set_interface(uaa->iface, 1); if (err) { DPRINTF(UDMASS_USB, ("%s: could not switch to " "Alt Interface %d\n", USBDEVNAME(sc->sc_dev), 1)); umass_detach(self); USB_ATTACH_ERROR_RETURN; } } /* * In addition to the Control endpoint the following endpoints * are required: * a) bulk-in endpoint. * b) bulk-out endpoint. * and for Control/Bulk/Interrupt with CCI (CBI_I) * c) intr-in * * The endpoint addresses are not fixed, so we have to read them * from the device descriptors of the current interface. */ for (i = 0 ; i < id->bNumEndpoints ; i++) { ed = usbd_interface2endpoint_descriptor(sc->iface, i); if (!ed) { printf("%s: could not read endpoint descriptor\n", USBDEVNAME(sc->sc_dev)); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { sc->bulkin = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { sc->bulkout = ed->bEndpointAddress; } else if (sc->proto & UMASS_PROTO_CBI_I && UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->intrin = ed->bEndpointAddress; #ifdef USB_DEBUG if (UGETW(ed->wMaxPacketSize) > 2) { DPRINTF(UDMASS_CBI, ("%s: intr size is %d\n", USBDEVNAME(sc->sc_dev), UGETW(ed->wMaxPacketSize))); } #endif } } /* check whether we found all the endpoints we need */ if (!sc->bulkin || !sc->bulkout || (sc->proto & UMASS_PROTO_CBI_I && !sc->intrin) ) { DPRINTF(UDMASS_USB, ("%s: endpoint not found %d/%d/%d\n", USBDEVNAME(sc->sc_dev), sc->bulkin, sc->bulkout, sc->intrin)); umass_detach(self); USB_ATTACH_ERROR_RETURN; } /* Open the bulk-in and -out pipe */ err = usbd_open_pipe(sc->iface, sc->bulkout, USBD_EXCLUSIVE_USE, &sc->bulkout_pipe); if (err) { DPRINTF(UDMASS_USB, ("%s: cannot open %d-out pipe (bulk)\n", USBDEVNAME(sc->sc_dev), sc->bulkout)); umass_detach(self); USB_ATTACH_ERROR_RETURN; } err = usbd_open_pipe(sc->iface, sc->bulkin, USBD_EXCLUSIVE_USE, &sc->bulkin_pipe); if (err) { DPRINTF(UDMASS_USB, ("%s: could not open %d-in pipe (bulk)\n", USBDEVNAME(sc->sc_dev), sc->bulkin)); umass_detach(self); USB_ATTACH_ERROR_RETURN; } /* Open the intr-in pipe if the protocol is CBI with CCI. * Note: early versions of the Zip drive do have an interrupt pipe, but * this pipe is unused. * * We do not open the interrupt pipe as an interrupt pipe, but as a * normal bulk endpoint. We send an IN transfer down the wire at the * appropriate time, because we know exactly when to expect data on * that endpoint. This saves bandwidth, but more important, makes the * code for handling the data on that endpoint simpler. No data * arriving concurrently. */ if (sc->proto & UMASS_PROTO_CBI_I) { err = usbd_open_pipe(sc->iface, sc->intrin, USBD_EXCLUSIVE_USE, &sc->intrin_pipe); if (err) { DPRINTF(UDMASS_USB, ("%s: couldn't open %d-in (intr)\n", USBDEVNAME(sc->sc_dev), sc->intrin)); umass_detach(self); USB_ATTACH_ERROR_RETURN; } } /* initialisation of generic part */ sc->transfer_state = TSTATE_ATTACH; /* request a sufficient number of xfer handles */ for (i = 0; i < XFER_NR; i++) { sc->transfer_xfer[i] = usbd_alloc_xfer(uaa->device); if (!sc->transfer_xfer[i]) { DPRINTF(UDMASS_USB, ("%s: Out of memory\n", USBDEVNAME(sc->sc_dev))); umass_detach(self); USB_ATTACH_ERROR_RETURN; } } /* Initialise the wire protocol specific methods */ if (sc->proto & UMASS_PROTO_BBB) { sc->reset = umass_bbb_reset; sc->transfer = umass_bbb_transfer; sc->state = umass_bbb_state; } else if (sc->proto & (UMASS_PROTO_CBI|UMASS_PROTO_CBI_I)) { sc->reset = umass_cbi_reset; sc->transfer = umass_cbi_transfer; sc->state = umass_cbi_state; #ifdef USB_DEBUG } else { panic("%s:%d: Unknown proto 0x%02x", __FILE__, __LINE__, sc->proto); #endif } if (sc->proto & UMASS_PROTO_SCSI) sc->transform = umass_scsi_transform; else if (sc->proto & UMASS_PROTO_UFI) sc->transform = umass_ufi_transform; else if (sc->proto & UMASS_PROTO_ATAPI) sc->transform = umass_atapi_transform; else if (sc->proto & UMASS_PROTO_RBC) sc->transform = umass_rbc_transform; #ifdef USB_DEBUG else panic("No transformation defined for command proto 0x%02x", sc->proto & UMASS_PROTO_COMMAND); #endif /* From here onwards the device can be used. */ if (sc->quirks & SHUTTLE_INIT) umass_init_shuttle(sc); /* Get the maximum LUN supported by the device. */ if (((sc->proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) && !(sc->quirks & NO_GETMAXLUN)) sc->maxlun = umass_bbb_get_max_lun(sc); else sc->maxlun = 0; if ((sc->proto & UMASS_PROTO_SCSI) || (sc->proto & UMASS_PROTO_ATAPI) || (sc->proto & UMASS_PROTO_UFI) || (sc->proto & UMASS_PROTO_RBC)) { /* Prepare the SCSI command block */ sc->cam_scsi_sense.opcode = REQUEST_SENSE; sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY; /* register the SIM */ err = umass_cam_attach_sim(sc); if (err) { umass_detach(self); USB_ATTACH_ERROR_RETURN; } /* scan the new sim */ err = umass_cam_attach(sc); if (err) { umass_cam_detach_sim(sc); umass_detach(self); USB_ATTACH_ERROR_RETURN; } } else { panic("%s:%d: Unknown proto 0x%02x", __FILE__, __LINE__, sc->proto); } sc->transfer_state = TSTATE_IDLE; DPRINTF(UDMASS_GEN, ("%s: Attach finished\n", USBDEVNAME(sc->sc_dev))); USB_ATTACH_SUCCESS_RETURN; } USB_DETACH(umass) { USB_DETACH_START(umass, sc); int err = 0; int i; DPRINTF(UDMASS_USB, ("%s: detached\n", USBDEVNAME(sc->sc_dev))); sc->flags |= UMASS_FLAGS_GONE; /* abort all the pipes in case there are transfers active. */ usbd_abort_default_pipe(sc->sc_udev); if (sc->bulkout_pipe) usbd_abort_pipe(sc->bulkout_pipe); if (sc->bulkin_pipe) usbd_abort_pipe(sc->bulkin_pipe); if (sc->intrin_pipe) usbd_abort_pipe(sc->intrin_pipe); usb_uncallout_drain(sc->cam_scsi_rescan_ch, umass_cam_rescan, sc); if ((sc->proto & UMASS_PROTO_SCSI) || (sc->proto & UMASS_PROTO_ATAPI) || (sc->proto & UMASS_PROTO_UFI) || (sc->proto & UMASS_PROTO_RBC)) /* detach the SCSI host controller (SIM) */ err = umass_cam_detach_sim(sc); for (i = 0; i < XFER_NR; i++) if (sc->transfer_xfer[i]) usbd_free_xfer(sc->transfer_xfer[i]); /* remove all the pipes */ if (sc->bulkout_pipe) usbd_close_pipe(sc->bulkout_pipe); if (sc->bulkin_pipe) usbd_close_pipe(sc->bulkin_pipe); if (sc->intrin_pipe) usbd_close_pipe(sc->intrin_pipe); return(err); } Static void umass_init_shuttle(struct umass_softc *sc) { usb_device_request_t req; u_char status[2]; /* The Linux driver does this, but no one can tell us what the * command does. */ req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = 1; /* XXX unknown command */ USETW(req.wValue, 0); USETW(req.wIndex, sc->ifaceno); USETW(req.wLength, sizeof status); (void) usbd_do_request(sc->sc_udev, &req, &status); DPRINTF(UDMASS_GEN, ("%s: Shuttle init returned 0x%02x%02x\n", USBDEVNAME(sc->sc_dev), status[0], status[1])); } /* * Generic functions to handle transfers */ Static usbd_status umass_setup_transfer(struct umass_softc *sc, usbd_pipe_handle pipe, void *buffer, int buflen, int flags, usbd_xfer_handle xfer) { usbd_status err; /* Initialise a USB transfer and then schedule it */ (void) usbd_setup_xfer(xfer, pipe, (void *) sc, buffer, buflen, flags, sc->timeout, sc->state); err = usbd_transfer(xfer); if (err && err != USBD_IN_PROGRESS) { DPRINTF(UDMASS_BBB, ("%s: failed to setup transfer, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err))); return(err); } return (USBD_NORMAL_COMPLETION); } Static usbd_status umass_setup_ctrl_transfer(struct umass_softc *sc, usbd_device_handle udev, usb_device_request_t *req, void *buffer, int buflen, int flags, usbd_xfer_handle xfer) { usbd_status err; /* Initialise a USB control transfer and then schedule it */ (void) usbd_setup_default_xfer(xfer, udev, (void *) sc, sc->timeout, req, buffer, buflen, flags, sc->state); err = usbd_transfer(xfer); if (err && err != USBD_IN_PROGRESS) { DPRINTF(UDMASS_BBB, ("%s: failed to setup ctrl transfer, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err))); /* do not reset, as this would make us loop */ return(err); } return (USBD_NORMAL_COMPLETION); } Static void umass_clear_endpoint_stall(struct umass_softc *sc, u_int8_t endpt, usbd_pipe_handle pipe, int state, usbd_xfer_handle xfer) { usbd_device_handle udev; DPRINTF(UDMASS_BBB, ("%s: Clear endpoint 0x%02x stall\n", USBDEVNAME(sc->sc_dev), endpt)); usbd_interface2device_handle(sc->iface, &udev); sc->transfer_state = state; usbd_clear_endpoint_toggle(pipe); sc->request.bmRequestType = UT_WRITE_ENDPOINT; sc->request.bRequest = UR_CLEAR_FEATURE; USETW(sc->request.wValue, UF_ENDPOINT_HALT); USETW(sc->request.wIndex, endpt); USETW(sc->request.wLength, 0); umass_setup_ctrl_transfer(sc, udev, &sc->request, NULL, 0, 0, xfer); } Static void umass_reset(struct umass_softc *sc, transfer_cb_f cb, void *priv) { sc->transfer_cb = cb; sc->transfer_priv = priv; /* The reset is a forced reset, so no error (yet) */ sc->reset(sc, STATUS_CMD_OK); } /* * Bulk protocol specific functions */ Static void umass_bbb_reset(struct umass_softc *sc, int status) { usbd_device_handle udev; KASSERT(sc->proto & UMASS_PROTO_BBB, ("%s: umass_bbb_reset: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) * * For Reset Recovery the host shall issue in the following order: * a) a Bulk-Only Mass Storage Reset * b) a Clear Feature HALT to the Bulk-In endpoint * c) a Clear Feature HALT to the Bulk-Out endpoint * * This is done in 3 steps, states: * TSTATE_BBB_RESET1 * TSTATE_BBB_RESET2 * TSTATE_BBB_RESET3 * * If the reset doesn't succeed, the device should be port reset. */ DPRINTF(UDMASS_BBB, ("%s: Bulk Reset\n", USBDEVNAME(sc->sc_dev))); sc->transfer_state = TSTATE_BBB_RESET1; sc->transfer_status = status; usbd_interface2device_handle(sc->iface, &udev); /* reset is a class specific interface write */ sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE; sc->request.bRequest = UR_BBB_RESET; USETW(sc->request.wValue, 0); USETW(sc->request.wIndex, sc->ifaceno); USETW(sc->request.wLength, 0); umass_setup_ctrl_transfer(sc, udev, &sc->request, NULL, 0, 0, sc->transfer_xfer[XFER_BBB_RESET1]); } Static void umass_bbb_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen, void *data, int datalen, int dir, u_int timeout, transfer_cb_f cb, void *priv) { KASSERT(sc->proto & UMASS_PROTO_BBB, ("%s: umass_bbb_transfer: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* Be a little generous. */ sc->timeout = timeout + UMASS_TIMEOUT; /* * Do a Bulk-Only transfer with cmdlen bytes from cmd, possibly * a data phase of datalen bytes from/to the device and finally a * csw read phase. * If the data direction was inbound a maximum of datalen bytes * is stored in the buffer pointed to by data. * * umass_bbb_transfer initialises the transfer and lets the state * machine in umass_bbb_state handle the completion. It uses the * following states: * TSTATE_BBB_COMMAND * -> TSTATE_BBB_DATA * -> TSTATE_BBB_STATUS * -> TSTATE_BBB_STATUS2 * -> TSTATE_BBB_IDLE * * An error in any of those states will invoke * umass_bbb_reset. */ /* check the given arguments */ KASSERT(datalen == 0 || data != NULL, ("%s: datalen > 0, but no buffer",USBDEVNAME(sc->sc_dev))); KASSERT(cmdlen <= CBWCDBLENGTH, ("%s: cmdlen exceeds CDB length in CBW (%d > %d)", USBDEVNAME(sc->sc_dev), cmdlen, CBWCDBLENGTH)); KASSERT(dir == DIR_NONE || datalen > 0, ("%s: datalen == 0 while direction is not NONE\n", USBDEVNAME(sc->sc_dev))); KASSERT(datalen == 0 || dir != DIR_NONE, ("%s: direction is NONE while datalen is not zero\n", USBDEVNAME(sc->sc_dev))); KASSERT(sizeof(umass_bbb_cbw_t) == UMASS_BBB_CBW_SIZE, ("%s: CBW struct does not have the right size (%ld vs. %d)\n", USBDEVNAME(sc->sc_dev), (long)sizeof(umass_bbb_cbw_t), UMASS_BBB_CBW_SIZE)); KASSERT(sizeof(umass_bbb_csw_t) == UMASS_BBB_CSW_SIZE, ("%s: CSW struct does not have the right size (%ld vs. %d)\n", USBDEVNAME(sc->sc_dev), (long)sizeof(umass_bbb_csw_t), UMASS_BBB_CSW_SIZE)); /* * Determine the direction of the data transfer and the length. * * dCBWDataTransferLength (datalen) : * This field indicates the number of bytes of data that the host * intends to transfer on the IN or OUT Bulk endpoint(as indicated by * the Direction bit) during the execution of this command. If this * field is set to 0, the device will expect that no data will be * transferred IN or OUT during this command, regardless of the value * of the Direction bit defined in dCBWFlags. * * dCBWFlags (dir) : * The bits of the Flags field are defined as follows: * Bits 0-6 reserved * Bit 7 Direction - this bit shall be ignored if the * dCBWDataTransferLength field is zero. * 0 = data Out from host to device * 1 = data In from device to host */ /* Fill in the Command Block Wrapper * We fill in all the fields, so there is no need to bzero it first. */ USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); /* We don't care about the initial value, as long as the values are unique */ USETDW(sc->cbw.dCBWTag, UGETDW(sc->cbw.dCBWTag) + 1); USETDW(sc->cbw.dCBWDataTransferLength, datalen); /* DIR_NONE is treated as DIR_OUT (0x00) */ sc->cbw.bCBWFlags = (dir == DIR_IN? CBWFLAGS_IN:CBWFLAGS_OUT); sc->cbw.bCBWLUN = lun; sc->cbw.bCDBLength = cmdlen; bcopy(cmd, sc->cbw.CBWCDB, cmdlen); DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw)); /* store the details for the data transfer phase */ sc->transfer_dir = dir; sc->transfer_data = data; sc->transfer_datalen = datalen; sc->transfer_actlen = 0; sc->transfer_cb = cb; sc->transfer_priv = priv; sc->transfer_status = STATUS_CMD_OK; /* move from idle to the command state */ sc->transfer_state = TSTATE_BBB_COMMAND; /* Send the CBW from host to device via bulk-out endpoint. */ if (umass_setup_transfer(sc, sc->bulkout_pipe, &sc->cbw, UMASS_BBB_CBW_SIZE, 0, sc->transfer_xfer[XFER_BBB_CBW])) { umass_bbb_reset(sc, STATUS_WIRE_FAILED); } } Static void umass_bbb_state(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err) { struct umass_softc *sc = (struct umass_softc *) priv; usbd_xfer_handle next_xfer; KASSERT(sc->proto & UMASS_PROTO_BBB, ("%s: umass_bbb_state: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* * State handling for BBB transfers. * * The subroutine is rather long. It steps through the states given in * Annex A of the Bulk-Only specification. * Each state first does the error handling of the previous transfer * and then prepares the next transfer. * Each transfer is done asynchronously so after the request/transfer * has been submitted you will find a 'return;'. */ DPRINTF(UDMASS_BBB, ("%s: Handling BBB state %d (%s), xfer=%p, %s\n", USBDEVNAME(sc->sc_dev), sc->transfer_state, states[sc->transfer_state], xfer, usbd_errstr(err))); /* Give up if the device has detached. */ if (sc->flags & UMASS_FLAGS_GONE) { sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, STATUS_CMD_FAILED); return; } switch (sc->transfer_state) { /***** Bulk Transfer *****/ case TSTATE_BBB_COMMAND: /* Command transport phase, error handling */ if (err) { DPRINTF(UDMASS_BBB, ("%s: failed to send CBW\n", USBDEVNAME(sc->sc_dev))); /* If the device detects that the CBW is invalid, then * the device may STALL both bulk endpoints and require * a Bulk-Reset */ umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } /* Data transport phase, setup transfer */ sc->transfer_state = TSTATE_BBB_DATA; if (sc->transfer_dir == DIR_IN) { if (umass_setup_transfer(sc, sc->bulkin_pipe, sc->transfer_data, sc->transfer_datalen, USBD_SHORT_XFER_OK, sc->transfer_xfer[XFER_BBB_DATA])) umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } else if (sc->transfer_dir == DIR_OUT) { if (umass_setup_transfer(sc, sc->bulkout_pipe, sc->transfer_data, sc->transfer_datalen, 0, /* fixed length transfer */ sc->transfer_xfer[XFER_BBB_DATA])) umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } else { DPRINTF(UDMASS_BBB, ("%s: no data phase\n", USBDEVNAME(sc->sc_dev))); } /* FALLTHROUGH if no data phase, err == 0 */ case TSTATE_BBB_DATA: /* Command transport phase, error handling (ignored if no data * phase (fallthrough from previous state)) */ if (sc->transfer_dir != DIR_NONE) { /* retrieve the length of the transfer that was done */ usbd_get_xfer_status(xfer, NULL, NULL, &sc->transfer_actlen, NULL); if (err) { DPRINTF(UDMASS_BBB, ("%s: Data-%s %db failed, " "%s\n", USBDEVNAME(sc->sc_dev), (sc->transfer_dir == DIR_IN?"in":"out"), sc->transfer_datalen,usbd_errstr(err))); if (err == USBD_STALLED) { umass_clear_endpoint_stall(sc, (sc->transfer_dir == DIR_IN? sc->bulkin:sc->bulkout), (sc->transfer_dir == DIR_IN? sc->bulkin_pipe:sc->bulkout_pipe), TSTATE_BBB_DCLEAR, sc->transfer_xfer[XFER_BBB_DCLEAR]); return; } else { /* Unless the error is a pipe stall the * error is fatal. */ umass_bbb_reset(sc,STATUS_WIRE_FAILED); return; } } } DIF(UDMASS_BBB, if (sc->transfer_dir == DIR_IN) umass_dump_buffer(sc, sc->transfer_data, sc->transfer_datalen, 48)); /* FALLTHROUGH, err == 0 (no data phase or successfull) */ case TSTATE_BBB_DCLEAR: /* stall clear after data phase */ case TSTATE_BBB_SCLEAR: /* stall clear after status phase */ /* Reading of CSW after bulk stall condition in data phase * (TSTATE_BBB_DATA2) or bulk-in stall condition after * reading CSW (TSTATE_BBB_SCLEAR). * In the case of no data phase or successfull data phase, * err == 0 and the following if block is passed. */ if (err) { /* should not occur */ /* try the transfer below, even if clear stall failed */ DPRINTF(UDMASS_BBB, ("%s: bulk-%s stall clear failed" ", %s\n", USBDEVNAME(sc->sc_dev), (sc->transfer_dir == DIR_IN? "in":"out"), usbd_errstr(err))); umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } /* Status transport phase, setup transfer */ if (sc->transfer_state == TSTATE_BBB_COMMAND || sc->transfer_state == TSTATE_BBB_DATA || sc->transfer_state == TSTATE_BBB_DCLEAR) { /* After no data phase, successfull data phase and * after clearing bulk-in/-out stall condition */ sc->transfer_state = TSTATE_BBB_STATUS1; next_xfer = sc->transfer_xfer[XFER_BBB_CSW1]; } else { /* After first attempt of fetching CSW */ sc->transfer_state = TSTATE_BBB_STATUS2; next_xfer = sc->transfer_xfer[XFER_BBB_CSW2]; } /* Read the Command Status Wrapper via bulk-in endpoint. */ if (umass_setup_transfer(sc, sc->bulkin_pipe, &sc->csw, UMASS_BBB_CSW_SIZE, 0, next_xfer)) { umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } return; case TSTATE_BBB_STATUS1: /* first attempt */ case TSTATE_BBB_STATUS2: /* second attempt */ /* Status transfer, error handling */ if (err) { DPRINTF(UDMASS_BBB, ("%s: Failed to read CSW, %s%s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err), (sc->transfer_state == TSTATE_BBB_STATUS1? ", retrying":""))); /* If this was the first attempt at fetching the CSW * retry it, otherwise fail. */ if (sc->transfer_state == TSTATE_BBB_STATUS1) { umass_clear_endpoint_stall(sc, sc->bulkin, sc->bulkin_pipe, TSTATE_BBB_SCLEAR, sc->transfer_xfer[XFER_BBB_SCLEAR]); return; } else { umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } } DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw)); /* Translate weird command-status signatures. */ if (sc->quirks & WRONG_CSWSIG) { u_int32_t dCSWSignature = UGETDW(sc->csw.dCSWSignature); if (dCSWSignature == CSWSIGNATURE_OLYMPUS_C1 || dCSWSignature == CSWSIGNATURE_IMAGINATION_DBX1) USETDW(sc->csw.dCSWSignature, CSWSIGNATURE); } int Residue; Residue = UGETDW(sc->csw.dCSWDataResidue); if (Residue == 0 && sc->transfer_datalen - sc->transfer_actlen != 0) Residue = sc->transfer_datalen - sc->transfer_actlen; /* Check CSW and handle any error */ if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) { /* Invalid CSW: Wrong signature or wrong tag might * indicate that the device is confused -> reset it. */ printf("%s: Invalid CSW: sig 0x%08x should be 0x%08x\n", USBDEVNAME(sc->sc_dev), UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE); umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) { printf("%s: Invalid CSW: tag %d should be %d\n", USBDEVNAME(sc->sc_dev), UGETDW(sc->csw.dCSWTag), UGETDW(sc->cbw.dCBWTag)); umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; /* CSW is valid here */ } else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) { printf("%s: Invalid CSW: status %d > %d\n", USBDEVNAME(sc->sc_dev), sc->csw.bCSWStatus, CSWSTATUS_PHASE); umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) { printf("%s: Phase Error, residue = %d\n", USBDEVNAME(sc->sc_dev), Residue); umass_bbb_reset(sc, STATUS_WIRE_FAILED); return; } else if (sc->transfer_actlen > sc->transfer_datalen) { /* Buffer overrun! Don't let this go by unnoticed */ panic("%s: transferred %db instead of %db", USBDEVNAME(sc->sc_dev), sc->transfer_actlen, sc->transfer_datalen); } else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) { DPRINTF(UDMASS_BBB, ("%s: Command Failed, res = %d\n", USBDEVNAME(sc->sc_dev), Residue)); /* SCSI command failed but transfer was succesful */ sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, Residue, STATUS_CMD_FAILED); return; } else { /* success */ sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, Residue, STATUS_CMD_OK); return; } /***** Bulk Reset *****/ case TSTATE_BBB_RESET1: if (err) printf("%s: BBB reset failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); umass_clear_endpoint_stall(sc, sc->bulkin, sc->bulkin_pipe, TSTATE_BBB_RESET2, sc->transfer_xfer[XFER_BBB_RESET2]); return; case TSTATE_BBB_RESET2: if (err) /* should not occur */ printf("%s: BBB bulk-in clear stall failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ umass_clear_endpoint_stall(sc, sc->bulkout, sc->bulkout_pipe, TSTATE_BBB_RESET3, sc->transfer_xfer[XFER_BBB_RESET3]); return; case TSTATE_BBB_RESET3: if (err) /* should not occur */ printf("%s: BBB bulk-out clear stall failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ sc->transfer_state = TSTATE_IDLE; if (sc->transfer_priv) { sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, sc->transfer_status); } return; /***** Default *****/ default: panic("%s: Unknown state %d", USBDEVNAME(sc->sc_dev), sc->transfer_state); } } Static int umass_bbb_get_max_lun(struct umass_softc *sc) { usbd_device_handle udev; usb_device_request_t req; usbd_status err; usb_interface_descriptor_t *id; int maxlun = 0; u_int8_t buf = 0; usbd_interface2device_handle(sc->iface, &udev); id = usbd_get_interface_descriptor(sc->iface); /* The Get Max Lun command is a class-specific request. */ req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_BBB_GET_MAX_LUN; USETW(req.wValue, 0); USETW(req.wIndex, id->bInterfaceNumber); USETW(req.wLength, 1); err = usbd_do_request(udev, &req, &buf); switch (err) { case USBD_NORMAL_COMPLETION: maxlun = buf; DPRINTF(UDMASS_BBB, ("%s: Max Lun is %d\n", USBDEVNAME(sc->sc_dev), maxlun)); break; case USBD_STALLED: case USBD_SHORT_XFER: default: /* Device doesn't support Get Max Lun request. */ printf("%s: Get Max Lun not supported (%s)\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* XXX Should we port_reset the device? */ break; } return(maxlun); } /* * Command/Bulk/Interrupt (CBI) specific functions */ Static int umass_cbi_adsc(struct umass_softc *sc, char *buffer, int buflen, usbd_xfer_handle xfer) { usbd_device_handle udev; KASSERT(sc->proto & (UMASS_PROTO_CBI|UMASS_PROTO_CBI_I), ("%s: umass_cbi_adsc: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); usbd_interface2device_handle(sc->iface, &udev); sc->request.bmRequestType = UT_WRITE_CLASS_INTERFACE; sc->request.bRequest = UR_CBI_ADSC; USETW(sc->request.wValue, 0); USETW(sc->request.wIndex, sc->ifaceno); USETW(sc->request.wLength, buflen); return umass_setup_ctrl_transfer(sc, udev, &sc->request, buffer, buflen, 0, xfer); } Static void umass_cbi_reset(struct umass_softc *sc, int status) { int i; # define SEND_DIAGNOSTIC_CMDLEN 12 KASSERT(sc->proto & (UMASS_PROTO_CBI|UMASS_PROTO_CBI_I), ("%s: umass_cbi_reset: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* * Command Block Reset Protocol * * First send a reset request to the device. Then clear * any possibly stalled bulk endpoints. * * This is done in 3 steps, states: * TSTATE_CBI_RESET1 * TSTATE_CBI_RESET2 * TSTATE_CBI_RESET3 * * If the reset doesn't succeed, the device should be port reset. */ DPRINTF(UDMASS_CBI, ("%s: CBI Reset\n", USBDEVNAME(sc->sc_dev))); KASSERT(sizeof(sc->cbl) >= SEND_DIAGNOSTIC_CMDLEN, ("%s: CBL struct is too small (%ld < %d)\n", USBDEVNAME(sc->sc_dev), (long)sizeof(sc->cbl), SEND_DIAGNOSTIC_CMDLEN)); sc->transfer_state = TSTATE_CBI_RESET1; sc->transfer_status = status; /* The 0x1d code is the SEND DIAGNOSTIC command. To distinguish between * the two the last 10 bytes of the cbl is filled with 0xff (section * 2.2 of the CBI spec). */ sc->cbl[0] = 0x1d; /* Command Block Reset */ sc->cbl[1] = 0x04; for (i = 2; i < SEND_DIAGNOSTIC_CMDLEN; i++) sc->cbl[i] = 0xff; umass_cbi_adsc(sc, sc->cbl, SEND_DIAGNOSTIC_CMDLEN, sc->transfer_xfer[XFER_CBI_RESET1]); /* XXX if the command fails we should reset the port on the hub */ } Static void umass_cbi_transfer(struct umass_softc *sc, int lun, void *cmd, int cmdlen, void *data, int datalen, int dir, u_int timeout, transfer_cb_f cb, void *priv) { KASSERT(sc->proto & (UMASS_PROTO_CBI|UMASS_PROTO_CBI_I), ("%s: umass_cbi_transfer: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* Be a little generous. */ sc->timeout = timeout + UMASS_TIMEOUT; /* * Do a CBI transfer with cmdlen bytes from cmd, possibly * a data phase of datalen bytes from/to the device and finally a * csw read phase. * If the data direction was inbound a maximum of datalen bytes * is stored in the buffer pointed to by data. * * umass_cbi_transfer initialises the transfer and lets the state * machine in umass_cbi_state handle the completion. It uses the * following states: * TSTATE_CBI_COMMAND * -> XXX fill in * * An error in any of those states will invoke * umass_cbi_reset. */ /* check the given arguments */ KASSERT(datalen == 0 || data != NULL, ("%s: datalen > 0, but no buffer",USBDEVNAME(sc->sc_dev))); KASSERT(datalen == 0 || dir != DIR_NONE, ("%s: direction is NONE while datalen is not zero\n", USBDEVNAME(sc->sc_dev))); /* store the details for the data transfer phase */ sc->transfer_dir = dir; sc->transfer_data = data; sc->transfer_datalen = datalen; sc->transfer_actlen = 0; sc->transfer_cb = cb; sc->transfer_priv = priv; sc->transfer_status = STATUS_CMD_OK; /* move from idle to the command state */ sc->transfer_state = TSTATE_CBI_COMMAND; DIF(UDMASS_CBI, umass_cbi_dump_cmd(sc, cmd, cmdlen)); /* Send the Command Block from host to device via control endpoint. */ if (umass_cbi_adsc(sc, cmd, cmdlen, sc->transfer_xfer[XFER_CBI_CB])) umass_cbi_reset(sc, STATUS_WIRE_FAILED); } Static void umass_cbi_state(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status err) { struct umass_softc *sc = (struct umass_softc *) priv; KASSERT(sc->proto & (UMASS_PROTO_CBI|UMASS_PROTO_CBI_I), ("%s: umass_cbi_state: wrong sc->proto 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->proto)); /* * State handling for CBI transfers. */ DPRINTF(UDMASS_CBI, ("%s: Handling CBI state %d (%s), xfer=%p, %s\n", USBDEVNAME(sc->sc_dev), sc->transfer_state, states[sc->transfer_state], xfer, usbd_errstr(err))); /* Give up if the device has detached. */ if (sc->flags & UMASS_FLAGS_GONE) { sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, STATUS_CMD_FAILED); return; } switch (sc->transfer_state) { /***** CBI Transfer *****/ case TSTATE_CBI_COMMAND: if (err == USBD_STALLED) { DPRINTF(UDMASS_CBI, ("%s: Command Transport failed\n", USBDEVNAME(sc->sc_dev))); /* Status transport by control pipe (section 2.3.2.1). * The command contained in the command block failed. * * The control pipe has already been unstalled by the * USB stack. * Section 2.4.3.1.1 states that the bulk in endpoints * should not be stalled at this point. */ sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, STATUS_CMD_FAILED); return; } else if (err) { DPRINTF(UDMASS_CBI, ("%s: failed to send ADSC\n", USBDEVNAME(sc->sc_dev))); umass_cbi_reset(sc, STATUS_WIRE_FAILED); return; } sc->transfer_state = TSTATE_CBI_DATA; if (sc->transfer_dir == DIR_IN) { if (umass_setup_transfer(sc, sc->bulkin_pipe, sc->transfer_data, sc->transfer_datalen, USBD_SHORT_XFER_OK, sc->transfer_xfer[XFER_CBI_DATA])) umass_cbi_reset(sc, STATUS_WIRE_FAILED); } else if (sc->transfer_dir == DIR_OUT) { if (umass_setup_transfer(sc, sc->bulkout_pipe, sc->transfer_data, sc->transfer_datalen, 0, /* fixed length transfer */ sc->transfer_xfer[XFER_CBI_DATA])) umass_cbi_reset(sc, STATUS_WIRE_FAILED); } else if (sc->proto & UMASS_PROTO_CBI_I) { DPRINTF(UDMASS_CBI, ("%s: no data phase\n", USBDEVNAME(sc->sc_dev))); sc->transfer_state = TSTATE_CBI_STATUS; if (umass_setup_transfer(sc, sc->intrin_pipe, &sc->sbl, sizeof(sc->sbl), 0, /* fixed length transfer */ sc->transfer_xfer[XFER_CBI_STATUS])){ umass_cbi_reset(sc, STATUS_WIRE_FAILED); } } else { DPRINTF(UDMASS_CBI, ("%s: no data phase\n", USBDEVNAME(sc->sc_dev))); /* No command completion interrupt. Request * sense data. */ sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, 0, STATUS_CMD_UNKNOWN); } return; case TSTATE_CBI_DATA: /* retrieve the length of the transfer that was done */ usbd_get_xfer_status(xfer,NULL,NULL,&sc->transfer_actlen,NULL); if (err) { DPRINTF(UDMASS_CBI, ("%s: Data-%s %db failed, " "%s\n", USBDEVNAME(sc->sc_dev), (sc->transfer_dir == DIR_IN?"in":"out"), sc->transfer_datalen,usbd_errstr(err))); if (err == USBD_STALLED) { umass_clear_endpoint_stall(sc, sc->bulkin, sc->bulkin_pipe, TSTATE_CBI_DCLEAR, sc->transfer_xfer[XFER_CBI_DCLEAR]); } else { umass_cbi_reset(sc, STATUS_WIRE_FAILED); } return; } DIF(UDMASS_CBI, if (sc->transfer_dir == DIR_IN) umass_dump_buffer(sc, sc->transfer_data, sc->transfer_actlen, 48)); if (sc->proto & UMASS_PROTO_CBI_I) { sc->transfer_state = TSTATE_CBI_STATUS; if (umass_setup_transfer(sc, sc->intrin_pipe, &sc->sbl, sizeof(sc->sbl), 0, /* fixed length transfer */ sc->transfer_xfer[XFER_CBI_STATUS])){ umass_cbi_reset(sc, STATUS_WIRE_FAILED); } } else { /* No command completion interrupt. Request * sense to get status of command. */ sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen - sc->transfer_actlen, STATUS_CMD_UNKNOWN); } return; case TSTATE_CBI_STATUS: if (err) { DPRINTF(UDMASS_CBI, ("%s: Status Transport failed\n", USBDEVNAME(sc->sc_dev))); /* Status transport by interrupt pipe (section 2.3.2.2). */ if (err == USBD_STALLED) { umass_clear_endpoint_stall(sc, sc->intrin, sc->intrin_pipe, TSTATE_CBI_SCLEAR, sc->transfer_xfer[XFER_CBI_SCLEAR]); } else { umass_cbi_reset(sc, STATUS_WIRE_FAILED); } return; } /* Dissect the information in the buffer */ if (sc->proto & UMASS_PROTO_UFI) { int status; /* Section 3.4.3.1.3 specifies that the UFI command * protocol returns an ASC and ASCQ in the interrupt * data block. */ DPRINTF(UDMASS_CBI, ("%s: UFI CCI, ASC = 0x%02x, " "ASCQ = 0x%02x\n", USBDEVNAME(sc->sc_dev), sc->sbl.ufi.asc, sc->sbl.ufi.ascq)); if (sc->sbl.ufi.asc == 0 && sc->sbl.ufi.ascq == 0) status = STATUS_CMD_OK; else status = STATUS_CMD_FAILED; sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen - sc->transfer_actlen, status); } else { /* Command Interrupt Data Block */ DPRINTF(UDMASS_CBI, ("%s: type=0x%02x, value=0x%02x\n", USBDEVNAME(sc->sc_dev), sc->sbl.common.type, sc->sbl.common.value)); if (sc->sbl.common.type == IDB_TYPE_CCI) { int err; if ((sc->sbl.common.value&IDB_VALUE_STATUS_MASK) == IDB_VALUE_PASS) { err = STATUS_CMD_OK; } else if ((sc->sbl.common.value & IDB_VALUE_STATUS_MASK) == IDB_VALUE_FAIL || (sc->sbl.common.value & IDB_VALUE_STATUS_MASK) == IDB_VALUE_PERSISTENT) { err = STATUS_CMD_FAILED; } else { err = STATUS_WIRE_FAILED; } sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen-sc->transfer_actlen, err); } } return; case TSTATE_CBI_DCLEAR: if (err) { /* should not occur */ printf("%s: CBI bulk-in/out stall clear failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); umass_cbi_reset(sc, STATUS_WIRE_FAILED); } sc->transfer_state = TSTATE_IDLE; sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, STATUS_CMD_FAILED); return; case TSTATE_CBI_SCLEAR: if (err) /* should not occur */ printf("%s: CBI intr-in stall clear failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* Something really bad is going on. Reset the device */ umass_cbi_reset(sc, STATUS_CMD_FAILED); return; /***** CBI Reset *****/ case TSTATE_CBI_RESET1: if (err) printf("%s: CBI reset failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); umass_clear_endpoint_stall(sc, sc->bulkin, sc->bulkin_pipe, TSTATE_CBI_RESET2, sc->transfer_xfer[XFER_CBI_RESET2]); return; case TSTATE_CBI_RESET2: if (err) /* should not occur */ printf("%s: CBI bulk-in stall clear failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ umass_clear_endpoint_stall(sc, sc->bulkout, sc->bulkout_pipe, TSTATE_CBI_RESET3, sc->transfer_xfer[XFER_CBI_RESET3]); return; case TSTATE_CBI_RESET3: if (err) /* should not occur */ printf("%s: CBI bulk-out stall clear failed, %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); /* no error recovery, otherwise we end up in a loop */ sc->transfer_state = TSTATE_IDLE; if (sc->transfer_priv) { sc->transfer_cb(sc, sc->transfer_priv, sc->transfer_datalen, sc->transfer_status); } return; /***** Default *****/ default: panic("%s: Unknown state %d", USBDEVNAME(sc->sc_dev), sc->transfer_state); } } /* * CAM specific functions (used by SCSI, UFI, 8070i (ATAPI)) */ Static int umass_cam_attach_sim(struct umass_softc *sc) { struct cam_devq *devq; /* Per device Queue */ /* A HBA is attached to the CAM layer. * * The CAM layer will then after a while start probing for * devices on the bus. The number of SIMs is limited to one. */ devq = cam_simq_alloc(1 /*maximum openings*/); if (devq == NULL) return(ENOMEM); sc->umass_sim = cam_sim_alloc(umass_cam_action, umass_cam_poll, DEVNAME_SIM, sc /*priv*/, USBDEVUNIT(sc->sc_dev) /*unit number*/, 1 /*maximum device openings*/, 0 /*maximum tagged device openings*/, devq); if (sc->umass_sim == NULL) { cam_simq_free(devq); return(ENOMEM); } if(xpt_bus_register(sc->umass_sim, USBDEVUNIT(sc->sc_dev)) != CAM_SUCCESS) return(ENOMEM); return(0); } Static void umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) { #ifdef USB_DEBUG if (ccb->ccb_h.status != CAM_REQ_CMP) { DPRINTF(UDMASS_SCSI, ("%s:%d Rescan failed, 0x%04x\n", periph->periph_name, periph->unit_number, ccb->ccb_h.status)); } else { DPRINTF(UDMASS_SCSI, ("%s%d: Rescan succeeded\n", periph->periph_name, periph->unit_number)); } #endif xpt_free_path(ccb->ccb_h.path); free(ccb, M_USBDEV); } Static void umass_cam_rescan(void *addr) { struct umass_softc *sc = (struct umass_softc *) addr; struct cam_path *path; union ccb *ccb; DPRINTF(UDMASS_SCSI, ("scbus%d: scanning for %s:%d:%d:%d\n", cam_sim_path(sc->umass_sim), USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD)); ccb = malloc(sizeof(union ccb), M_USBDEV, M_NOWAIT | M_ZERO); if (ccb == NULL) return; if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->umass_sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { free(ccb, M_USBDEV); return; } xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/); ccb->ccb_h.func_code = XPT_SCAN_BUS; ccb->ccb_h.cbfcnp = umass_cam_rescan_callback; ccb->crcn.flags = CAM_FLAG_NONE; xpt_action(ccb); /* The scan is in progress now. */ } Static int umass_cam_attach(struct umass_softc *sc) { #ifndef USB_DEBUG if (bootverbose) #endif printf("%s:%d:%d:%d: Attached to scbus%d\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), USBDEVUNIT(sc->sc_dev), CAM_LUN_WILDCARD, cam_sim_path(sc->umass_sim)); if (!cold) { /* Notify CAM of the new device after a short delay. Any * failure is benign, as the user can still do it by hand * (camcontrol rescan ). Only do this if we are not * booting, because CAM does a scan after booting has * completed, when interrupts have been enabled. */ usb_callout(sc->cam_scsi_rescan_ch, MS_TO_TICKS(200), umass_cam_rescan, sc); } return(0); /* always succesfull */ } /* umass_cam_detach * detach from the CAM layer */ Static int umass_cam_detach_sim(struct umass_softc *sc) { if (sc->umass_sim) { if (xpt_bus_deregister(cam_sim_path(sc->umass_sim))) cam_sim_free(sc->umass_sim, /*free_devq*/TRUE); else return(EBUSY); sc->umass_sim = NULL; } return(0); } /* umass_cam_action * CAM requests for action come through here */ Static void umass_cam_action(struct cam_sim *sim, union ccb *ccb) { struct umass_softc *sc = (struct umass_softc *)sim->softc; /* The softc is still there, but marked as going away. umass_cam_detach * has not yet notified CAM of the lost device however. */ if (sc && (sc->flags & UMASS_FLAGS_GONE)) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target (gone)\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } /* Verify, depending on the operation to perform, that we either got a * valid sc, because an existing target was referenced, or otherwise * the SIM is addressed. * * This avoids bombing out at a printf and does give the CAM layer some * sensible feedback on errors. */ switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: case XPT_RESET_DEV: case XPT_GET_TRAN_SETTINGS: case XPT_SET_TRAN_SETTINGS: case XPT_CALC_GEOMETRY: /* the opcodes requiring a target. These should never occur. */ if (sc == NULL) { printf("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target (target needed)\n", DEVNAME_SIM, cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code); ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } break; case XPT_PATH_INQ: case XPT_NOOP: /* The opcodes sometimes aimed at a target (sc is valid), * sometimes aimed at the SIM (sc is invalid and target is * CAM_TARGET_WILDCARD) */ if (sc == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Invalid target (no wildcard)\n", DEVNAME_SIM, cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } break; default: /* XXX Hm, we should check the input parameters */ break; } /* Perform the requested action */ switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { struct ccb_scsiio *csio = &ccb->csio; /* deref union */ int dir; unsigned char *cmd; int cmdlen; unsigned char *rcmd; int rcmdlen; DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " "cmd: 0x%02x, flags: 0x%02x, " "%db cmd/%db data/%db sense\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], ccb->ccb_h.flags & CAM_DIR_MASK, csio->cdb_len, csio->dxfer_len, csio->sense_len)); /* clear the end of the buffer to make sure we don't send out * garbage. */ DIF(UDMASS_SCSI, if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) umass_dump_buffer(sc, csio->data_ptr, csio->dxfer_len, 48)); if (sc->transfer_state != TSTATE_IDLE) { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SCSI_IO: " "I/O in progress, deferring (state %d, %s)\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, sc->transfer_state,states[sc->transfer_state])); ccb->ccb_h.status = CAM_SCSI_BUSY; xpt_done(ccb); return; } switch(ccb->ccb_h.flags&CAM_DIR_MASK) { case CAM_DIR_IN: dir = DIR_IN; break; case CAM_DIR_OUT: dir = DIR_OUT; break; default: dir = DIR_NONE; } ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED; if (csio->ccb_h.flags & CAM_CDB_POINTER) { cmd = (unsigned char *) csio->cdb_io.cdb_ptr; } else { cmd = (unsigned char *) &csio->cdb_io.cdb_bytes; } cmdlen = csio->cdb_len; rcmd = (unsigned char *) &sc->cam_scsi_command; rcmdlen = sizeof(sc->cam_scsi_command); /* sc->transform will convert the command to the command * (format) needed by the specific command set and return * the converted command in a buffer pointed to be rcmd. * We pass in a buffer, but if the command does not * have to be transformed it returns a ptr to the original * buffer (see umass_scsi_transform). */ if (sc->transform(sc, cmd, cmdlen, &rcmd, &rcmdlen)) { /* * Handle EVPD inquiry for broken devices first * NO_INQUIRY also implies NO_INQUIRY_EVPD */ if ((sc->quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) && rcmd[0] == INQUIRY && (rcmd[1] & SI_EVPD)) { struct scsi_sense_data *sense; sense = &ccb->csio.sense_data; bzero(sense, sizeof(*sense)); sense->error_code = SSD_CURRENT_ERROR; sense->flags = SSD_KEY_ILLEGAL_REQUEST; sense->add_sense_code = 0x24; sense->extra_len = 10; ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; xpt_done(ccb); return; } /* Return fake inquiry data for broken devices */ if ((sc->quirks & NO_INQUIRY) && rcmd[0] == INQUIRY) { struct ccb_scsiio *csio = &ccb->csio; memcpy(csio->data_ptr, &fake_inq_data, sizeof(fake_inq_data)); csio->scsi_status = SCSI_STATUS_OK; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); return; } if ((sc->quirks & FORCE_SHORT_INQUIRY) && rcmd[0] == INQUIRY) { csio->dxfer_len = SHORT_INQUIRY_LENGTH; } sc->transfer(sc, ccb->ccb_h.target_lun, rcmd, rcmdlen, csio->data_ptr, csio->dxfer_len, dir, ccb->ccb_h.timeout, umass_cam_cb, (void *) ccb); } else { ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); } break; } case XPT_PATH_INQ: { struct ccb_pathinq *cpi = &ccb->cpi; DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_PATH_INQ:.\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); /* host specific information */ cpi->version_num = 1; cpi->hba_inquiry = 0; cpi->target_sprt = 0; cpi->hba_misc = PIM_NO_6_BYTE; cpi->hba_eng_cnt = 0; cpi->max_target = UMASS_SCSIID_MAX; /* one target */ cpi->initiator_id = UMASS_SCSIID_HOST; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = USBDEVUNIT(sc->sc_dev); if (sc == NULL) { cpi->base_transfer_speed = 0; cpi->max_lun = 0; } else { if (sc->quirks & FLOPPY_SPEED) { cpi->base_transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED; } else if (usbd_get_speed(sc->sc_udev) == USB_SPEED_HIGH) { cpi->base_transfer_speed = UMASS_HIGH_TRANSFER_SPEED; } else { cpi->base_transfer_speed = UMASS_FULL_TRANSFER_SPEED; } cpi->max_lun = sc->maxlun; } cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_RESET_DEV: { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_RESET_DEV:.\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_REQ_INPROG; umass_reset(sc, umass_cam_cb, (void *) ccb); break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); cts->valid = 0; cts->flags = 0; /* no disconnection, tagging */ ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_SET_TRAN_SETTINGS: { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n", USBDEVNAME(sc->sc_dev), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; xpt_done(ccb); break; } case XPT_CALC_GEOMETRY: { cam_calc_geometry(&ccb->ccg, /*extended*/1); xpt_done(ccb); break; } case XPT_NOOP: { DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:XPT_NOOP:.\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun)); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } default: DPRINTF(UDMASS_SCSI, ("%s:%d:%d:%d:func_code 0x%04x: " "Not implemented\n", (sc == NULL? DEVNAME_SIM:USBDEVNAME(sc->sc_dev)), cam_sim_path(sc->umass_sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->ccb_h.func_code)); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; xpt_done(ccb); break; } } /* umass_cam_poll * all requests are handled through umass_cam_action, requests * are never pending. So, nothing to do here. */ Static void umass_cam_poll(struct cam_sim *sim) { #ifdef USB_DEBUG struct umass_softc *sc = (struct umass_softc *) sim->softc; DPRINTF(UDMASS_SCSI, ("%s: CAM poll\n", USBDEVNAME(sc->sc_dev))); #endif /* nop */ } /* umass_cam_cb * finalise a completed CAM command */ Static void umass_cam_cb(struct umass_softc *sc, void *priv, int residue, int status) { union ccb *ccb = (union ccb *) priv; struct ccb_scsiio *csio = &ccb->csio; /* deref union */ /* If the device is gone, just fail the request. */ if (sc->flags & UMASS_FLAGS_GONE) { ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } csio->resid = residue; switch (status) { case STATUS_CMD_OK: ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; case STATUS_CMD_UNKNOWN: case STATUS_CMD_FAILED: switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { unsigned char *rcmd; int rcmdlen; /* fetch sense data */ /* the rest of the command was filled in at attach */ sc->cam_scsi_sense.length = csio->sense_len; DPRINTF(UDMASS_SCSI,("%s: Fetching %db sense data\n", USBDEVNAME(sc->sc_dev), csio->sense_len)); rcmd = (unsigned char *) &sc->cam_scsi_command; rcmdlen = sizeof(sc->cam_scsi_command); if (sc->transform(sc, (unsigned char *) &sc->cam_scsi_sense, sizeof(sc->cam_scsi_sense), &rcmd, &rcmdlen)) { if ((sc->quirks & FORCE_SHORT_INQUIRY) && (rcmd[0] == INQUIRY)) { csio->sense_len = SHORT_INQUIRY_LENGTH; } sc->transfer(sc, ccb->ccb_h.target_lun, rcmd, rcmdlen, &csio->sense_data, csio->sense_len, DIR_IN, ccb->ccb_h.timeout, umass_cam_sense_cb, (void *) ccb); } else { panic("transform(REQUEST_SENSE) failed"); } break; } case XPT_RESET_DEV: /* Reset failed */ ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); break; default: panic("umass_cam_cb called for func_code %d", ccb->ccb_h.func_code); } break; case STATUS_WIRE_FAILED: /* the wire protocol failed and will have recovered * (hopefully). We return an error to CAM and let CAM retry * the command if necessary. */ ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); break; default: panic("%s: Unknown status %d in umass_cam_cb", USBDEVNAME(sc->sc_dev), status); } } /* Finalise a completed autosense operation */ Static void umass_cam_sense_cb(struct umass_softc *sc, void *priv, int residue, int status) { union ccb *ccb = (union ccb *) priv; struct ccb_scsiio *csio = &ccb->csio; /* deref union */ unsigned char *rcmd; int rcmdlen; if (sc->flags & UMASS_FLAGS_GONE) { ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; xpt_done(ccb); return; } switch (status) { case STATUS_CMD_OK: case STATUS_CMD_UNKNOWN: case STATUS_CMD_FAILED: /* Getting sense data always succeeds (apart from wire * failures). */ if ((sc->quirks & RS_NO_CLEAR_UA) && csio->cdb_io.cdb_bytes[0] == INQUIRY && (csio->sense_data.flags & SSD_KEY) == SSD_KEY_UNIT_ATTENTION) { /* Ignore unit attention errors in the case where * the Unit Attention state is not cleared on * REQUEST SENSE. They will appear again at the next * command. */ ccb->ccb_h.status = CAM_REQ_CMP; } else if ((csio->sense_data.flags & SSD_KEY) == SSD_KEY_NO_SENSE) { /* No problem after all (in the case of CBI without * CCI) */ ccb->ccb_h.status = CAM_REQ_CMP; } else if ((sc->quirks & RS_NO_CLEAR_UA) && (csio->cdb_io.cdb_bytes[0] == READ_CAPACITY) && ((csio->sense_data.flags & SSD_KEY) == SSD_KEY_UNIT_ATTENTION)) { /* * Some devices do not clear the unit attention error * on request sense. We insert a test unit ready * command to make sure we clear the unit attention * condition, then allow the retry to proceed as * usual. */ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; csio->scsi_status = SCSI_STATUS_CHECK_COND; #if 0 DELAY(300000); #endif DPRINTF(UDMASS_SCSI,("%s: Doing a sneaky" "TEST_UNIT_READY\n", USBDEVNAME(sc->sc_dev))); /* the rest of the command was filled in at attach */ rcmd = (unsigned char *) &sc->cam_scsi_command2; rcmdlen = sizeof(sc->cam_scsi_command2); if (sc->transform(sc, (unsigned char *) &sc->cam_scsi_test_unit_ready, sizeof(sc->cam_scsi_test_unit_ready), &rcmd, &rcmdlen)) { sc->transfer(sc, ccb->ccb_h.target_lun, rcmd, rcmdlen, NULL, 0, DIR_NONE, ccb->ccb_h.timeout, umass_cam_quirk_cb, (void *) ccb); } else { panic("transform(TEST_UNIT_READY) failed"); } break; } else { ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; csio->scsi_status = SCSI_STATUS_CHECK_COND; } xpt_done(ccb); break; default: DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n", USBDEVNAME(sc->sc_dev), status)); ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; xpt_done(ccb); } } /* * This completion code just handles the fact that we sent a test-unit-ready * after having previously failed a READ CAPACITY with CHECK_COND. Even * though this command succeeded, we have to tell CAM to retry. */ Static void umass_cam_quirk_cb(struct umass_softc *sc, void *priv, int residue, int status) { union ccb *ccb = (union ccb *) priv; DPRINTF(UDMASS_SCSI, ("%s: Test unit ready returned status %d\n", USBDEVNAME(sc->sc_dev), status)); if (sc->flags & UMASS_FLAGS_GONE) { ccb->ccb_h.status = CAM_TID_INVALID; xpt_done(ccb); return; } #if 0 ccb->ccb_h.status = CAM_REQ_CMP; #endif ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; xpt_done(ccb); } Static int umass_driver_load(module_t mod, int what, void *arg) { switch (what) { case MOD_UNLOAD: case MOD_LOAD: default: return(usbd_driver_load(mod, what, arg)); } } /* * SCSI specific functions */ Static int umass_scsi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { switch (cmd[0]) { case TEST_UNIT_READY: if (sc->quirks & NO_TEST_UNIT_READY) { KASSERT(*rcmdlen >= sizeof(struct scsi_start_stop_unit), ("rcmdlen = %d < %ld, buffer too small", *rcmdlen, (long)sizeof(struct scsi_start_stop_unit))); DPRINTF(UDMASS_SCSI, ("%s: Converted TEST_UNIT_READY " "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); memset(*rcmd, 0, *rcmdlen); (*rcmd)[0] = START_STOP_UNIT; (*rcmd)[4] = SSS_START; return 1; } /* fallthrough */ case INQUIRY: /* some drives wedge when asked for full inquiry information. */ if (sc->quirks & FORCE_SHORT_INQUIRY) { memcpy(*rcmd, cmd, cmdlen); *rcmdlen = cmdlen; (*rcmd)[4] = SHORT_INQUIRY_LENGTH; return 1; } /* fallthrough */ default: *rcmd = cmd; /* We don't need to copy it */ *rcmdlen = cmdlen; } return 1; } /* RBC specific functions */ Static int umass_rbc_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { switch (cmd[0]) { /* these commands are defined in RBC: */ case READ_10: case READ_CAPACITY: case START_STOP_UNIT: case SYNCHRONIZE_CACHE: case WRITE_10: case 0x2f: /* VERIFY_10 is absent from scsi_all.h??? */ case INQUIRY: case MODE_SELECT_10: case MODE_SENSE_10: case TEST_UNIT_READY: case WRITE_BUFFER: /* The following commands are not listed in my copy of the RBC specs. * CAM however seems to want those, and at least the Sony DSC device * appears to support those as well */ case REQUEST_SENSE: case PREVENT_ALLOW: if ((sc->quirks & RBC_PAD_TO_12) && cmdlen < 12) { *rcmdlen = 12; bcopy(cmd, *rcmd, cmdlen); bzero(*rcmd + cmdlen, 12 - cmdlen); } else { *rcmd = cmd; /* We don't need to copy it */ *rcmdlen = cmdlen; } return 1; /* All other commands are not legal in RBC */ default: printf("%s: Unsupported RBC command 0x%02x", USBDEVNAME(sc->sc_dev), cmd[0]); printf("\n"); return 0; /* failure */ } } /* * UFI specific functions */ Static int umass_ufi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { /* A UFI command is always 12 bytes in length */ KASSERT(*rcmdlen >= UFI_COMMAND_LENGTH, ("rcmdlen = %d < %d, buffer too small", *rcmdlen, UFI_COMMAND_LENGTH)); *rcmdlen = UFI_COMMAND_LENGTH; memset(*rcmd, 0, UFI_COMMAND_LENGTH); switch (cmd[0]) { /* Commands of which the format has been verified. They should work. * Copy the command into the (zeroed out) destination buffer. */ case TEST_UNIT_READY: if (sc->quirks & NO_TEST_UNIT_READY) { /* Some devices do not support this command. * Start Stop Unit should give the same results */ DPRINTF(UDMASS_UFI, ("%s: Converted TEST_UNIT_READY " "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); (*rcmd)[0] = START_STOP_UNIT; (*rcmd)[4] = SSS_START; } else { memcpy(*rcmd, cmd, cmdlen); } return 1; case REZERO_UNIT: case REQUEST_SENSE: case FORMAT_UNIT: case INQUIRY: case START_STOP_UNIT: case SEND_DIAGNOSTIC: case PREVENT_ALLOW: case READ_CAPACITY: case READ_10: case WRITE_10: case POSITION_TO_ELEMENT: /* SEEK_10 */ case WRITE_AND_VERIFY: case VERIFY: case MODE_SELECT_10: case MODE_SENSE_10: case READ_12: case WRITE_12: case READ_FORMAT_CAPACITIES: memcpy(*rcmd, cmd, cmdlen); return 1; default: printf("%s: Unsupported UFI command 0x%02x\n", USBDEVNAME(sc->sc_dev), cmd[0]); return 0; /* failure */ } } /* * 8070i (ATAPI) specific functions */ Static int umass_atapi_transform(struct umass_softc *sc, unsigned char *cmd, int cmdlen, unsigned char **rcmd, int *rcmdlen) { /* An ATAPI command is always 12 bytes in length. */ KASSERT(*rcmdlen >= ATAPI_COMMAND_LENGTH, ("rcmdlen = %d < %d, buffer too small", *rcmdlen, ATAPI_COMMAND_LENGTH)); *rcmdlen = ATAPI_COMMAND_LENGTH; memset(*rcmd, 0, ATAPI_COMMAND_LENGTH); switch (cmd[0]) { /* Commands of which the format has been verified. They should work. * Copy the command into the (zeroed out) destination buffer. */ case INQUIRY: memcpy(*rcmd, cmd, cmdlen); /* some drives wedge when asked for full inquiry information. */ if (sc->quirks & FORCE_SHORT_INQUIRY) (*rcmd)[4] = SHORT_INQUIRY_LENGTH; return 1; case TEST_UNIT_READY: if (sc->quirks & NO_TEST_UNIT_READY) { KASSERT(*rcmdlen >= sizeof(struct scsi_start_stop_unit), ("rcmdlen = %d < %ld, buffer too small", *rcmdlen, (long)sizeof(struct scsi_start_stop_unit))); DPRINTF(UDMASS_SCSI, ("%s: Converted TEST_UNIT_READY " "to START_UNIT\n", USBDEVNAME(sc->sc_dev))); memset(*rcmd, 0, *rcmdlen); (*rcmd)[0] = START_STOP_UNIT; (*rcmd)[4] = SSS_START; return 1; } /* fallthrough */ case REZERO_UNIT: case REQUEST_SENSE: case START_STOP_UNIT: case SEND_DIAGNOSTIC: case PREVENT_ALLOW: case READ_CAPACITY: case READ_10: case WRITE_10: case POSITION_TO_ELEMENT: /* SEEK_10 */ case SYNCHRONIZE_CACHE: case MODE_SELECT_10: case MODE_SENSE_10: case READ_BUFFER: case 0x42: /* READ_SUBCHANNEL */ case 0x43: /* READ_TOC */ case 0x44: /* READ_HEADER */ case 0x47: /* PLAY_MSF (Play Minute/Second/Frame) */ case 0x48: /* PLAY_TRACK */ case 0x49: /* PLAY_TRACK_REL */ case 0x4b: /* PAUSE */ case 0x51: /* READ_DISK_INFO */ case 0x52: /* READ_TRACK_INFO */ case 0x54: /* SEND_OPC */ case 0x59: /* READ_MASTER_CUE */ case 0x5b: /* CLOSE_TR_SESSION */ case 0x5c: /* READ_BUFFER_CAP */ case 0x5d: /* SEND_CUE_SHEET */ case 0xa1: /* BLANK */ case 0xa5: /* PLAY_12 */ case 0xa6: /* EXCHANGE_MEDIUM */ case 0xad: /* READ_DVD_STRUCTURE */ case 0xbb: /* SET_CD_SPEED */ case 0xe5: /* READ_TRACK_INFO_PHILIPS */ memcpy(*rcmd, cmd, cmdlen); return 1; case READ_12: case WRITE_12: default: printf("%s: Unsupported ATAPI command 0x%02x\n", USBDEVNAME(sc->sc_dev), cmd[0]); return 0; /* failure */ } } /* (even the comment is missing) */ DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, umass_driver_load, 0); #ifdef USB_DEBUG Static void umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw) { int clen = cbw->bCDBLength; int dlen = UGETDW(cbw->dCBWDataTransferLength); u_int8_t *c = cbw->CBWCDB; int tag = UGETDW(cbw->dCBWTag); int flags = cbw->bCBWFlags; DPRINTF(UDMASS_BBB, ("%s: CBW %d: cmd = %db " "(0x%02x%02x%02x%02x%02x%02x%s), " "data = %db, dir = %s\n", USBDEVNAME(sc->sc_dev), tag, clen, c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6? "...":""), dlen, (flags == CBWFLAGS_IN? "in": (flags == CBWFLAGS_OUT? "out":"")))); } Static void umass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw) { int sig = UGETDW(csw->dCSWSignature); int tag = UGETW(csw->dCSWTag); int res = UGETDW(csw->dCSWDataResidue); int status = csw->bCSWStatus; DPRINTF(UDMASS_BBB, ("%s: CSW %d: sig = 0x%08x (%s), tag = %d, " "res = %d, status = 0x%02x (%s)\n", USBDEVNAME(sc->sc_dev), tag, sig, (sig == CSWSIGNATURE? "valid":"invalid"), tag, res, status, (status == CSWSTATUS_GOOD? "good": (status == CSWSTATUS_FAILED? "failed": (status == CSWSTATUS_PHASE? "phase":""))))); } Static void umass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, int cmdlen) { u_int8_t *c = cmd; int dir = sc->transfer_dir; DPRINTF(UDMASS_BBB, ("%s: cmd = %db " "(0x%02x%02x%02x%02x%02x%02x%s), " "data = %db, dir = %s\n", USBDEVNAME(sc->sc_dev), cmdlen, c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6? "...":""), sc->transfer_datalen, (dir == DIR_IN? "in": (dir == DIR_OUT? "out": (dir == DIR_NONE? "no data phase": ""))))); } Static void umass_dump_buffer(struct umass_softc *sc, u_int8_t *buffer, int buflen, int printlen) { int i, j; char s1[40]; char s2[40]; char s3[5]; s1[0] = '\0'; s3[0] = '\0'; sprintf(s2, " buffer=%p, buflen=%d", buffer, buflen); for (i = 0; i < buflen && i < printlen; i++) { j = i % 16; if (j == 0 && i != 0) { DPRINTF(UDMASS_GEN, ("%s: 0x %s%s\n", USBDEVNAME(sc->sc_dev), s1, s2)); s2[0] = '\0'; } sprintf(&s1[j*2], "%02x", buffer[i] & 0xff); } if (buflen > printlen) sprintf(s3, " ..."); DPRINTF(UDMASS_GEN, ("%s: 0x %s%s%s\n", USBDEVNAME(sc->sc_dev), s1, s2, s3)); } #endif Index: head/sys/dev/usb/usbdevs =================================================================== --- head/sys/dev/usb/usbdevs (revision 155062) +++ head/sys/dev/usb/usbdevs (revision 155063) @@ -1,1641 +1,1642 @@ $FreeBSD$ /* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */ /*- * Copyright (c) 1998-2004 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * List of known USB vendors * * USB.org publishes a VID list of USB-IF member companies at * http://www.usb.org/developers/tools * Note that it does not show companies that have obtained a Vendor ID * without becoming full members. * * Please note that these IDs do not do anything. Adding an ID here and * regenerating the usbdevs.h and usbdevs_data.h only makes a symbolic name * available to the source code and does not change any functionality, nor * does it make your device available to a specific driver. * It will however make the descriptive string available if a device does not * provide the string itself. * * After adding a vendor ID VNDR and a product ID PRDCT you will have the * following extra defines: * #define USB_VENDOR_VNDR 0x???? * #define USB_PRODUCT_VNDR_PRDCT 0x???? * * You may have to add these defines to the respective probe routines to * make the device recognised by the appropriate device driver. */ vendor EGALAX2 0x0123 eGalax vendor LTS 0x0386 LTS vendor AOX 0x03e8 AOX vendor THESYS 0x03e9 Thesys vendor DATABROADCAST 0x03ea Data Broadcasting vendor ATMEL 0x03eb Atmel vendor IWATSU 0x03ec Iwatsu America vendor MITEL 0x03ee Mitel vendor MITSUMI 0x03ee Mitsumi vendor HP 0x03f0 Hewlett Packard vendor GENOA 0x03f1 Genoa vendor OAK 0x03f2 Oak vendor ADAPTEC 0x03f3 Adaptec vendor DIEBOLD 0x03f4 Diebold vendor SIEMENSELECTRO 0x03f5 Siemens Electromechanical vendor EPSONIMAGING 0x03f8 Epson Imaging vendor KEYTRONIC 0x03f9 KeyTronic vendor OPTI 0x03fb OPTi vendor ELITEGROUP 0x03fc Elitegroup vendor XILINX 0x03fd Xilinx vendor FARALLON 0x03fe Farallon Communications vendor NATIONAL 0x0400 National Semiconductor vendor NATIONALREG 0x0401 National Registry vendor ACERLABS 0x0402 Acer Labs vendor FTDI 0x0403 Future Technology Devices vendor NCR 0x0404 NCR vendor SYNOPSYS2 0x0405 Synopsys vendor FUJITSUICL 0x0406 Fujitsu-ICL vendor FUJITSU2 0x0407 Fujitsu Personal Systems vendor QUANTA 0x0408 Quanta vendor NEC 0x0409 NEC vendor KODAK 0x040a Eastman Kodak vendor WELTREND 0x040b Weltrend vendor VIA 0x040d VIA vendor MCCI 0x040e MCCI vendor MELCO 0x0411 Melco vendor WINBOND 0x0416 Winbond vendor PHOENIX 0x041a Phoenix vendor CREATIVE 0x041e Creative vendor NOKIA 0x0421 Nokia vendor ADI 0x0422 ADI vendor CATC 0x0423 Computer Access Technology vendor SMC2 0x0424 SMC vendor MOTOROLA_HK 0x0425 Motorola HK vendor GRAVIS 0x0428 Advanced Gravis Computer Tech. vendor CIRRUSLOGIC 0x0429 Cirrus Logic vendor INNOVATIVE 0x042c Innovative Semiconductors vendor MOLEX 0x042f Molex vendor SUN2 0x0430 Sun Microsystems (unofficial) vendor UNISYS 0x0432 Unisys vendor TAUGA 0x0436 Taugagreining HF vendor AMD 0x0438 ADM vendor LEXMARK 0x043d Lexmark vendor LG 0x043e LG Electronics vendor NANAO 0x0440 NANAO vendor GATEWAY 0x0443 Gateway 2000 vendor NMB 0x0446 NMB vendor ALPS 0x044e Alps vendor THRUST 0x044f Thrustmaster vendor TI 0x0451 Texas Instruments vendor ANALOGDEVICES 0x0456 Analog Devices vendor SIS 0x0457 SIS vendor KYE 0x0458 KYE vendor DIAMOND2 0x045a Diamond (Supra) vendor RENESAS 0x045b Renesas vendor MICROSOFT 0x045e Microsoft vendor PRIMAX 0x0461 Primax vendor MGE 0x0463 MGE vendor AMP 0x0464 AMP vendor CHERRY 0x046a Cherry vendor MEGATRENDS 0x046b American Megatrends vendor LOGITECH 0x046d Logitech vendor BTC 0x046e BTC vendor PHILIPS 0x0471 Philips vendor SUN 0x0472 Sun Microsystems (offical) vendor SANYO 0x0474 Sanyo vendor SEAGATE 0x0477 Seagate vendor CONNECTIX 0x0478 Connectix vendor SEMTECH 0x047a Semtech vendor KENSINGTON 0x047d Kensington vendor LUCENT 0x047e Lucent vendor PLANTRONICS 0x047f Plantronics vendor KYOCERA 0x0482 Kyocera vendor STMICRO 0x0483 STMicroelectronics vendor FOXCONN 0x0489 Foxconn vendor YAMAHA 0x0499 YAMAHA vendor COMPAQ 0x049f Compaq vendor HITACHI 0x04a4 Hitachi vendor ACERP 0x04a5 Acer Peripherals vendor VISIONEER 0x04a7 Visioneer vendor CANON 0x04a9 Canon vendor NIKON 0x04b0 Nikon vendor PAN 0x04b1 Pan International vendor IBM 0x04b3 IBM vendor CYPRESS 0x04b4 Cypress vendor ROHM 0x04b5 ROHM vendor COMPAL 0x04b7 Compal vendor EPSON 0x04b8 Seiko Epson vendor RAINBOW 0x04b9 Rainbow vendor IODATA 0x04bb I-O Data vendor TDK 0x04bf TDK vendor 3COMUSR 0x04c1 U.S. Robotics vendor METHODE 0x04c2 Methode vendor MAXISWITCH 0x04c3 Maxi Switch vendor LOCKHEEDMER 0x04c4 Lockheed Martin Energy Research vendor FUJITSU 0x04c5 Fujitsu vendor TOSHIBAAM 0x04c6 Toshiba vendor MICROMACRO 0x04c7 Micro Macro vendor KONICA 0x04c8 Konica vendor LITEON 0x04ca Lite-On vendor FUJIPHOTO 0x04cb Fuji Photo vendor PHILIPSSEMI 0x04cc Philips vendor TATUNG 0x04cd Tatung vendor SCANLOGIC 0x04ce ScanLogic vendor MYSON 0x04cf Myson vendor DIGI2 0x04d0 Digi vendor ITTCANON 0x04d1 ITT Canon vendor ALTEC 0x04d2 Altec Lansing vendor LSI 0x04d4 LSI vendor MENTORGRAPHICS 0x04d6 Mentor Graphics vendor HOLTEK 0x04d9 Holtek vendor PANASONIC 0x04da Panasonic (Matsushita) vendor HUANHSIN 0x04dc Huan Hsin vendor SHARP 0x04dd Sharp vendor IIYAMA 0x04e1 Iiyama vendor SHUTTLE 0x04e6 Shuttle vendor ELO 0x04e7 Elo TouchSystems vendor SAMSUNG 0x04e8 Samsung vendor NORTHSTAR 0x04eb Northstar vendor TOKYOELECTRON 0x04ec Tokyo Electron vendor ANNABOOKS 0x04ed Annabooks vendor JVC 0x04f1 JVC vendor CHICONY 0x04f2 Chicony vendor ELAN 0x04f3 Elan vendor NEWNEX 0x04f7 Newnex vendor BROTHER 0x04f9 Brother vendor DALLAS 0x04fa Dallas Semiconductor vendor SUNPLUS 0x04fc Sunplus vendor PFU 0x04fe PFU vendor FUJIKURA 0x0501 Fujikura/DDK vendor ACER 0x0502 Acer vendor 3COM 0x0506 3Com vendor HOSIDEN 0x0507 Hosiden vendor AZTECH 0x0509 Aztech vendor BELKIN 0x050d Belkin vendor KAWATSU 0x050f Kawatsu vendor FCI 0x0514 FCI vendor LONGWELL 0x0516 Longwell vendor COMPOSITE 0x0518 Composite vendor STAR 0x0519 Star Micronics vendor APC 0x051d American Power Conversion vendor SCIATLANTA 0x051e Scientific Atlanta vendor TSM 0x0520 TSM vendor CONNECTEK 0x0522 Connectek vendor NETCHIP 0x0525 NetChip vendor ALTRA 0x0527 ALTRA vendor ATI 0x0528 ATI vendor AKS 0x0529 AKS vendor TEKOM 0x052b Tekom vendor CANONDEV 0x052c Canon vendor WACOMTECH 0x0531 Wacom vendor INVENTEC 0x0537 Inventec vendor SHYHSHIUN 0x0539 Shyh Shiun Terminals vendor PREHWERKE 0x053a Preh Werke Gmbh & Co. KG vendor SYNOPSYS 0x053f Synopsys vendor UNIACCESS 0x0540 Universal Access vendor VIEWSONIC 0x0543 ViewSonic vendor XIRLINK 0x0545 Xirlink vendor ANCHOR 0x0547 Anchor vendor SONY 0x054c Sony vendor FUJIXEROX 0x0550 Fuji Xerox vendor VISION 0x0553 VLSI Vision vendor ASAHIKASEI 0x0556 Asahi Kasei vendor ATEN 0x0557 ATEN vendor MUSTEK 0x055f Mustek vendor TELEX 0x0562 Telex vendor CHINON 0x0564 Chinon vendor PERACOM 0x0565 Peracom Networks vendor ALCOR2 0x0566 Alcor Micro vendor XYRATEX 0x0567 Xyratex vendor WACOM 0x056a WACOM vendor ETEK 0x056c e-TEK vendor EIZO 0x056d EIZO vendor ELECOM 0x056e Elecom vendor CONEXANT 0x0572 Conexant vendor HAUPPAUGE 0x0573 Hauppauge vendor BAFO 0x0576 BAFO vendor YEDATA 0x057b Y-E Data vendor AVM 0x057c AVM vendor QUICKSHOT 0x057f Quickshot vendor ROLAND 0x0582 Roland vendor ROCKFIRE 0x0583 Rockfire vendor RATOC 0x0584 RATOC vendor ZYXEL 0x0586 ZyXEL vendor INFINEON 0x058b Infineon vendor MICREL 0x058d Micrel vendor ALCOR 0x058f Alcor vendor OMRON 0x0590 OMRON vendor NIIGATA 0x0598 Niigata vendor IOMEGA 0x059b Iomega vendor ATREND 0x059c A-Trend vendor AID 0x059d AID vendor LACIE 0x059f LaCie vendor FUJIFILM 0x05a2 Fuji Film vendor ARC 0x05a3 ARC vendor ORTEK 0x05a4 Ortek vendor BOSE 0x05a7 Bose vendor OMNIVISION 0x05a9 OmniVision vendor INSYSTEM 0x05ab In-System vendor APPLE 0x05ac Apple Computer vendor YCCABLE 0x05ad Y.C. Cable vendor DIGITALPERSONA 0x05ba DigitalPersona vendor RAFI 0x05bd RAFI vendor TYCO 0x05be Tyco vendor KAWASAKI 0x05c1 Kawasaki vendor DIGI 0x05c5 Digi vendor QUALCOMM 0x05c6 Qualcomm vendor QTRONIX 0x05c7 Qtronix vendor FOXLINK 0x05c8 Foxlink vendor RICOH 0x05ca Ricoh vendor ELSA 0x05cc ELSA vendor SCIWORX 0x05ce sci-worx vendor BRAINBOXES 0x05d1 Brainboxes vendor ULTIMA 0x05d8 Ultima vendor AXIOHM 0x05d9 Axiohm vendor MICROTEK 0x05da Microtek vendor SUNTAC 0x05db SUN Corporation vendor LEXAR 0x05dc Lexar Media vendor DELTA 0x05dd Delta vendor SYMBOL 0x05e0 Symbol vendor SYNTEK 0x05e1 Syntek vendor GENESYS 0x05e3 Genesys vendor FUJI 0x05e5 Fuji vendor KEITHLEY 0x05e6 Keithley vendor EIZONANAO 0x05e7 EIZO Nanao vendor KLSI 0x05e9 Kawasaki LSI vendor FFC 0x05eb FFC vendor ANKO 0x05ef Anko vendor PIENGINEERING 0x05f3 P.I. Engineering vendor AOC 0x05f6 AOC vendor CHIC 0x05fe Chic vendor BARCO 0x0600 Barco vendor BRIDGE 0x0607 Bridge vendor SOLIDYEAR 0x060b Solid Year vendor BIORAD 0x0614 Bio-Rad vendor MACALLY 0x0618 Macally vendor ACTLABS 0x061c Act Labs vendor ALARIS 0x0620 Alaris vendor APEX 0x0624 Apex vendor VIVITAR 0x0636 Vivitar vendor AVISION 0x0638 Avision vendor TEAC 0x0644 TEAC vendor SGI 0x065e Silicon Graphics vendor SANWASUPPLY 0x0663 Sanwa Supply vendor LINKSYS 0x066b Linksys vendor ACERSA 0x066e Acer vendor SIGMATEL 0x066f Sigmatel vendor AIWA 0x0677 Aiwa vendor ACARD 0x0678 ACARD vendor PROLIFIC 0x067b Prolific vendor SIEMENS 0x067c Siemens vendor AVANCELOGIC 0x0680 Avance Logic vendor MINOLTA 0x0686 Minolta vendor CHPRODUCTS 0x068e CH Products vendor HAGIWARA 0x0693 Hagiwara Sys-Com vendor CTX 0x0698 Chuntex vendor ASKEY 0x069a Askey vendor SAITEK 0x06a3 Saitek vendor ALCATELT 0x06b9 Alcatel vendor AGFA 0x06bd AGFA-Gevaert vendor ASIAMD 0x06be Asia Microelectronic Development vendor BIZLINK 0x06c4 Bizlink vendor KEYSPAN 0x06cd Keyspan / InnoSys Inc. vendor AASHIMA 0x06d6 Aashima vendor MULTITECH 0x06e0 MultiTech vendor ADS 0x06e1 ADS vendor ALCATELM 0x06e4 Alcatel vendor SIRIUS 0x06ea Sirius vendor GUILLEMOT 0x06f8 Guillemot vendor BOSTON 0x06fd Boston Acoustics vendor SMC 0x0707 SCM vendor PUTERCOM 0x0708 Putercom vendor MCT 0x0711 MCT vendor IMATION 0x0718 Imation vendor SONYERICSSON 0x0731 Sony Ericsson vendor EICON 0x0734 Eicon Networks vendor DIGITALSTREAM 0x074e Digital Stream vendor AUREAL 0x0755 Aureal vendor MIDIMAN 0x0763 Midiman vendor LINKSYS2 0x077b Linksys vendor GRIFFIN 0x077d Griffin vendor SANDISK 0x0781 SanDisk vendor JENOPTIK 0x0784 Jenoptik vendor LOGITEC 0x0789 Logitec vendor BRIMAX 0x078e Brimax vendor AXIS 0x0792 Axis vendor ABL 0x0794 ABL vendor SUNCOMM 0x079c Sun Communications vendor ALFADATA 0x079d Alfadata vendor NATIONALTECH 0x07a2 National Technical vendor ONNTO 0x07a3 Onnto vendor BE 0x07a4 Be vendor ADMTEK 0x07a6 ADMtek vendor COREGA 0x07aa Corega vendor FREECOM 0x07ab Freecom vendor MICROTECH 0x07af Microtech vendor GENERALINSTMNTS 0x07b2 General Instruments (Motorola) vendor OLYMPUS 0x07b4 Olympus vendor ABOCOM 0x07b8 AboCom vendor KEISOKUGIKEN 0x07c1 Keisokugiken vendor ONSPEC 0x07c4 OnSpec vendor APG 0x07c5 APG vendor BUG 0x07c8 BUG vendor ALLIEDTELESYN 0x07c9 Allied Telesyn vendor AVERMEDIA 0x07ca AVerMedia vendor SIIG 0x07cc SIIG vendor CASIO 0x07cf CASIO vendor APTIO 0x07d2 Aptio vendor ARASAN 0x07da Arasan vendor ALLIEDCABLE 0x07e6 Allied Cable vendor STSN 0x07ef STSN vendor ZOOM 0x0803 Zoom vendor PCS 0x0810 Personal Communication Systems vendor BROADLOGIC 0x0827 BroadLogic vendor HANDSPRING 0x082d Handspring vendor PALM 0x0830 Palm vendor SOURCENEXT 0x0833 SOURCENEXT vendor ACTIONSTAR 0x0835 Action Star vendor SAMSUNG_TECHWIN 0x0839 Samsung Techwin vendor ACCTON 0x083a Accton vendor DIAMOND 0x0841 Diamond vendor NETGEAR 0x0846 BayNETGEAR vendor ACTIVEWIRE 0x0854 ActiveWire vendor BBELECTRONICS 0x0856 B&B Electronics vendor PORTGEAR 0x085a PortGear vendor SYSTEMTALKS 0x086e System Talks vendor METRICOM 0x0870 Metricom vendor ADESSOKBTEK 0x087c ADESSO vendor JATON 0x087d Jaton vendor APT 0x0880 APT vendor BOCARESEARCH 0x0885 Boca Research vendor ANDREA 0x08a8 Andrea vendor BURRBROWN 0x08bb Burr-Brown Japan vendor 2WIRE 0x08c8 2Wire vendor AIPTEK 0x08ca AIPTEK vendor SMARTBRIDGES 0x08d1 SmartBridges vendor BILLIONTON 0x08dd Billionton vendor EXTENDED 0x08e9 Extended vendor MSYSTEMS 0x08ec M-Systems vendor AUTHENTEC 0x08ff AuthenTec vendor AUDIOTECHNICA 0x0909 Audio-Technica vendor TRUMPION 0x090a Trumpion vendor ALATION 0x0910 Alation vendor CONCORDCAMERA 0x0919 Concord Camera vendor GOHUBS 0x0921 GoHubs vendor BIOMETRIC 0x0929 American Biometric vendor TOSHIBA 0x0930 Toshiba vendor PLEXTOR 0x093b Plextor vendor INTREPIDCS 0x093c Intrepid vendor YANO 0x094f Yano vendor KINGSTON 0x0951 Kingston vendor BLUEWATER 0x0956 BlueWater vendor AGILENT 0x0957 Agilent vendor PORTSMITH 0x095a Portsmith vendor ACERW 0x0967 Acer vendor ADIRONDACK 0x0976 Adirondack Wire & Cable vendor BECKHOFF 0x0978 Beckhoff vendor MINDSATWORK 0x097a Minds At Work vendor POINTCHIPS 0x09a6 PointChips vendor INTERSIL 0x09aa Intersil vendor ALTIUS 0x09b3 Altius Solutions vendor ARRIS 0x09c1 Arris Interactive vendor ACTIVCARD 0x09c3 ACTIVCARD vendor ACTISYS 0x09c4 ACTiSYS vendor AFOURTECH 0x09da A-FOUR TECH vendor AIMEX 0x09dc AIMEX vendor ADDONICS 0x09df Addonics vendor AKAI 0x09e8 AKAI vendor ARESCOM 0x09f5 ARESCOM vendor BAY 0x09f9 Bay Associates vendor ALTERA 0x09fb Altera vendor CSR 0x0a12 Cambridge Silicon Radio vendor TREK 0x0a16 Trek vendor ASAHIOPTICAL 0x0a17 Asahi Optical vendor BOCASYSTEMS 0x0a43 Boca Systems vendor MEDIAGEAR 0x0a48 MediaGear vendor BROADCOM 0x0a5c Broadcom vendor GREENHOUSE 0x0a6b GREENHOUSE vendor GEOCAST 0x0a79 Geocast vendor NEODIO 0x0aec Neodio vendor VODAFONE 0x0af0 Vodafone vendor ASUS 0x0b05 ASUS vendor TODOS 0x0b0c Todos Data System vendor SIIG2 0x0b39 SIIG vendor TEKRAM 0x0b3b Tekram vendor HAL 0x0b41 HAL vendor EMS 0x0b43 EMS vendor NEC2 0x0b62 NEC vendor ATI2 0x0b6f ATI vendor ZEEVO 0x0b7a Zeevo vendor KURUSUGAWA 0x0b7e Kurusugawa vendor ASIX 0x0b95 ASIX vendor USR 0x0baf U.S. Robotics vendor REALTEK 0x0bda RealTek vendor ADDONICS2 0x0bf6 Addonics vendor AGATE 0x0c08 Agate vendor DMI 0x0c0b DMI vendor CHICONY2 0x0c45 Chicony vendor SEALEVEL 0x0c52 Sealevel vendor LUWEN 0x0c76 Luwen vendor ZCOM 0x0cde Z-Com vendor TANGTOP 0x0d3d Tangtop vendor SMC3 0x0d5c SMC vendor PNY 0x0d7d PNY vendor ACDC 0x0d7e ACDC vendor ABC 0x0d8c ABC vendor MSI 0x0db0 Micro Star International vendor HAWKING 0x0e66 Hawking vendor GMATE 0x0e7e G.Mate, Inc vendor OTI 0x0ea0 Ours vendor PILOTECH 0x0eaf Pilotech vendor EGALAX 0x0eef eGalax vendor MICROTUNE 0x0f4d Microtune vendor VTECH 0x0f88 VTech vendor QUALCOMM2 0x1004 Qualcomm vendor GIGABYTE 0x1044 GIGABYTE vendor WESTERN 0x1058 Western Digital vendor MOTOROLA 0x1063 Motorola vendor CCYU 0x1065 CCYU vendor PLX 0x10b5 PLX vendor ASANTE 0x10bd Asante vendor JRC 0x1145 JRC vendor DELORME 0x1163 DeLorme vendor SERVERWORKS 0x1166 ServerWorks vendor ACERCM 0x1189 Acer Communications & Multimedia vendor TWINMOS 0x126f TwinMOS vendor TSUNAMI 0x1241 Tsunami vendor CREATIVE2 0x1292 Creative Labs vendor BELKIN2 0x1293 Belkin vendor AINCOMM 0x12fd Aincomm vendor MOBILITY 0x1342 Mobility vendor LINKSYS4 0x13b1 Linksys vendor SHARK 0x13d2 Shark vendor SILICOM 0x1485 Silicom vendor RALINK 0x148f Ralink Technology vendor IMAGINATION 0x149a Imagination Technologies vendor CONCEPTRONIC 0x14b2 Conceptronic vendor SILICONPORTALS 0x1527 Silicon Portals vendor SOHOWARE 0x15e8 SOHOware vendor UMAX 0x1606 UMAX vendor INSIDEOUT 0x1608 Inside Out Networks vendor ENTREGA 0x1645 Entrega vendor ACTIONTEC 0x1668 Actiontec vendor LINKSYS3 0x1915 Linksys vendor DLINK 0x2001 D-Link vendor ERICSSON 0x2282 Ericsson vendor MOTOROLA2 0x22b8 Motorola vendor TRIPPLITE 0x2478 Tripp-Lite vendor HIROSE 0x2631 Hirose vendor NHJ 0x2770 NHJ vendor PLANEX 0x2c02 Planex vendor VIDZMEDIA 0x3275 VidzMedia vendor AEI 0x3334 AEI vendor PQI 0x3538 PQI vendor DAISY 0x3579 Daisy vendor NI 0x3923 National Instruments vendor MICRONET 0x3980 Micronet vendor IODATA2 0x40bb I-O Data vendor IRIVER 0x4102 iRiver vendor DELL 0x413c Dell vendor AVERATEC 0x50c2 Averatec vendor ONSPEC2 0x55aa OnSpec vendor ZINWELL 0x5a57 Zinwell vendor SITECOM 0x6189 Sitecom vendor INTEL 0x8086 Intel vendor HP2 0xf003 Hewlett Packard /* * List of known products. Grouped by vendor. */ /* 3Com products */ product 3COM HOMECONN 0x009d HomeConnect Camera product 3COM 3CREB96 0x00a0 Bluetooth dongle product 3COM 3C19250 0x03E8 3C19250 Ethernet product 3COM 3CRSHEW696 0x0a01 3CRSHEW696 Wireless adapter product 3COM USR56K 0x3021 U.S.Robotics 56000 Voice Faxmodem Pro product 3COM 3C460 0x11f8 HomeConnect 3C460 product 3COM 3C460B 0x4601 HomeConnect 3C460B product 3COMUSR OFFICECONN 0x0082 3Com OfficeConnect Analog Modem product 3COMUSR USRISDN 0x008f 3Com U.S. Robotics Pro ISDN TA product 3COMUSR HOMECONN 0x009d 3Com HomeConnect camera product 3COMUSR USR56K 0x3021 U.S.Robotics 56000 Voice Faxmodem Pro /* AboCom products */ product ABOCOM XX1 0x110c XX1 product ABOCOM XX2 0x200c XX2 product ABOCOM URE450 0x4000 URE450 Ethernet product ABOCOM UFE1000 0x4002 UFE1000 Fast Ethernet product ABOCOM DSB650TX_PNA 0x4003 1/10/100 ethernet product ABOCOM XX4 0x4004 XX4 product ABOCOM XX5 0x4007 XX5 product ABOCOM XX6 0x400b XX6 product ABOCOM XX7 0x400c XX7 product ABOCOM XX8 0x4102 XX8 product ABOCOM XX9 0x4104 XX9 product ABOCOM XX10 0xabc1 XX10 /* Accton products */ product ACCTON USB320_EC 0x1046 USB320-EC Ethernet product ACCTON SS1001 0x5046 SpeedStream Ethernet /* Acer Peripherals, Inc. products */ product ACERP ACERSCAN_C310U 0x12a6 Acerscan C310U product ACERP ACERSCAN_320U 0x2022 Acerscan 320U product ACERP ACERSCAN_640U 0x2040 Acerscan 640U product ACERP ACERSCAN_620U 0x2060 Acerscan 620U product ACERP ACERSCAN_1240U 0x20c0 Acerscan 1240U product ACERP AWL300 0x9000 AWL300 Wireless adapter product ACERP AWL400 0x9001 AWL400 Wireless adapter /* ActiveWire, Inc. products */ product ACTIVEWIRE IOBOARD 0x0100 I/O Board product ACTIVEWIRE IOBOARD_FW1 0x0101 I/O Board, rev. 1 firmware /* Actiontec, Inc. products */ product ACTIONTEC UAT1 0x7605 UAT1 Wireless Ethernet /* ADMtek products */ product ADMTEK PEGASUS 0x0986 AN986 Ethernet product ADMTEK PEGASUSII 0x8511 AN8511 Ethernet product ADMTEK PEGASUSII_2 0x8513 AN8513 Ethernet /* ADS products */ product ADS UBS10BT 0x0008 UBS-10BT Ethernet /* Agate Technologies products */ product AGATE QDRIVE 0x0378 Q-Drive /* AGFA products */ product AGFA SNAPSCAN1212U 0x0001 SnapScan 1212U product AGFA SNAPSCAN1236U 0x0002 SnapScan 1236U product AGFA SNAPSCANTOUCH 0x0100 SnapScan Touch product AGFA SNAPSCAN1212U2 0x2061 SnapScan 1212U product AGFA SNAPSCANE40 0x208d SnapScan e40 product AGFA SNAPSCANE50 0x208f SnapScan e50 product AGFA SNAPSCANE20 0x2091 SnapScan e20 product AGFA SNAPSCANE25 0x2095 SnapScan e25 product AGFA SNAPSCANE26 0x2097 SnapScan e26 product AGFA SNAPSCANE52 0x20fd SnapScan e52 /* Ain Communication Technology products */ product AINCOMM AWU2000B 0x1001 AWU2000B Wireless adapter /* AKS products */ product AKS USBHASP 0x0001 USB-HASP 0.06 /* Alcor Micro, Inc. products */ product ALCOR2 KBD_HUB 0x2802 Kbd Hub product ALCOR MA_KBD_HUB 0x9213 MacAlly Kbd Hub product ALCOR AU9814 0x9215 AU9814 Hub product ALCOR SM_KBD 0x9410 MicroConnectors/StrongMan Keyboard product ALCOR NEC_KBD_HUB 0x9472 NEC Kbd Hub /* Altec Lansing products */ product ALTEC ADA70 0x0070 ADA70 Speakers product ALTEC ASC495 0xff05 ASC495 Speakers /* American Power Conversion products */ product APC UPS 0x0002 Uninterruptible Power Supply /* Anchor products */ product ANCHOR EZUSB 0x2131 EZUSB product ANCHOR EZLINK 0x2720 EZLINK /* AOX, Inc. products */ product AOX USB101 0x0008 Ethernet /* Apple Computer products */ product APPLE OPTMOUSE 0x0302 Optical mouse product APPLE SPEAKERS 0x1101 Speakers product APPLE IPOD 0x1201 iPod product APPLE IPOD2G 0x1202 iPod 2G product APPLE IPOD3G 0x1203 iPod 3G product APPLE IPOD_04 0x1204 iPod "04" product APPLE IPODMINI 0x1205 iPod Mini product APPLE IPOD_06 0x1206 iPod "06" product APPLE IPOD_07 0x1207 iPod "07" product APPLE IPOD_08 0x1208 iPod "08" product APPLE IPODVIDEO 0x1209 iPod Video product APPLE IPODNANO 0x120a iPod Nano /* Asahi Optical products */ product ASAHIOPTICAL OPTIO230 0x0004 Digital camera product ASAHIOPTICAL OPTIO330 0x0006 Digital camera /* ASIX Electronics products */ product ASIX AX88172 0x1720 10/100 ethernet /* ASUS products */ product ASUS WL167G 0x1707 WL-167g wireless adapter /* ATen products */ product ATEN UC1284 0x2001 Parallel printer product ATEN UC10T 0x2002 10Mbps ethernet product ATEN UC232A 0x2008 Serial /* Atmel Comp. products */ product ATMEL UHB124 0x3301 UHB124 hub product ATMEL DWL120 0x7603 DWL-120 Wireless adapter product ATMEL BW002 0x7605 BW002 Wireless adapter product ATMEL WL1130USB 0x7613 WL-1130 USB product ATMEL AT76C505A 0x7614 AT76c505a Wireless adapter /* Avision products */ product AVISION 1200U 0x0268 1200U scanner /* B&B Electronics products */ product BBELECTRONICS USOTL4 0xAC01 RS-422/485 /* Belkin products */ /*product BELKIN F5U111 0x???? F5U111 Ethernet*/ product BELKIN2 F5U002 0x0002 F5U002 Parallel printer product BELKIN USB2LAN 0x0121 USB to LAN product BELKIN F5U103 0x0103 F5U103 Serial product BELKIN F5U109 0x0109 F5U109 Serial product BELKIN F5U208 0x0208 F5U208 VideoBus II product BELKIN F5U409 0x0409 F5U409 Serial product BELKIN F5U120 0x1203 F5U120-PC Hub product BELKIN F5D7050 0x7050 F5D7050 wireless adapter /* Billionton products */ product BILLIONTON USB100 0x0986 USB100N 10/100 FastEthernet product BILLIONTON USBLP100 0x0987 USB100LP product BILLIONTON USBEL100 0x0988 USB100EL product BILLIONTON USBE100 0x8511 USBE100 /* Broadcom products */ product BROADCOM BCM2033 0x2033 BCM2033 Bluetooth USB dongle /* Brother Industries products */ product BROTHER HL1050 0x0002 HL-1050 laser printer /* Behavior Technology Computer products */ product BTC BTC7932 0x6782 Keyboard with mouse port /* Canon, Inc. products */ product CANON N656U 0x2206 CanoScan N656U product CANON N1220U 0x2207 CanoScan N1220U product CANON D660U 0x2208 CanoScan D660U product CANON N676U 0x220d CanoScan N676U product CANON N1240U 0x220e CanoScan N1240U product CANON LIDE25 0x2220 CanoScan LIDE 25 product CANON S10 0x3041 PowerShot S10 product CANON S100 0x3045 PowerShot S100 product CANON S200 0x3065 PowerShot S200 /* CATC products */ product CATC NETMATE 0x000a Netmate ethernet product CATC NETMATE2 0x000c Netmate2 ethernet product CATC CHIEF 0x000d USB Chief Bus & Protocol Analyzer product CATC ANDROMEDA 0x1237 Andromeda hub /* CASIO products */ product CASIO NAMELAND 0x4001 CASIO Nameland EZ-USB /* Cherry products */ product CHERRY MY3000KBD 0x0001 My3000 keyboard product CHERRY MY3000HUB 0x0003 My3000 hub product CHERRY CYBOARD 0x0004 CyBoard Keyboard /* Chic Technology products */ product CHIC MOUSE1 0x0001 mouse product CHIC CYPRESS 0x0003 Cypress USB Mouse /* Chicony products */ product CHICONY KB8933 0x0001 KB-8933 keyboard /* Compaq products */ product COMPAQ PJB100 0x504a Personal Jukebox PJB100 /* Connectix products */ product CONNECTIX QUICKCAM 0x0001 QuickCam /* Corega products */ product COREGA ETHER_USB_T 0x0001 Ether USB-T product COREGA FETHER_USB_TX 0x0004 FEther USB-TX product COREGA FETHER_USB_TXS 0x000d FEther USB-TXS product COREGA FETHER_USB_TXC 0x9601 FEther USB-TXC /* Creative products */ product CREATIVE NOMAD_II 0x1002 Nomad II MP3 player /* Crystalfontz products */ product FTDI CFA_631 0xfc0c Crystalfontz CFA-631 USB LCD product FTDI CFA_632 0xfc08 Crystalfontz CFA-632 USB LCD product FTDI CFA_633 0xfc0b Crystalfontz CFA-633 USB LCD product FTDI CFA_634 0xfc09 Crystalfontz CFA-634 USB LCD product FTDI SEMC_DSS20 0xfc82 SEMC DSS-20 SyncStation /* Cambridge Silicon Radio Ltd. products */ product CSR BT_DONGLE 0x0001 Bluetooth USB dongle product CSR CSRDFU 0xffff USB Bluetooth Device in DFU State /* Conceptronic products */ product CONCEPTRONIC C54U 0x3c02 C54U wireless adapter /* CTX products */ product CTX EX1300 0x9999 Ex1300 hub /* Cypress Semiconductor products */ product CYPRESS MOUSE 0x0001 mouse product CYPRESS THERMO 0x0002 thermometer product CYPRESS FMRADIO 0x1002 FM Radio product CYPRESS SLIM_HUB 0x6560 Slim Hub /* Daisy Technology products */ product DAISY DMC 0x6901 USB MultiMedia Reader /* Dallas Semiconductor products */ product DALLAS J6502 0x4201 J-6502 speakers /* Dell products */ product DELL PORT 0x0058 Port Replicator product DELL BC02 0x8000 BC02 Bluetooth USB Adapter /* Delorme Paublishing products */ product DELORME EARTHMATE 0x0100 Earthmate GPS /* Diamond products */ product DIAMOND RIO500USB 0x0001 Rio 500 USB /* Digi International products */ product DIGI ACCELEPORT2 0x0002 AccelePort USB 2 product DIGI ACCELEPORT4 0x0004 AccelePort USB 4 product DIGI ACCELEPORT8 0x0008 AccelePort USB 8 /* D-Link products */ /*product DLINK DSBS25 0x0100 DSB-S25 serial*/ product DLINK DUBE100 0x1a00 10/100 ethernet product DLINK DSB650TX4 0x200c 10/100 ethernet product DLINK DWLG122 0x3c00 DWL-G122 b1 wireless adapter product DLINK DSB650C 0x4000 10Mbps ethernet product DLINK DSB650TX1 0x4001 10/100 ethernet product DLINK DSB650TX 0x4002 10/100 ethernet product DLINK DSB650TX_PNA 0x4003 1/10/100 ethernet product DLINK DSB650TX3 0x400b 10/100 ethernet product DLINK DSB650TX2 0x4102 10/100 ethernet product DLINK DSB650 0xabc1 10/100 ethernet /* EIZO products */ product EIZO HUB 0x0000 hub product EIZO MONITOR 0x0001 monitor /* Elecom products */ product ELECOM MOUSE29UO 0x0002 mouse 29UO product ELECOM LDUSBTX0 0x200c LD-USB/TX product ELECOM LDUSBTX1 0x4002 LD-USB/TX product ELECOM LDUSBLTX 0x4005 LD-USBL/TX product ELECOM LDUSBTX2 0x400b LD-USB/TX product ELECOM UCSGT 0x5003 UC-SGT product ELECOM UCSGT0 0x5004 UC-SGT product ELECOM LDUSBTX3 0xabc1 LD-USB/TX /* Elsa products */ product ELSA MODEM1 0x2265 ELSA Modem Board product ELSA USB2ETHERNET 0x3000 Microlink USB2Ethernet /* EMS products */ product EMS DUAL_SHOOTER 0x0003 PSX gun controller converter /* Entrega products */ product ENTREGA 1S 0x0001 1S serial product ENTREGA 2S 0x0002 2S serial product ENTREGA 1S25 0x0003 1S25 serial product ENTREGA 4S 0x0004 4S serial product ENTREGA E45 0x0005 E45 Ethernet product ENTREGA CENTRONICS 0x0006 Parallel Port product ENTREGA 1S9 0x0093 1S9 serial product ENTREGA EZUSB 0x8000 EZ-USB /*product ENTREGA SERIAL 0x8001 DB25 Serial*/ product ENTREGA 2U4S 0x8004 2U4S serial/usb hub /*product ENTREGA SERIAL_DB9 0x8093 DB9 Serial*/ /* Epson products */ product EPSON PRINTER1 0x0001 USB Printer product EPSON PRINTER2 0x0002 ISD USB Smart Cable for Mac product EPSON PRINTER3 0x0003 ISD USB Smart Cable product EPSON PRINTER5 0x0005 USB Printer product EPSON 636 0x0101 Perfection 636U / 636Photo scanner product EPSON 610 0x0103 Perfection 610 scanner product EPSON 1200 0x0104 Perfection 1200U / 1200Photo scanner product EPSON 1600 0x0107 Expression 1600 scanner product EPSON 1640 0x010a Perfection 1640SU scanner product EPSON 1240 0x010b Perfection 1240U / 1240Photo scanner product EPSON 640U 0x010c Perfection 640U scanner product EPSON 1250 0x010f Perfection 1250U / 1250Photo scanner product EPSON 1650 0x0110 Perfection 1650 scanner product EPSON GT9700F 0x0112 GT-9700F scanner product EPSON GT9300UF 0x011b GT-9300UF scanner product EPSON 3200 0x011c Perfection 3200 scanner product EPSON 1260 0x011d Perfection 1260 scanner product EPSON 1660 0x011e Perfection 1660 scanner product EPSON 1670 0x011f Perfection 1670 scanner product EPSON 2480 0x0121 Perfection 2480 scanner /* e-TEK Labs products */ product ETEK 1COM 0x8007 Serial /* Extended Systems products */ product EXTENDED XTNDACCESS 0x0100 XTNDAccess IrDA /* GoHubs products */ product GOHUBS GOCOM232 0x1001 GoCOM232 Serial /* Gravis products */ product GRAVIS GAMEPADPRO 0x4001 GamePad Pro /* GREENHOUSE products */ product GREENHOUSE KANA21 0x0001 CF-writer with MP3 /* Griffin Technology */ product GRIFFIN IMATE 0x0405 iMate, ADB adapter /* Freecom products */ product FREECOM DVD 0xfc01 DVD drive /* Future Technology Devices products */ product FTDI SERIAL_8U100AX 0x8372 8U100AX Serial product FTDI SERIAL_8U232AM 0x6001 8U232AM Serial product FTDI SERIAL_2232C 0x6010 FT2232C Dual port Serial /* Fuji photo products */ product FUJIPHOTO MASS0100 0x0100 Mass Storage /* Fujitsu protducts */ product FUJITSU AH_F401U 0x105b AH-F401U Air H device /* General Instruments (Motorola) products */ product GENERALINSTMNTS SB5100 0x5100 SURFboard SB5100 Cable modem /* Genesys Logic products */ product GENESYS GL650 0x0604 GL650 Hub product GENESYS GL641USB 0x0700 GL641USB CompactFlash Card Reader product GENESYS GL641USB2IDE_2 0x0701 GL641USB USB-IDE Bridge No 2 product GENESYS GL641USB2IDE 0x0702 GL641USB USB-IDE Bridge +product GENESYS GL641USB_2 0x0760 GL641USB 6-in-1 Card Reader /* GIGABYTE products */ product GIGABYTE GNBR402W 0x8002 GN-BR402W product GIGABYTE GNWLBM101 0x8003 GN-WLBM101 product GIGABYTE GNWBKG 0x8007 GN-WBKG /* G.Mate, Inc products */ product GMATE YP3X00 0x1001 YP3X00 PDA /* Guillemot Corporation */ product GUILLEMOT DALEADER 0xa300 DA Leader product GUILLEMOT HWGUSB254 0xe000 HWGUSB2-54 WLAN /* HAL Corporation products */ product HAL IMR001 0x0011 Crossam2+USB IR commander /* Hagiwara products */ product HAGIWARA FGSM 0x0002 FlashGate SmartMedia Card Reader product HAGIWARA FGCF 0x0003 FlashGate CompactFlash Card Reader product HAGIWARA FG 0x0005 FlashGate /* Handspring, Inc. */ product HANDSPRING VISOR 0x0100 Handspring Visor product HANDSPRING TREO 0x0200 Handspring Treo product HANDSPRING TREO600 0x0300 Handspring Treo 600 /* Hauppauge Computer Works */ product HAUPPAUGE WINTV_USB_FM 0x4d12 WinTV USB FM /* Hawking Technologies products */ product HAWKING UF100 0x400c 10/100 USB Ethernet /* Hitachi, Ltd. products */ product HITACHI DVDCAM_USB 0x001e DVDCAM USB HS Interface /* HP products */ product HP 895C 0x0004 DeskJet 895C product HP 4100C 0x0101 Scanjet 4100C product HP S20 0x0102 Photosmart S20 product HP 880C 0x0104 DeskJet 880C product HP 4200C 0x0105 ScanJet 4200C product HP CDWRITERPLUS 0x0107 CD-Writer Plus product HP KBDHUB 0x010c Multimedia Keyboard Hub product HP G55XI 0x0111 OfficeJet G55xi product HP HN210W 0x011c HN210W 802.11b WLAN product HP 49GPLUS 0x0121 49g+ graphing calculator product HP 6200C 0x0201 ScanJet 6200C product HP S20b 0x0202 PhotoSmart S20 product HP 815C 0x0204 DeskJet 815C product HP 3300C 0x0205 ScanJet 3300C product HP CDW8200 0x0207 CD-Writer Plus 8200e product HP MMKEYB 0x020c Multimedia keyboard product HP 1220C 0x0212 DeskJet 1220C product HP 810C 0x0304 DeskJet 810C/812C product HP 4300C 0x0305 Scanjet 4300C product HP G85XI 0x0311 OfficeJet G85xi product HP 1200 0x0317 LaserJet 1200 product HP 5200C 0x0401 Scanjet 5200C product HP 830C 0x0404 DeskJet 830C product HP 3400CSE 0x0405 ScanJet 3400cse product HP 6300C 0x0601 Scanjet 6300C product HP 840C 0x0604 DeskJet 840c product HP 2200C 0x0605 ScanJet 2200C product HP 5300C 0x0701 Scanjet 5300C product HP 4400C 0x0705 Scanjet 4400C product HP 82x0C 0x0b01 Scanjet 82x0C product HP 2300D 0x0b17 Laserjet 2300d product HP 970CSE 0x1004 Deskjet 970Cse product HP 5400C 0x1005 Scanjet 5400C product HP 930C 0x1204 DeskJet 930c product HP P2000U 0x1801 Inkjet P-2000U product HP 640C 0x2004 DeskJet 640c product HP 4670V 0x3005 ScanJet 4670v product HP P1100 0x3102 Photosmart P1100 product HP HN210E 0x811c Ethernet HN210E /* HP products */ product HP2 C500 0x6002 PhotoSmart C500 /* IBM Corporation */ product IBM USBCDROMDRIVE 0x4427 USB CD-ROM Drive /* Imagination Technologies products */ product IMAGINATION DBX1 0x2107 DBX1 DSP core /* Inside Out Networks products */ product INSIDEOUT EDGEPORT4 0x0001 EdgePort/4 serial ports /* In-System products */ product INSYSTEM F5U002 0x0002 Parallel printer product INSYSTEM ATAPI 0x0031 ATAPI adapter product INSYSTEM ISD110 0x0200 IDE adapter ISD110 product INSYSTEM ISD105 0x0202 IDE adapter ISD105 product INSYSTEM USBCABLE 0x081a USB cable /* Intel products */ product INTEL EASYPC_CAMERA 0x0110 Easy PC Camera product INTEL TESTBOARD 0x9890 82930 test board /* Intersil products */ product INTERSIL PRISM_2X 0x3642 Prism2.x or Atmel WLAN /* Interpid Control Systems products */ product INTREPIDCS VALUECAN 0x0601 ValueCAN CAN bus interface product INTREPIDCS NEOVI 0x0701 NeoVI Blue vehicle bus interface /* I/O DATA products */ product IODATA IU_CD2 0x0204 DVD Multi-plus unit iU-CD2 product IODATA DVR_UEH8 0x0206 DVD Multi-plus unit DVR-UEH8 product IODATA USBETT 0x0901 USB ETT product IODATA USBETTX 0x0904 USB ETTX product IODATA USBETTXS 0x0913 USB ETTX product IODATA USBRSAQ 0x0a03 Serial USB-RSAQ1 /* Iomega products */ product IOMEGA ZIP100 0x0001 Zip 100 product IOMEGA ZIP250 0x0030 Zip 250 /* JVC products */ product JVC GR_DX95 0x000a GR-DX95 product JVC MP_PRX1 0x3008 MP-PRX1 Ethernet /* JRC products */ product JRC AH_J3001V_J3002V 0x0001 AirH\" PHONE AH-J3001V/J3002V /* Kawasaki products */ product KLSI DUH3E10BT 0x0008 USB ethernet product KLSI DUH3E10BTN 0x0009 USB ethernet /* Kawatsu products */ product KAWATSU MH4000P 0x0003 MiniHub 4000P /* Keisokugiken Corp. products */ product KEISOKUGIKEN USBDAQ 0x0068 HKS-0200 USBDAQ /* Kawasaki products */ product KLSI DUH3E10BT 0x0008 DU-H3E 10BT Ethernet /* Kensington products */ product KENSINGTON ORBIT 0x1003 Orbit USB/PS2 trackball product KENSINGTON TURBOBALL 0x1005 TurboBall /* Keyspan products */ product KEYSPAN USA28 0x0101 USA-28 serial product KEYSPAN USA28X 0x0102 USA-28X serial product KEYSPAN USA19 0x0103 USA-19 serial product KEYSPAN USA18X 0x0105 USA-18X serial product KEYSPAN USA19W 0x0106 USA-19W serial product KEYSPAN USA49W 0x0109 USA-49W serial product KEYSPAN USA19QW 0x0118 USA-19QW serial /* Kingston products */ product KINGSTON KNU101TX 0x000a KNU101TX USB Ethernet /* Kodak products */ product KODAK DC220 0x0100 Digital Science DC220 product KODAK DC260 0x0110 Digital Science DC260 product KODAK DC265 0x0111 Digital Science DC265 product KODAK DC290 0x0112 Digital Science DC290 product KODAK DC240 0x0120 Digital Science DC240 product KODAK DC280 0x0130 Digital Science DC280 /* Konica Corp. Products */ product KONICA CAMERA 0x0720 Digital Color Camera /* KYE products */ product KYE NICHE 0x0001 Niche mouse product KYE NETSCROLL 0x0003 Genius NetScroll mouse product KYE FLIGHT2000 0x1004 Flight 2000 joystick product KYE VIVIDPRO 0x2001 ColorPage Vivid-Pro scanner /* Kyocera products */ product KYOCERA AHK3001V 0x0203 AH-K3001V /* LaCie products */ product LACIE HD 0xa601 Hard Disk product LACIE CDRW 0xa602 CD R/W /* Lexar products */ product LEXAR JUMPSHOT 0x0001 jumpSHOT CompactFlash Reader /* Lexmark products */ product LEXMARK S2450 0x0009 Optra S 2450 /* Linksys products */ product LINKSYS MAUSB2 0x0105 Camedia MAUSB-2 product LINKSYS USB10TX1 0x200c USB10TX product LINKSYS USB10T 0x2202 USB10T Ethernet product LINKSYS USB100TX 0x2203 USB100TX Ethernet product LINKSYS USB100H1 0x2204 USB100H1 Ethernet/HPNA product LINKSYS USB10TA 0x2206 USB10TA Ethernet product LINKSYS USB10TX2 0x400b USB10TX product LINKSYS2 WUSB11 0x2219 WUSB11 Wireless adapter product LINKSYS2 USB200M 0x2226 USB 2.0 10/100 ethernet product LINKSYS3 WUSB11v28 0x2233 WUSB11 v2.8 wireless adapter product LINKSYS4 WUSB54G 0x000d WUSB54G wireless adapter product LINKSYS4 WUSB54GP 0x0011 WUSB54GP wireless adapter product LINKSYS4 HU200TS 0x001a HU200TS wireless adapter /* Logitech products */ product LOGITECH M2452 0x0203 M2452 keyboard product LOGITECH M4848 0x0301 M4848 mouse product LOGITECH PAGESCAN 0x040f PageScan product LOGITECH QUICKCAMWEB 0x0801 QuickCam Web product LOGITECH QUICKCAMPRO 0x0810 QuickCam Pro product LOGITECH QUICKCAMEXP 0x0840 QuickCam Express product LOGITECH QUICKCAM 0x0850 QuickCam product LOGITECH N43 0xc000 N43 product LOGITECH N48 0xc001 N48 mouse product LOGITECH MBA47 0xc002 M-BA47 mouse product LOGITECH WMMOUSE 0xc004 WingMan Gaming Mouse product LOGITECH BD58 0xc00c BD58 mouse product LOGITECH UN58A 0xc030 iFeel Mouse product LOGITECH BB13 0xc401 USB-PS/2 Trackball product LOGITECH WMPAD 0xc208 WingMan GamePad Extreme product LOGITECH WMRPAD 0xc20a WingMan RumblePad product LOGITECH WMJOY 0xc281 WingMan Force joystick product LOGITECH RK53 0xc501 Cordless mouse product LOGITECH RB6 0xc503 Cordless keyboard product LOGITECH MX700 0xc506 Cordless optical mouse product LOGITECH QUICKCAMPRO2 0xd001 QuickCam Pro /* Logitec Corp. products */ product LOGITEC LDR_H443SU2 0x0033 DVD Multi-plus unit LDR-H443SU2 product LOGITEC LDR_H443U2 0x00b3 DVD Multi-plus unit LDR-H443U2 /* Lucent products */ product LUCENT EVALKIT 0x1001 USS-720 evaluation kit /* Luwen products */ product LUWEN EASYDISK 0x0005 EasyDisc /* Macally products */ product MACALLY MOUSE1 0x0101 mouse /* Matrix Orbital products */ product FTDI USBSERIAL 0xfa00 Matrix Orbital USB Serial product FTDI MX2_3 0xfa01 Matrix Orbital MX2 or MX3 product FTDI MX4_5 0xfa02 Matrix Orbital MX4 or MX5 product FTDI LK202 0xfa03 Matrix Orbital VK/LK202 Family product FTDI LK204 0xfa04 Matrix Orbital VK/LK204 Family /* MCT Corp. */ product MCT HUB0100 0x0100 Hub product MCT DU_H3SP_USB232 0x0200 D-Link DU-H3SP USB BAY Hub product MCT USB232 0x0210 USB-232 Interface product MCT SITECOM_USB232 0x0230 Sitecom USB-232 Products /* Melco, Inc products */ product MELCO LUATX1 0x0001 LUA-TX Ethernet product MELCO LUATX5 0x0005 LUA-TX Ethernet product MELCO LUA2TX5 0x0009 LUA2-TX Ethernet product MELCO LUAKTX 0x0012 LUA-KTX Ethernet product MELCO DUBPXXG 0x001c USB-IDE Bridge: DUB-PxxG product MELCO LUAU2KTX 0x003d LUA-U2-KTX Ethernet product MELCO KG54YB 0x005e WLI-U2-KG54-YB WLAN product MELCO KG54 0x0066 WLI-U2-KG54 WLAN product MELCO KG54AI 0x0067 WLI-U2-KG54-AI WLAN product MELCO NINWIFI 0x008b Nintendo Wi-Fi /* Metricom products */ product METRICOM RICOCHET_GS 0x0001 Ricochet GS /* MGE UPS Systems */ product MGE UPS1 0x0001 MGE UPS SYSTEMS PROTECTIONCENTER 1 product MGE UPS2 0xffff MGE UPS SYSTEMS PROTECTIONCENTER 2 /* Micro Star International products */ product MSI BT_DONGLE 0x1967 Bluetooth USB dongle product MSI RT2570 0x6861 RT2570 product MSI RT2570_2 0x6865 RT2570 product MSI RT2570_3 0x6869 RT2570 /* Microsoft products */ product MICROSOFT SIDEPREC 0x0008 SideWinder Precision Pro product MICROSOFT INTELLIMOUSE 0x0009 IntelliMouse product MICROSOFT NATURALKBD 0x000b Natural Keyboard Elite product MICROSOFT DDS80 0x0014 Digital Sound System 80 product MICROSOFT SIDEWINDER 0x001a Sidewinder Precision Racing Wheel product MICROSOFT INETPRO 0x001c Internet Keyboard Pro product MICROSOFT INTELLIEYE 0x0025 IntelliEye mouse product MICROSOFT INETPRO2 0x002b Internet Keyboard Pro product MICROSOFT MN110 0x007a 10/100 USB NIC /* Microtech products */ product MICROTECH SCSIDB25 0x0004 USB-SCSI-DB25 product MICROTECH SCSIHD50 0x0005 USB-SCSI-HD50 product MICROTECH DPCM 0x0006 USB CameraMate product MICROTECH FREECOM 0xfc01 Freecom USB-IDE /* Microtek products */ product MICROTEK 336CX 0x0094 Phantom 336CX - C3 scanner product MICROTEK X6U 0x0099 ScanMaker X6 - X6U product MICROTEK C6 0x009a Phantom C6 scanner product MICROTEK 336CX2 0x00a0 Phantom 336CX - C3 scanner product MICROTEK V6USL 0x00a3 ScanMaker V6USL product MICROTEK V6USL2 0x80a3 ScanMaker V6USL product MICROTEK V6UL 0x80ac ScanMaker V6UL /* Microtune, Inc. products */ product MICROTUNE BT_DONGLE 0x1000 Bluetooth USB dongle /* Midiman products */ product MIDIMAN MIDISPORT2X2 0x1001 Midisport 2x2 /* Minolta Co., Ltd. */ product MINOLTA 2300 0x4001 Dimage 2300 product MINOLTA S304 0x4007 Dimage S304 product MINOLTA X 0x4009 Dimage X product MINOLTA 5400 0x400e Dimage 5400 /* Mitsumi products */ product MITSUMI CDRRW 0x0000 CD-R/RW Drive product MITSUMI BT_DONGLE 0x641f Bluetooth USB dongle /* Motorola products */ product MOTOROLA MC141555 0x1555 MC141555 hub controller product MOTOROLA SB4100 0x4100 SB4100 USB Cable Modem product MOTOROLA2 E398 0x4810 E398 Mobile Phone /* MultiTech products */ product MULTITECH ATLAS 0xf101 MT5634ZBA-USB modem /* Mustek products */ product MUSTEK 1200CU 0x0001 1200 CU scanner product MUSTEK 600CU 0x0002 600 CU scanner product MUSTEK 1200USB 0x0003 1200 USB scanner product MUSTEK 1200UB 0x0006 1200 UB scanner product MUSTEK 1200USBPLUS 0x0007 1200 USB Plus scanner product MUSTEK 1200CUPLUS 0x0008 1200 CU Plus scanner product MUSTEK BEARPAW1200F 0x0010 BearPaw 1200F scanner product MUSTEK BEARPAW1200TA 0x021e BearPaw 1200TA scanner product MUSTEK 600USB 0x0873 600 USB scanner product MUSTEK MDC800 0xa800 MDC-800 digital camera /* M-Systems products */ product MSYSTEMS DISKONKEY 0x0010 DiskOnKey product MSYSTEMS DISKONKEY2 0x0011 DiskOnKey /* National Semiconductor */ product NATIONAL BEARPAW1200 0x1000 BearPaw 1200 product NATIONAL BEARPAW2400 0x1001 BearPaw 2400 /* NEC products */ product NEC HUB 0x55aa hub product NEC HUB_B 0x55ab hub /* NEODIO products */ product NEODIO ND3260 0x3260 8-in-1 Multi-format Flash Controller product NEODIO ND5010 0x5010 Multi-format Flash Controller /* NetChip Technology Products */ product NETCHIP TURBOCONNECT 0x1080 Turbo-Connect product NETCHIP ETHERNETGADGET 0xa4a2 Linux Ethernet/RNDIS gadget on pxa210/25x/26x /* Netgear products */ product NETGEAR EA101 0x1001 Ethernet product NETGEAR FA120 0x1040 USB 2.0 Ethernet /* Nikon products */ product NIKON E990 0x0102 Digital Camera E990 product NIKON LS40 0x4000 CoolScan LS40 ED /* Olympus products */ product OLYMPUS C1 0x0102 C-1 Digital Camera product OLYMPUS C700 0x0105 C-700 Ultra Zoom /* OmniVision Technologies, Inc. products */ product OMNIVISION OV511 0x0511 OV511 Camera product OMNIVISION OV511PLUS 0xa511 OV511+ Camera /* OnSpec Electronic, Inc. */ product ONSPEC UCF100 0xa400 FlashLink UCF-100 CompactFlash Reader /* Palm Computing, Inc. product */ product PALM SERIAL 0x0080 USB Serial product PALM M500 0x0001 Palm m500 product PALM M505 0x0002 Palm m505 product PALM M515 0x0003 Palm m515 product PALM I705 0x0020 Palm i705 product PALM TUNGSTEN_Z 0x0031 Palm Tungsten Z product PALM M125 0x0040 Palm m125 product PALM M130 0x0050 Palm m130 product PALM TUNGSTEN_T 0x0060 Palm Tungsten T product PALM ZIRE31 0x0061 Palm Zire 31 product PALM ZIRE 0x0070 Palm Zire /* Panasonic products */ product PANASONIC KXLRW32AN 0x0d09 CD-R Drive KXL-RW32AN product PANASONIC KXLCB20AN 0x0d0a CD-R Drive KXL-CB20AN product PANASONIC KXLCB35AN 0x0d0e DVD-ROM & CD-R/RW product PANASONIC SDCAAE 0x1b00 MultiMediaCard /* Peracom products */ product PERACOM SERIAL1 0x0001 Serial product PERACOM ENET 0x0002 Ethernet product PERACOM ENET3 0x0003 At Home Ethernet product PERACOM ENET2 0x0005 Ethernet /* Philips products */ product PHILIPS DSS350 0x0101 DSS 350 Digital Speaker System product PHILIPS DSS 0x0104 DSS XXX Digital Speaker System product PHILIPS HUB 0x0201 hub product PHILIPS PCA646VC 0x0303 PCA646VC PC Camera product PHILIPS PCVC680K 0x0308 PCVC680K Vesta Pro PC Camera product PHILIPS DSS150 0x0471 DSS 150 Digital Speaker System product PHILIPS UM10016 0x1552 ISP 1581 Hi-Speed USB MPEG2 Encoder Reference Kit product PHILIPS DIVAUSB 0x1801 DIVA USB mp3 player /* Philips Semiconductor products */ product PHILIPSSEMI HUB1122 0x1122 hub /* P.I. Engineering products */ product PIENGINEERING PS2USB 0x020b PS2 to Mac USB Adapter /* Plextor Corp. */ product PLEXTOR 40_12_40U 0x0011 PlexWriter 40/12/40U /* PLX products */ product PLX TESTBOARD 0x9060 test board /* PNY products */ product PNY ATTACHE 0x1300 USB 2.0 Flash Drive product PNY A256MB 0x1400 Attache 256MB USB 2.0 Flash Drive product PNY DISKPRO512 0x1420 USB 2.0 Flash Drive (DANE-ELEC zMate 512MB USB flash drive) /* Primax products */ product PRIMAX G2X300 0x0300 G2-200 scanner product PRIMAX G2E300 0x0301 G2E-300 scanner product PRIMAX G2300 0x0302 G2-300 scanner product PRIMAX G2E3002 0x0303 G2E-300 scanner product PRIMAX 9600 0x0340 Colorado USB 9600 scanner product PRIMAX 600U 0x0341 Colorado 600u scanner product PRIMAX 6200 0x0345 Visioneer 6200 scanner product PRIMAX 19200 0x0360 Colorado USB 19200 scanner product PRIMAX 1200U 0x0361 Colorado 1200u scanner product PRIMAX G600 0x0380 G2-600 scanner product PRIMAX 636I 0x0381 ReadyScan 636i product PRIMAX G2600 0x0382 G2-600 scanner product PRIMAX G2E600 0x0383 G2E-600 scanner product PRIMAX COMFORT 0x4d01 Comfort product PRIMAX MOUSEINABOX 0x4d02 Mouse-in-a-Box product PRIMAX PCGAUMS1 0x4d04 Sony PCGA-UMS1 /* Prolific products */ product PROLIFIC PL2301 0x0000 PL2301 Host-Host interface product PROLIFIC PL2302 0x0001 PL2302 Host-Host interface product PROLIFIC RSAQ2 0x04bb PL2303 Serial (IODATA USB-RSAQ2) product PROLIFIC PL2303 0x2303 PL2303 Serial (ATEN/IOGEAR UC232A) product PROLIFIC PL2305 0x2305 Parallel printer product PROLIFIC ATAPI4 0x2307 ATAPI-4 Controller product PROLIFIC PL2501 0x2501 PL2501 Host-Host interface product PROLIFIC RSAQ3 0xaaa2 PL2303 Serial adapter (IODATA USB-RSAQ3) /* Putercom products */ product PUTERCOM UPA100 0x047e USB-1284 BRIDGE /* Qualcomm products */ product QUALCOMM CDMA_MSM 0x3196 CDMA Technologies MSM modem product QUALCOMM2 CDMA_MSM 0x6000 CDMA Technologies MSM phone /* Qtronix products */ product QTRONIX 980N 0x2011 Scorpion-980N keyboard /* Quickshot products */ product QUICKSHOT STRIKEPAD 0x6238 USB StrikePad /* Rainbow Technologies products */ product RAINBOW IKEY2000 0x1200 i-Key 2000 /* Ralink Technology products */ product RALINK RT2570 0x1706 RT2500USB wireless adapter product RALINK RT2570_2 0x2570 RT2500USB wireless adapter /* ReakTek products */ product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet (GREEN HOUSE) /* Roland products */ product ROLAND UM1 0x0009 UM-1 MIDI I/F product ROLAND UM880N 0x0014 EDIROL UM-880 MIDI I/F (native) product ROLAND UM880G 0x0015 EDIROL UM-880 MIDI I/F (generic) /* Rockfire products */ product ROCKFIRE GAMEPAD 0x2033 gamepad 203USB /* RATOC Systems products */ product RATOC REXUSB60 0xb000 REX-USB60 /* Samsung products */ product SAMSUNG ML6060 0x3008 ML-6060 laser printer /* SanDisk products */ product SANDISK SDDR05A 0x0001 ImageMate SDDR-05a product SANDISK SDDR05 0x0005 ImageMate SDDR-05 product SANDISK SDDR31 0x0002 ImageMate SDDR-31 product SANDISK SDDR12 0x0100 ImageMate SDDR-12 product SANDISK SDDR09 0x0200 ImageMate SDDR-09 product SANDISK SDDR75 0x0810 ImageMate SDDR-75 product SANDISK SDCZ2_256 0x7104 Cruzer Mini 256MB product SANDISK SDCZ4_128 0x7112 Cruzer Micro 128MB product SANDISK SDCZ4_256 0x7113 Cruzer Micro 256MB /* Sanyo Electric products */ product SANYO SCP4900 0x0701 Sanyo SCP-4900 USB Phone /* ScanLogic products */ product SCANLOGIC SL11R 0x0002 SL11R IDE Adapter product SCANLOGIC 336CX 0x0300 Phantom 336CX - C3 scanner /* Sharp products */ product SHARP SL5500 0x8004 Zaurus SL-5500 PDA product SHARP SLA300 0x8005 Zaurus SL-A300 PDA product SHARP SL5600 0x8006 Zaurus SL-5600 PDA product SHARP SLC700 0x8007 Zaurus SL-C700 PDA product SHARP SLC750 0x9031 Zaurus SL-C750 PDA /* Shuttle Technology products */ product SHUTTLE EUSB 0x0001 E-USB Bridge product SHUTTLE EUSCSI 0x0002 eUSCSI Bridge product SHUTTLE SDDR09 0x0003 ImageMate SDDR09 product SHUTTLE ZIOMMC 0x0006 eUSB MultiMediaCard Adapter product SHUTTLE HIFD 0x0007 Sony Hifd product SHUTTLE EUSBATAPI 0x0009 eUSB ATA/ATAPI Adapter product SHUTTLE CF 0x000a eUSB CompactFlash Adapter product SHUTTLE EUSCSI_B 0x000b eUSCSI Bridge product SHUTTLE EUSCSI_C 0x000c eUSCSI Bridge product SHUTTLE CDRW 0x0101 CD-RW Device product SHUTTLE EUSBORCA 0x0325 eUSB ORCA Quad Reader /* Siemens products */ product SIEMENS SPEEDSTREAM 0x1001 SpeedStream USB /* Sigmatel products */ product SIGMATEL I_BEAD100 0x8008 i-Bead 100 MP3 Player /* SIIG products */ product SIIG DIGIFILMREADER 0x0004 DigiFilm-Combo Reader product SIIG WINTERREADER 0x0330 WINTERREADER Reader product SIIG2 US2308 0x0421 Serial /* Silicon Portals Inc. */ product SILICONPORTALS YAPPH_NF 0x0200 YAP Phone (no firmware) product SILICONPORTALS YAPPHONE 0x0201 YAP Phone /* Sirius Technologies products */ product SIRIUS ROADSTER 0x0001 NetComm Roadster II 56 USB /* Sitecom products */ product SITECOM LN029 0x182d USB 2.0 Ethernet product SITECOM SERIAL 0x2068 USB to serial cable (v2) /* SmartBridges products */ product SMARTBRIDGES SMARTLINK 0x0001 SmartLink USB ethernet product SMARTBRIDGES SMARTNIC 0x0003 smartNIC 2 PnP ethernet /* SMC products */ product SMC 2102USB 0x0100 10Mbps ethernet product SMC 2202USB 0x0200 10/100 ethernet product SMC 2206USB 0x0201 EZ Connect USB Ethernet product SMC 2862WG 0xee13 EZ Connect wireless adapter product SMC2 2020HUB 0x2020 USB Hub product SMC3 2662WUSB 0xa002 2662W-AR Wireless /* SOHOware products */ product SOHOWARE NUB100 0x9100 10/100 USB Ethernet /* SOLID YEAR products */ product SOLIDYEAR KEYBOARD 0x2101 Solid Year USB keyboard /* SONY products */ product SONY DSC 0x0010 DSC cameras product SONY MSACUS1 0x002d Memorystick MSAC-US1 product SONY HANDYCAM 0x002e Handycam product SONY MSC 0x0032 MSC memory stick slot product SONY CLIE_35 0x0038 Sony Clie v3.5 product SONY CLIE_40 0x0066 Sony Clie v4.0 product SONY CLIE_40_MS 0x006d Sony Clie v4.0 Memory Stick slot product SONY CLIE_S360 0x0095 Sony Clie s360 product SONY CLIE_41_MS 0x0099 Sony Clie v4.1 Memory Stick slot product SONY CLIE_41 0x009a Sony Clie v4.1 product SONY CLIE_NX60 0x00da Sony Clie nx60 product SONY CLIE_TJ37 0x0169 Sony Clie tj37 /* Sony Ericsson products */ product SONYERICSSON DCU10 0x0528 USB Cable /* SOURCENEXT products */ product SOURCENEXT KEIKAI8 0x039f KeikaiDenwa 8 product SOURCENEXT KEIKAI8_CHG 0x012e KeikaiDenwa 8 with charger /* STMicroelectronics products */ product STMICRO COMMUNICATOR 0x7554 USB Communicator /* STSN products */ product STSN STSN0001 0x0001 Internet Access Device /* SUN Corporation products */ product SUNTAC DS96L 0x0003 SUNTAC U-Cable type D2 product SUNTAC PS64P1 0x0005 SUNTAC U-Cable type P1 product SUNTAC VS10U 0x0009 SUNTAC Slipper U product SUNTAC IS96U 0x000a SUNTAC Ir-Trinity product SUNTAC AS64LX 0x000b SUNTAC U-Cable type A3 product SUNTAC AS144L4 0x0011 SUNTAC U-Cable type A4 /* Sun Microsystems products */ product SUN2 KEYBOARD 0x0005 Type 6 USB keyboard /* XXX The above is a North American PC style keyboard possibly */ product SUN2 MOUSE 0x0100 Type 6 USB mouse /* Supra products */ product DIAMOND2 SUPRAEXPRESS56K 0x07da Supra Express 56K modem product DIAMOND2 SUPRA2890 0x0b4a SupraMax 2890 56K Modem product DIAMOND2 RIO600USB 0x5001 Rio 600 USB product DIAMOND2 RIO800USB 0x5002 Rio 800 USB /* System TALKS, Inc. */ product SYSTEMTALKS SGCX2UL 0x1920 SGC-X2UL /* Taugagreining products */ product TAUGA CAMERAMATE 0x0005 CameraMate (DPCM_USB) /* TDK products */ product TDK UPA9664 0x0115 USB-PDC Adapter UPA9664 product TDK UCA1464 0x0116 USB-cdmaOne Adapter UCA1464 product TDK UHA6400 0x0117 USB-PHS Adapter UHA6400 product TDK UPA6400 0x0118 USB-PHS Adapter UPA6400 product TDK BT_DONGLE 0x0309 Bluetooth USB dongle /* TEAC products */ product TEAC FD05PUB 0x0000 FD-05PUB floppy /* Telex Communications products */ product TELEX MIC1 0x0001 Enhanced USB Microphone /* Texas Intel products */ product TI UTUSB41 0x1446 UT-USB41 hub product TI TUSB2046 0x2046 TUSB2046 hub /* Thrustmaster products */ product THRUST FUSION_PAD 0xa0a3 Fusion Digital Gamepad /* Toshiba Corporation products */ product TOSHIBA POCKETPC_E740 0x0706 PocketPC e740 /* Trek Technology products */ product TREK THUMBDRIVE 0x1111 ThumbDrive product TREK THUMBDRIVE_8MB 0x9988 ThumbDrive_8MB /* Trumpion products */ product TRUMPION C3310 0x1100 Comotron C3310 MP3 player /* TwinMOS */ product TWINMOS MDIV 0x1325 Memory Disk IV /* Ultima products */ product ULTIMA 1200UBPLUS 0x4002 1200 UB Plus scanner /* UMAX products */ product UMAX ASTRA1236U 0x0002 Astra 1236U Scanner product UMAX ASTRA1220U 0x0010 Astra 1220U Scanner product UMAX ASTRA2000U 0x0030 Astra 2000U Scanner product UMAX ASTRA2100U 0x0130 Astra 2100U Scanner product UMAX ASTRA2200U 0x0230 Astra 2200U Scanner product UMAX ASTRA3400 0x0060 Astra 3400 Scanner /* Universal Access products */ product UNIACCESS PANACHE 0x0101 Panache Surf USB ISDN Adapter /* VidzMedia products */ product VIDZMEDIA MONSTERTV 0x4fb1 MonsterTV P2H /* Vision products */ product VISION VC6452V002 0x0002 CPiA Camera /* Visioneer products */ product VISIONEER 7600 0x0211 OneTouch 7600 product VISIONEER 5300 0x0221 OneTouch 5300 product VISIONEER 3000 0x0224 Scanport 3000 product VISIONEER 6100 0x0231 OneTouch 6100 product VISIONEER 6200 0x0311 OneTouch 6200 product VISIONEER 8100 0x0321 OneTouch 8100 product VISIONEER 8600 0x0331 OneTouch 8600 /* Vodafone products */ product VODAFONE MC3G 0x5000 Mobile Connect 3G datacard /* VTech products */ product VTECH RT2570 0x3012 RT2570 /* Wacom products */ product WACOM CT0405U 0x0000 CT-0405-U Tablet product WACOM GRAPHIRE 0x0010 Graphire product WACOM GRAPHIRE3_4X5 0x0013 Graphire 3 4x5 product WACOM INTUOSA5 0x0021 Intuos A5 product WACOM GD0912U 0x0022 Intuos 9x12 Graphics Tablet /* Western Digital products */ product WESTERN EXTHDD 0x0400 External HDD product WESTERN HUB 0x0500 USB HUB /* Windbond Electronics */ product WINBOND UH104 0x5518 4-port USB Hub /* Xirlink products */ product XIRLINK PCCAM 0x8080 IBM PC Camera /* Y-E Data products */ product YEDATA FLASHBUSTERU 0x0000 Flashbuster-U /* Yamaha products */ product YAMAHA UX256 0x1000 UX256 MIDI I/F product YAMAHA UX96 0x1008 UX96 MIDI I/F product YAMAHA RTA54I 0x4000 NetVolante RTA54i Broadband&ISDN Router product YAMAHA RTA55I 0x4004 NetVolante RTA55i Broadband VoIP Router product YAMAHA RTW65B 0x4001 NetVolante RTW65b Broadband Wireless Router product YAMAHA RTW65I 0x4002 NetVolante RTW65i Broadband&ISDN Wireless Router /* Yano products */ product YANO U640MO 0x0101 U640MO-03 /* Zinwell products */ product ZINWELL RT2570 0x0260 RT2570 /* Zoom Telephonics, Inc. products */ product ZOOM 2986L 0x9700 2986L Fax modem /* ZyXEL Communication Co. products */ product ZYXEL OMNI56K 0x1500 Omni 56K Plus product ZYXEL 980N 0x2011 Scorpion-980N keyboard