diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG
index 7cb3e1f251773d0e8a3efe00fc77c0830e29b61a..a75e7cff1189383a28fe047c21e6111cbef24005 100644
--- a/smartmontools/CHANGELOG
+++ b/smartmontools/CHANGELOG
@@ -43,6 +43,8 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Read USB ID info from drivedb.h (ticket #44).
+
   [CF] Create branch RELEASE_5_39_DRIVEDB with last drivedb.h file
        compatible with smartmontools 5.39[.1].
 
diff --git a/smartmontools/NEWS b/smartmontools/NEWS
index 56661b221c80b78ec421ac4684d9953d48a5648e..f8c02260ffb77851ca96d50964029e35d9a02391 100644
--- a/smartmontools/NEWS
+++ b/smartmontools/NEWS
@@ -13,6 +13,7 @@ Summary: smartmontools release 5.40
 - configure: New default value for '--with-docdir'.
 - Drive database is in a separate source file 'drivedb.h'
   which can be downloaded from SVN.
+- USB ID info is now included in 'drivedb.h'.
 - New script 'update-smart-drivedb'.
 - smartd libcap-ng support, option '-C, --capabilities'.
 - smartctl option '-l scterc[,...]' to get/set the
diff --git a/smartmontools/drivedb.h b/smartmontools/drivedb.h
index c90753946153e669d497c71420d37254dd48bad6..8fbcd2916fcc0e0e41129b859a215cdcf0b84d45 100644
--- a/smartmontools/drivedb.h
+++ b/smartmontools/drivedb.h
@@ -32,7 +32,7 @@
  *  modelfamily     Informal string about the model family/series of a
  *                  device. Set to "" if no info (apart from device id)
  *                  known.  The entry is ignored if this string starts with
- *                  a dollar sign.
+ *                  a dollar sign.  Must not start with "USB:", see below.
  *  modelregexp     POSIX extended regular expression to match the model of
  *                  a device.  This should never be "".
  *  firmwareregexp  POSIX extended regular expression to match a devices's
@@ -53,6 +53,23 @@
  * The table will be searched from the start to end or until the first match,
  * so the order in the table is important for distinct entries that could match
  * the same drive.
+ *
+ *
+ * Format for USB ID entries:
+ *
+ *  modelfamily     String with format "USB: DEVICE; BRIDGE" where
+ *                  DEVICE is the name of the device and BRIDGE is
+ *                  the name of the USB bridge.  Both may be empty
+ *                  if no info known.
+ *  modelregexp     POSIX extended regular expression to match the USB
+ *                  vendor:product ID in hex notation ("0x1234:0xabcd").
+ *                  This should never be "".
+ *  firmwareregexp  POSIX extended regular expression to match the USB
+ *                  bcdDevice info.  Only compared during search if other
+ *                  entries with same USB vendor:product ID exist.
+ *  warningmsg      Not used yet.
+ *  presets         String with one device type ('-d') option.
+ *
  */
 
 /*
@@ -1499,6 +1516,350 @@ const drive_settings builtin_knowndrives[] = {
     "QUANTUM FIREBALLP KA(9|10).1",
     "", "", ""
   },
+
+  ////////////////////////////////////////////////////
+  // USB ID entries
+  ////////////////////////////////////////////////////
+
+  // Cypress
+  { "USB: ; Cypress CY7C68300A (AT2)",
+    "0x04b4:0x6830",
+    "0x0001",
+    "",
+    ""
+  },
+  { "USB: ; Cypress CY7C68300B/C (AT2LP)",
+    "0x04b4:0x6830",
+    "0x0240",
+    "",
+    "-d usbcypress"
+  },
+  // Myson Century
+  { "USB: ; Myson Century CS8818",
+    "0x04cf:0x8818",
+    "0xb007",
+    "",
+    ""
+  },
+  // Samsung
+  { "USB: Samsung Story Station; ",
+    "0x04e8:0x5f06",
+    "",
+    "",
+    "-d sat"
+  },
+  // Sunplus
+  { "USB: ; SunPlus SPDIF215",
+    "0x04fc:0x0c15",
+    "0xf615",
+    "",
+    "-d usbsunplus"
+  },
+  { "USB: ; SunPlus SPDIF225", // USB+SATA->SATA
+    "0x04fc:0x0c25",
+    "0x0103",
+    "",
+    "-d usbsunplus"
+  },
+  // Iomega
+  { "USB: Iomega LPHD080-0; ",
+    "0x059b:0x0272",
+    "",
+    "",
+    "-d usbcypress"
+  },
+  { "USB: Iomega MDHD500-U; ",
+    "0x059b:0x0275",
+    "0x0001",
+    "",
+    ""
+  },
+  // LaCie
+  { "USB: LaCie hard disk (FA Porsche design); ",
+    "0x059f:0x0651",
+    "",
+    "",
+    ""
+  },
+  { "USB: LaCie hard disk (Neil Poulton design); ",
+    "0x059f:0x1018",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: LaCie Desktop Hard Drive; JMicron",
+    "0x059f:0x1019",
+    "",
+    "",
+    "-d usbjmicron"
+  },
+  // In-System Design
+  { "USB: ; In-System/Cypress ISD-300A1",
+    "0x05ab:0x0060",
+    "0x1101",
+    "",
+    "-d usbcypress"
+  },
+  // Genesys Logic
+  { "USB: ; Genesys Logic GL881E",
+    "0x05e3:0x0702",
+    "",
+    "",
+    ""
+  },
+  { "USB: ; Genesys Logic", // TODO: requires '-T permissive'
+    "0x05e3:0x0718",
+    "0x0041",
+    "",
+    "-d sat"
+  },
+  // Prolific
+  { "USB: ; Prolific PL2507", // USB->PATA
+    "0x067b:0x2507",
+    "",
+    "",
+    ""
+  },
+  { "USB: ; Prolific PL3507", // USB+IEE1394->PATA
+    "0x067b:0x3507",
+    "0x0001",
+    "",
+    ""
+  },
+  // Freecom
+  { "USB: Freecom Hard Drive XS; Sunplus",
+    "0x07ab:0xfc8e",
+    "0x010f",
+    "",
+    "-d usbsunplus"
+  },
+  // Toshiba
+  { "USB: Toshiba PX1270E-1G16; Sunplus",
+    "0x0930:0x0b03",
+    "",
+    "",
+    "-d usbsunplus"
+  },
+  { "USB: Toshiba PX1396E-3T01; Sunplus", // similar to Dura Micro 501
+    "0x0930:0x0b09",
+    "",
+    "",
+    "-d usbsunplus"
+  },
+  { "USB: Seagate FreeAgent Go; ",
+    "0x0bc2:0x2(000|100|101)",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: Seagate FreeAgent Go FW; ",
+    "0x0bc2:0x2200",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: Seagate Expansion Portable; ",
+    "0x0bc2:0x2300",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: Seagate FreeAgent Desktop; ",
+    "0x0bc2:0x3000",
+    "",
+    "",
+    "-d sat"
+  },
+  { "USB: Seagate FreeAgent Desk; ",
+    "0x0bc2:0x3001",
+    "",
+    "",
+    "-d sat"
+  },
+  // Dura Micro
+  { "USB: Dura Micro 509; Sunplus",
+    "0x0c0b:0xb159",
+    "0x0103",
+    "",
+    "-d usbsunplus"
+  },
+  // Maxtor
+  { "USB: Maxtor OneTouch 4; ",
+    "0x0d49:0x7310",
+    "0x0125",
+    "",
+    "-d sat"
+  },
+  { "USB: Maxtor OneTouch 4 Mini; ",
+    "0x0d49:0x7350",
+    "0x0125",
+    "",
+    "-d sat"
+  },
+  { "USB: Maxtor Basics Desktop; ",
+    "0x0d49:0x7410",
+    "0x0122",
+    "",
+    "-d sat"
+  },
+  { "USB: Maxtor Basics Portable; ",
+    "0x0d49:0x7450",
+    "0x0122",
+    "",
+    "-d sat"
+  },
+  // Western Digital
+  { "USB: WD My Passport (IDE); Cypress",
+    "0x1058:0x0701",
+    "0x0240",
+    "",
+    "-d usbcypress"
+  },
+  { "USB: WD My Passport Portable; ",
+    "0x1058:0x0702",
+    "0x0102",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Passport Essential; ",
+    "0x1058:0x0704",
+    "0x0175",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Passport Elite; ",
+    "0x1058:0x0705",
+    "0x0175",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Passport 070A; ",
+    "0x1058:0x070a",
+    "0x1028",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Book ES; ",
+    "0x1058:0x0906",
+    "0x0012",
+    "",
+    "-d sat"
+  },
+  { "USB: WD Elements Desktop; ",
+    "0x1058:0x1001",
+    "0x0104",
+    "",
+    "-d sat"
+  },
+  { "USB: WD Elements Desktop WDE1UBK...; ",
+    "0x1058:0x1003",
+    "0x0175",
+    "",
+    "-d sat"
+  },
+  { "USB: WD Elements; ",
+    "0x1058:0x1010",
+    "0x0105",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Book Essential; ",
+    "0x1058:0x1100",
+    "0x0165",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Book; ",
+    "0x1058:0x1102",
+    "0x1028",
+    "",
+    "-d sat"
+  },
+  { "USB: WD My Book Essential; ",
+    "0x1058:0x1110",
+    "0x1030",
+    "",
+    "-d sat"
+  },
+  // A-DATA
+  { "USB: A-DATA SH93; ",
+    "0x125f:0xa93a",
+    "0x0150",
+    "",
+    "-d usbcypress"
+  },
+  // Initio
+  { "USB: ; Initio 316000",
+    "0x13fd:0x0540",
+    "",
+    "",
+    ""
+  },
+  { "USB: ; Initio", // USB->SATA
+    "0x13fd:0x1240",
+    "0x0104",
+    "",
+    "-d sat"
+  },
+  { "USB: ; Initio", // USB+SATA->SATA
+    "0x13fd:0x1340",
+    "0x0208",
+    "",
+    "-d sat"
+  },
+  // JMicron
+  { "USB: ; JMicron JM20329", // USB->SATA
+    "0x152d:0x2329",
+    "0x0100",
+    "",
+    "-d usbjmicron"
+  },
+  { "USB: ; JMicron JM20336", // USB+SATA->SATA, USB->2xSATA
+    "0x152d:0x2336",
+    "0x0100",
+    "",
+    "-d usbjmicron,x"
+  },
+  { "USB: ; JMicron JM20337/8", // USB->SATA+PATA, USB+SATA->PATA
+    "0x152d:0x2338",
+    "0x0100",
+    "",
+    "-d usbjmicron"
+  },
+  { "USB: ; JMicron JM20339", // USB->SATA
+    "0x152d:0x2339",
+    "0x0100",
+    "",
+    "-d usbjmicron,x"
+  },
+  // Verbatim
+  { "USB: Verbatim FW/USB160; Oxford OXUF934SSA-LQAG", // USB+IEE1394->SATA
+    "0x18a5:0x0215",
+    "0x0001",
+    "",
+    "-d sat"
+  },
+  // SunplusIT
+  { "USB: ; SunplusIT",
+    "0x1bcf:0x0c31",
+    "",
+    "",
+    "-d usbsunplus"
+  },
+  // Hitachi/SimpleTech
+  { "USB: Hitachi/SimpleTech; JMicron", // 1TB
+    "0x4971:0xce17",
+    "",
+    "",
+    "-d usbjmicron"
+  },
+  // OnSpec
+  { "USB: ; OnSpec", // USB->PATA
+    "0x55aa:0x2b00",
+    "0x0100",
+    "",
+    ""
+  },
 /*
 }; // builtin_knowndrives[]
  */
diff --git a/smartmontools/knowndrives.cpp b/smartmontools/knowndrives.cpp
index 79e538249489c7a3ac41aee246041761b09c6536..0776b81cdfc7ab05b27eb2cfbe428b0d9fab9407 100644
--- a/smartmontools/knowndrives.cpp
+++ b/smartmontools/knowndrives.cpp
@@ -4,8 +4,8 @@
  * Home page of code is: http://smartmontools.sourceforge.net
  * Address of support mailing list: smartmontools-support@lists.sourceforge.net
  *
- * Copyright (C) 2003-9 Philip Williams, Bruce Allen
- * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-10 Philip Williams, Bruce Allen
+ * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -140,6 +140,18 @@ const char * drive_database::copy_string(const char * src)
 static drive_database knowndrives;
 
 
+// Return true if modelfamily string describes entry for USB ID
+static bool is_usb_modelfamily(const char * modelfamily)
+{
+  return !strncmp(modelfamily, "USB:", 4);
+}
+
+// Return true if entry for USB ID
+static inline bool is_usb_entry(const drive_settings * dbentry)
+{
+  return is_usb_modelfamily(dbentry->modelfamily);
+}
+
 // Compile regular expression, print message on failure.
 static bool compile(regular_expression & regex, const char *pattern)
 {
@@ -173,6 +185,10 @@ const drive_settings * lookup_drive(const char * model, const char * firmware)
     firmware = "";
 
   for (unsigned i = 0; i < knowndrives.size(); i++) {
+    // Skip USB entries
+    if (is_usb_entry(&knowndrives[i]))
+      continue;
+
     // Check whether model matches the regular expression in knowndrives[i].
     if (!match(knowndrives[i].modelregexp, model))
       continue;
@@ -190,9 +206,10 @@ const drive_settings * lookup_drive(const char * model, const char * firmware)
   return 0;
 }
 
-// Parse '-v' and '-F' options in preset string, return false on error.
-static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs,
-                          unsigned char & fix_firmwarebug)
+
+// Parse drive or USB options in preset string, return false on error.
+static bool parse_db_presets(const char * presets, ata_vendor_attr_defs * defs,
+                             unsigned char * fix_firmwarebug, std::string * type)
 {
   for (int i = 0; ; ) {
     i += strspn(presets+i, " \t");
@@ -201,12 +218,12 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs,
     char opt, arg[40+1+13]; int len = -1;
     if (!(sscanf(presets+i, "-%c %40[^ ]%n", &opt, arg, &len) >= 2 && len > 0))
       return false;
-    if (opt == 'v') {
+    if (opt == 'v' && defs) {
       // Parse "-v N,format[,name]"
-      if (!parse_attribute_def(arg, defs, PRIOR_DATABASE))
+      if (!parse_attribute_def(arg, *defs, PRIOR_DATABASE))
         return false;
     }
-    else if (opt == 'F') {
+    else if (opt == 'F' && fix_firmwarebug) {
       unsigned char fix;
       if (!strcmp(arg, "samsung"))
         fix = FIX_SAMSUNG;
@@ -217,8 +234,12 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs,
       else
         return false;
       // Set only if not set by user
-      if (fix_firmwarebug == FIX_NOTSPECIFIED)
-        fix_firmwarebug = fix;
+      if (*fix_firmwarebug == FIX_NOTSPECIFIED)
+        *fix_firmwarebug = fix;
+    }
+    else if (opt == 'd' && type) {
+        // TODO: Check valid types
+        *type = arg;
     }
     else
       return false;
@@ -228,6 +249,83 @@ static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs,
   return true;
 }
 
+// Parse '-v' and '-F' options in preset string, return false on error.
+static inline bool parse_presets(const char * presets,
+                                 ata_vendor_attr_defs & defs,
+                                 unsigned char & fix_firmwarebug)
+{
+  return parse_db_presets(presets, &defs, &fix_firmwarebug, 0);
+}
+
+// Parse '-d' option in preset string, return false on error.
+static inline bool parse_usb_type(const char * presets, std::string & type)
+{
+  return parse_db_presets(presets, 0, 0, &type);
+}
+
+// Parse "USB: [DEVICE] ; [BRIDGE]" string
+static void parse_usb_names(const char * names, usb_dev_info & info)
+{
+  int n1 = -1, n2 = -1, n3 = -1;
+  sscanf(names, "USB: %n%*[^;]%n; %n", &n1, &n2, &n3);
+  if (0 < n1 && n1 < n2)
+    info.usb_device.assign(names+n1, n2-n1);
+  else
+    sscanf(names, "USB: ; %n", &n3);
+  if (0 < n3)
+    info.usb_bridge = names+n3;
+}
+
+// Search drivedb for USB device with vendor:product ID.
+int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
+                      usb_dev_info & info, usb_dev_info & info2)
+{
+  // Format strings to match
+  char usb_id_str[16], bcd_dev_str[16];
+  snprintf(usb_id_str, sizeof(usb_id_str), "0x%04x:0x%04x", vendor_id, product_id);
+  if (bcd_device >= 0)
+    snprintf(bcd_dev_str, sizeof(bcd_dev_str), "0x%04x", bcd_device);
+  else
+    bcd_dev_str[0] = 0;
+
+  int found = 0;
+  bool bcd_match = false;
+  for (unsigned i = 0; i < knowndrives.size(); i++) {
+    const drive_settings & dbentry = knowndrives[i];
+
+    // Skip drive entries
+    if (!is_usb_entry(&dbentry))
+      continue;
+
+    // Check whether USB vendor:product ID matches
+    if (!match(dbentry.modelregexp, usb_id_str))
+      continue;
+
+    // Parse '-d type'
+    usb_dev_info d;
+    if (!parse_usb_type(dbentry.presets, d.usb_type))
+      return 0; // Syntax error
+    parse_usb_names(dbentry.modelfamily, d);
+
+    // If two entries with same vendor:product ID have different
+    // types, use bcd_device (if provided by OS) to select entry.
+    bool bm = (   *bcd_dev_str && *dbentry.firmwareregexp
+               && match(dbentry.firmwareregexp, bcd_dev_str));
+
+    if (found == 0 || bm > bcd_match) {
+      info = d; found = 1;
+      bcd_match = bm;
+    }
+    else if (info.usb_type != d.usb_type && bm == bcd_match) {
+      // two different entries found
+      info2 = d; found = 2;
+      break;
+    }
+  }
+
+  return found;
+}
+
 // Shows one entry of knowndrives[], returns #errors.
 static int showonepreset(const drive_settings * dbentry)
 {
@@ -242,60 +340,80 @@ static int showonepreset(const drive_settings * dbentry)
          "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n");
     return 1;
   }
-  
+
+  bool usb = is_usb_entry(dbentry);
+
   // print and check model and firmware regular expressions
   int errcnt = 0;
   regular_expression regex;
-  pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL REGEXP:", dbentry->modelregexp);
+  pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "MODEL REGEXP:" : "USB Vendor:Product:"),
+       dbentry->modelregexp);
   if (!compile(regex, dbentry->modelregexp))
     errcnt++;
 
