Commit 06b7c5fc authored by chrfranke's avatar chrfranke
Browse files

Read USB ID info from drivedb.h (ticket #44).

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@3087 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent d0c7547f
......@@ -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].
......
......@@ -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
......
......@@ -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[]
*/
......@@ -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"