From d7cd2b16110c806128747ee245aaa883dd52039d Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 7 Oct 2010 17:02:21 +0200 Subject: [PATCH] cdrom_id: request the drive profile features with a dynamic length Some drives don't like huge feature buffers, so we query twice. First run for the current profile and to get the length. Second time we query the whole profile feature set. --- extras/cdrom_id/cdrom_id.c | 81 +++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/extras/cdrom_id/cdrom_id.c b/extras/cdrom_id/cdrom_id.c index 1b43fe43a..ec001cde7 100644 --- a/extras/cdrom_id/cdrom_id.c +++ b/extras/cdrom_id/cdrom_id.c @@ -398,12 +398,12 @@ static int cd_profiles(struct udev *udev, int fd) unsigned int i; int err; + /* First query the current profile */ scsi_cmd_init(udev, &sc, features, sizeof(features)); scsi_cmd_set(udev, &sc, 0, 0x46); - scsi_cmd_set(udev, &sc, 7, (sizeof(features) >> 8) & 0xff); - scsi_cmd_set(udev, &sc, 8, sizeof(features) & 0xff); + scsi_cmd_set(udev, &sc, 8, 8); scsi_cmd_set(udev, &sc, 9, 0); - err = scsi_cmd_run(udev, &sc, fd, features, sizeof(features)); + err = scsi_cmd_run(udev, &sc, fd, features, 8); if ((err != 0)) { info_scsi_cmd_err(udev, "GET CONFIGURATION", err); /* handle pre-MMC2 drives which do not support GET CONFIGURATION */ @@ -415,31 +415,6 @@ static int cd_profiles(struct udev *udev, int fd) return -1; } - len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; - info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len); - - if (len > sizeof(features)) { - info(udev, "can not get features in a single query, truncating\n"); - len = sizeof(features); - } - - /* device features */ - for (i = 8; i+4 < len; i += (4 + features[i+3])) { - unsigned int feature; - - feature = features[i] << 8 | features[i+1]; - - switch (feature) { - case 0x00: - info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4); - feature_profiles(udev, &features[i]+4, features[i+3]); - break; - default: - info(udev, "GET CONFIGURATION: feature 0x%04x , with 0x%02x bytes\n", feature, features[i+3]); - break; - } - } - cur_profile = features[6] << 8 | features[7]; if (cur_profile > 0) { info(udev, "current profile 0x%02x\n", cur_profile); @@ -553,6 +528,56 @@ static int cd_profiles(struct udev *udev, int fd) info(udev, "profile 0x%02x \n", cur_profile); break; } + + + len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; + info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len); + + if (len > sizeof(features)) { + info(udev, "can not get features in a single query, truncating\n"); + len = sizeof(features); + } else if (len <= 8) { + len = sizeof(features); + } + + /* Now get the full feature buffer */ + scsi_cmd_init(udev, &sc, features, len); + scsi_cmd_set(udev, &sc, 0, 0x46); + scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff); + scsi_cmd_set(udev, &sc, 8, len & 0xff); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, features, len); + if ((err != 0)) { + info_scsi_cmd_err(udev, "GET CONFIGURATION", err); + return -1; + } + + /* parse the length once more, in case the drive decided to have other features suddenly :) */ + len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; + info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len); + + if (len > sizeof(features)) { + info(udev, "can not get features in a single query, truncating\n"); + len = sizeof(features); + } + + /* device features */ + for (i = 8; i+4 < len; i += (4 + features[i+3])) { + unsigned int feature; + + feature = features[i] << 8 | features[i+1]; + + switch (feature) { + case 0x00: + info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4); + feature_profiles(udev, &features[i]+4, features[i+3]); + break; + default: + info(udev, "GET CONFIGURATION: feature 0x%04x , with 0x%02x bytes\n", feature, features[i+3]); + break; + } + } + return 0; } -- 2.30.2