-  pout("%-*s %s\n", TABLEPRINTWIDTH, "FIRMWARE REGEXP:", *dbentry->firmwareregexp ?
-    dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change)
+  pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "FIRMWARE REGEXP:" : "USB bcdDevice:"),
+       *dbentry->firmwareregexp ? dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change)
   if (*dbentry->firmwareregexp && !compile(regex, dbentry->firmwareregexp))
     errcnt++;
 
-  pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily);
-
-  // if there are any presets, then show them
-  unsigned char fix_firmwarebug = 0;
-  bool first_preset = true;
-  if (*dbentry->presets) {
-    ata_vendor_attr_defs defs;
-    if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) {
-      pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
-      errcnt++;
+  if (!usb) {
+    pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily);
+
+    // if there are any presets, then show them
+    unsigned char fix_firmwarebug = 0;
+    bool first_preset = true;
+    if (*dbentry->presets) {
+      ata_vendor_attr_defs defs;
+      if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) {
+        pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
+        errcnt++;
+      }
+      for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
+        if (defs[i].priority != PRIOR_DEFAULT) {
+          // Use leading zeros instead of spaces so that everything lines up.
+          pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "",
+               i, ata_get_smart_attr_name(i, defs).c_str());
+          first_preset = false;
+        }
+      }
     }
-    for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
-      if (defs[i].priority != PRIOR_DEFAULT) {
-        // Use leading zeros instead of spaces so that everything lines up.
-        pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "",
-             i, ata_get_smart_attr_name(i, defs).c_str());
-        first_preset = false;
+    if (first_preset)
+      pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required.");
+
+    // describe firmwarefix
+    if (fix_firmwarebug) {
+      const char * fixdesc;
+      switch (fix_firmwarebug) {
+        case FIX_SAMSUNG:
+          fixdesc = "Fixes byte order in some SMART data (same as -F samsung)";
+          break;
+        case FIX_SAMSUNG2:
+          fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)";
+          break;
+        case FIX_SAMSUNG3:
+          fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)";
+          break;
+        default:
+          fixdesc = "UNKNOWN"; errcnt++;
+          break;
       }
+      pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc);
     }
   }
-  if (first_preset)
-    pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required.");
-
-  // describe firmwarefix
-  if (fix_firmwarebug) {
-    const char * fixdesc;
-    switch (fix_firmwarebug) {
-      case FIX_SAMSUNG:
-        fixdesc = "Fixes byte order in some SMART data (same as -F samsung)";
-        break;
-      case FIX_SAMSUNG2:
-        fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)";
-        break;
-      case FIX_SAMSUNG3:
-        fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)";
-        break;
-      default:
-        fixdesc = "UNKNOWN"; errcnt++;
-        break;
+  else {
+    // Print USB info
+    usb_dev_info info; parse_usb_names(dbentry->modelfamily, info);
+    pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Device:",
+      (!info.usb_device.empty() ? info.usb_device.c_str() : "[unknown]"));
+    pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Bridge:",
+      (!info.usb_bridge.empty() ? info.usb_bridge.c_str() : "[unknown]"));
+
+    if (*dbentry->presets && !parse_usb_type(dbentry->presets, info.usb_type)) {
+      pout("Syntax error in USB type string \"%s\"\n", dbentry->presets);
+      errcnt++;
     }
-    pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc);
+    pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Type",
+      (!info.usb_type.empty() ? info.usb_type.c_str() : "[unsupported]"));
   }
 
   // Print any special warnings
@@ -633,10 +751,19 @@ static bool parse_drive_database(parse_ptr src, drive_database & db, const char
             break;
           case 4:
             if (!token.value.empty()) {
-              ata_vendor_attr_defs defs; unsigned char fix = 0;
-              if (!parse_presets(token.value.c_str(), defs, fix)) {
-                pout("%s(%d): Syntax error in preset option string\n", path, token.line);
-                ok = false;
+              if (!is_usb_modelfamily(values[0].c_str())) {
+                ata_vendor_attr_defs defs; unsigned char fix = 0;
+                if (!parse_presets(token.value.c_str(), defs, fix)) {
+                  pout("%s(%d): Syntax error in preset option string\n", path, token.line);
+                  ok = false;
+                }
+              }
+              else {
+                std::string type;
+                if (!parse_usb_type(token.value.c_str(), type)) {
+                  pout("%s(%d): Syntax error in USB type string\n", path, token.line);
+                  ok = false;
+                }
               }
             }
             break;
diff --git a/smartmontools/knowndrives.h b/smartmontools/knowndrives.h
index c695b63df9086e9634444738b9c662f97a89fc48..e69f00300d4f7753d2343ca53533609c836c14a3 100644
--- a/smartmontools/knowndrives.h
+++ b/smartmontools/knowndrives.h
@@ -4,8 +4,8 @@
  * Home page of code is: http://smartmontools.sourceforge.net
  * Address of support mailing list: smartmontools-support@lists.sourceforge.net
  *
- * Copyright (C) 2003-9 Philip Williams, Bruce Allen
- * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2003-10 Philip Williams, Bruce Allen
+ * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,6 +36,18 @@ struct drive_settings {
 // string.
 const drive_settings * lookup_drive(const char * model, const char * firmware);
 
+// info returned by lookup_usb_device()
+struct usb_dev_info
+{
+  std::string usb_device; // Device name, empty if unknown
+  std::string usb_bridge; // USB bridge name, empty if unknown
+  std::string usb_type;   // Type string ('-d' option).
+};
+
+// Search drivedb for USB device with vendor:product ID.
+int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
+                      usb_dev_info & info, usb_dev_info & info2);
+
 // Shows the presets (if any) that are available for the given drive.
 void show_presets(const ata_identify_device * drive, bool fix_swapped_id);
 
diff --git a/smartmontools/scsiata.cpp b/smartmontools/scsiata.cpp
index 52fbdd80d4f6d4ded867214b1035f58bc98228d0..840d0008f589dec05f79ad3459bec6a5b8840dc6 100644
--- a/smartmontools/scsiata.cpp
+++ b/smartmontools/scsiata.cpp
@@ -56,6 +56,7 @@
 #include "extern.h"
 #include "scsicmds.h"
 #include "atacmds.h" // ataReadHDIdentity()
+#include "knowndrives.h" // lookup_usb_device()
 #include "utility.h"
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
@@ -1321,103 +1322,6 @@ ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev,
 /////////////////////////////////////////////////////////////////////////////
 // USB device type detection
 
-struct usb_id_entry {
-  int vendor_id, product_id, version;
-  const char * type;
-};
-
-const char d_sat[]       = "sat";
-const char d_cypress[]   = "usbcypress";
-const char d_jmicron[]   = "usbjmicron";
-const char d_jmicron_x[] = "usbjmicron,x";
-const char d_sunplus[]   = "usbsunplus";
-const char d_unsup[]     = "unsupported";
-
-// Map USB IDs -> '-d type' string
-const usb_id_entry usb_ids[] = {
-  // Cypress
-  { 0x04b4, 0x6830, 0x0001, d_unsup   }, // Cypress CY7C68300A (AT2)
-  { 0x04b4, 0x6830, 0x0240, d_cypress }, // Cypress CY7C68300B/C (AT2LP)
-//{ 0x04b4, 0x6831,     -1, d_cypress }, // Cypress CY7C68310 (ISD-300LP)
-  // Myson Century
-  { 0x04cf, 0x8818, 0xb007, d_unsup   }, // Myson Century CS8818
-  // Samsung
-  { 0x04e8, 0x5f06,     -1, d_sat     }, // Samsung Story Station
-  // Sunplus
-  { 0x04fc, 0x0c15, 0xf615, d_sunplus }, // SunPlus SPDIF215
-  { 0x04fc, 0x0c25, 0x0103, d_sunplus }, // SunPlus SPDIF225 (USB+SATA->SATA)
-  // Iomega
-  { 0x059b, 0x0272,     -1, d_cypress }, // Iomega LPHD080-0
-  { 0x059b, 0x0275, 0x0001, d_unsup   }, // Iomega MDHD500-U
-  // LaCie
-  { 0x059f, 0x0651,     -1, d_unsup   }, // LaCie hard disk (FA Porsche design)
-  { 0x059f, 0x1018,     -1, d_sat     }, // LaCie hard disk (Neil Poulton design)
-  { 0x059f, 0x1019,     -1, d_jmicron }, // LaCie Desktop Hard Drive
-  // In-System Design
-  { 0x05ab, 0x0060, 0x1101, d_cypress }, // In-System/Cypress ISD-300A1
-  // Genesys Logic
-  { 0x05e3, 0x0702,     -1, d_unsup   }, // Genesys Logic GL881E
-  { 0x05e3, 0x0718, 0x0041, d_sat     }, // Genesys Logic ? (TODO: requires '-T permissive')
-  // Prolific
-  { 0x067b, 0x2507,     -1, d_unsup   }, // Prolific PL2507 (USB->PATA)
-  { 0x067b, 0x3507, 0x0001, d_unsup   }, // Prolific PL3507 (USB+IEE1394->PATA)
-  // Freecom
-  { 0x07ab, 0xfc8e, 0x010f, d_sunplus }, // Freecom Hard Drive XS
-  // Toshiba
-  { 0x0930, 0x0b03,     -1, d_sunplus }, // Toshiba PX1270E-1G16
-  { 0x0930, 0x0b09,     -1, d_sunplus }, // Toshiba PX1396E-3T01 (similar to Dura Micro 501)
-  // Seagate
-  { 0x0bc2, 0x2000,     -1, d_sat     }, // Seagate FreeAgent Go
-  { 0x0bc2, 0x2100,     -1, d_sat     }, // Seagate FreeAgent Go
-  { 0x0bc2, 0x2101,     -1, d_sat     }, // Seagate FreeAgent Go
-  { 0x0bc2, 0x2200,     -1, d_sat     }, // Seagate FreeAgent Go FW
-  { 0x0bc2, 0x2300,     -1, d_sat     }, // Seagate Expansion Portable
-  { 0x0bc2, 0x3000,     -1, d_sat     }, // Seagate FreeAgent Desktop
-  { 0x0bc2, 0x3001,     -1, d_sat     }, // Seagate FreeAgent Desk
-  // Dura Micro
-  { 0x0c0b, 0xb159, 0x0103, d_sunplus }, // Dura Micro 509
-  // Maxtor
-  { 0x0d49, 0x7310, 0x0125, d_sat     }, // Maxtor OneTouch 4
-  { 0x0d49, 0x7350, 0x0125, d_sat     }, // Maxtor OneTouch 4 Mini
-  { 0x0d49, 0x7410, 0x0122, d_sat     }, // Maxtor Basics Desktop
-  { 0x0d49, 0x7450, 0x0122, d_sat     }, // Maxtor Basics Portable
-  // Western Digital
-  { 0x1058, 0x0701, 0x0240, d_cypress }, // WD My Passport (IDE)
-  { 0x1058, 0x0702, 0x0102, d_sat     }, // WD My Passport Portable
-  { 0x1058, 0x0704, 0x0175, d_sat     }, // WD My Passport Essential
-  { 0x1058, 0x0705, 0x0175, d_sat     }, // WD My Passport Elite
-  { 0x1058, 0x070a, 0x1028, d_sat     }, // WD My Passport 070A
-  { 0x1058, 0x0906, 0x0012, d_sat     }, // WD My Book ES
-  { 0x1058, 0x1001, 0x0104, d_sat     }, // WD Elements Desktop
-  { 0x1058, 0x1003, 0x0175, d_sat     }, // WD Elements Desktop WDE1UBK...
-  { 0x1058, 0x1010, 0x0105, d_sat     }, // WD Elements
-  { 0x1058, 0x1100, 0x0165, d_sat     }, // WD My Book Essential
-  { 0x1058, 0x1102, 0x1028, d_sat     }, // WD My Book
-  { 0x1058, 0x1110, 0x1030, d_sat     }, // WD My Book Essential
-  // A-DATA
-  { 0x125f, 0xa93a, 0x0150, d_cypress }, // A-DATA SH93
-  // Initio
-  { 0x13fd, 0x0540,     -1, d_unsup   }, // Initio 316000
-  { 0x13fd, 0x1240, 0x0104, d_sat     }, // Initio ? (USB->SATA)
-  { 0x13fd, 0x1340, 0x0208, d_sat     }, // Initio ? (USB+SATA->SATA)
-  // JMicron
-  { 0x152d, 0x2329, 0x0100, d_jmicron }, // JMicron JM20329 (USB->SATA)
-  { 0x152d, 0x2336, 0x0100, d_jmicron_x},// JMicron JM20336 (USB+SATA->SATA, USB->2xSATA)
-  { 0x152d, 0x2338, 0x0100, d_jmicron }, // JMicron JM20337/8 (USB->SATA+PATA, USB+SATA->PATA)
-  { 0x152d, 0x2339, 0x0100, d_jmicron_x},// JMicron JM20339 (USB->SATA)
-  // Verbatim
-  { 0x18a5, 0x0215, 0x0001, d_sat     }, // Verbatim FW/USB160 - Oxford OXUF934SSA-LQAG (USB+IEE1394->SATA)
-  // SunplusIT
-  { 0x1bcf, 0x0c31,     -1, d_sunplus }, // SunplusIT
-  // Hitachi/SimpleTech
-  { 0x4971, 0xce17,     -1, d_jmicron }, // Hitachi/SimpleTech 1TB
-  // OnSpec
-  { 0x55aa, 0x2b00, 0x0100, d_unsup   }  // OnSpec ? (USB->PATA)
-};
-
-const unsigned num_usb_ids = sizeof(usb_ids)/sizeof(usb_ids[0]);
-
-
 // Format USB ID for error messages
 static std::string format_usb_id(int vendor_id, int product_id, int version)
 {
@@ -1431,41 +1335,31 @@ static std::string format_usb_id(int vendor_id, int product_id, int version)
 const char * smart_interface::get_usb_dev_type_by_id(int vendor_id, int product_id,
                                                      int version /*= -1*/)
 {
-  const usb_id_entry * entry = 0;
-  bool state = false;
-
-  for (unsigned i = 0; i < num_usb_ids; i++) {
-    const usb_id_entry & e = usb_ids[i];
-    if (!(vendor_id == e.vendor_id && product_id == e.product_id))
-      continue;
-
-    // If two entries with same vendor:product ID have different
-    // types, use version (if provided by OS) to select entry.
-    bool s = (version >= 0 && version == e.version);
-    if (entry) {
-      if (s <= state) {
-        if (s == state && e.type != entry->type) {
-          set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'",
-                  format_usb_id(vendor_id, product_id, version).c_str(),
-                  e.type, entry->type);
-          return 0;
-        }
-        continue;
-      }
-    }
-    state = s;
-    entry = &e;
-  }
+  usb_dev_info info, info2;
+  int n = lookup_usb_device(vendor_id, product_id, version, info, info2);
 
-  if (!entry) {
+  if (n <= 0) {
     set_err(EINVAL, "Unknown USB bridge %s",
             format_usb_id(vendor_id, product_id, version).c_str());
     return 0;
   }
-  if (entry->type == d_unsup) {
+
+  if (n > 1) {
+    set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'",
+            format_usb_id(vendor_id, product_id, version).c_str(),
+            (!info.usb_type.empty()  ? info.usb_type.c_str()  : "[unsupported]"),
+            (!info2.usb_type.empty() ? info2.usb_type.c_str() : "[unsupported]"));
+    return 0;
+  }
+
+  if (info.usb_type.empty()) {
     set_err(ENOSYS, "Unsupported USB bridge %s",
             format_usb_id(vendor_id, product_id, version).c_str());
     return 0;
   }
-  return entry->type;
+
+  // TODO: change return type to std::string
+  static std::string type;
+  type = info.usb_type;
+  return type.c_str();
 }
diff --git a/smartmontools/smartctl.8.in b/smartmontools/smartctl.8.in
index a2245cc828f46370573472986a0927ef48c1a9a6..1f1076aabe057f77984ef3ae4fc73c8df57486a4 100644
--- a/smartmontools/smartctl.8.in
+++ b/smartmontools/smartctl.8.in
@@ -1339,6 +1339,14 @@ Example:
     "",                // No warning.
     ""                 // No options preset.
   },
+  /* USB ID entry: */
+  {
+    "USB: Device; Bridge", // Info about USB device and bridge name.
+    "0x1234:0xabcd",   // Regular expression to match vendor:product ID.
+    "0x0101",          // Regular expression to match bcdDevice.
+    "",                // Not used.
+    "\-d sat"           // String with device type option.
+  },
   /* ... */
 .fi