Exemple #1
0
static int cd_profiles(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char features[65530];
	unsigned int cur_profile = 0;
	unsigned int len;
	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, 8, 8);
	scsi_cmd_set(udev, &sc, 9, 0);
	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 */
		if (SK(err) == 0x5 && ASC(err) == 0x20) {
			info(udev, "drive is pre-MMC2 and does not support 46h get configuration command\n");
			info(udev, "trying to work around the problem\n");
			return cd_profiles_old_mmc(udev, fd);
		}
		return -1;
	}

	cur_profile = features[6] << 8 | features[7];
	if (cur_profile > 0) {
		info(udev, "current profile 0x%02x\n", cur_profile);
	} else {
		info(udev, "no current profile, assuming no media\n");
		return -1;
	}

	switch (cur_profile) {
	case 0x03:
	case 0x04:
	case 0x05:
		info(udev, "profile 0x%02x \n", cur_profile);
		cd_media = 1;
		cd_media_mo = 1;
		break;
	case 0x08:
		info(udev, "profile 0x%02x media_cd_rom\n", cur_profile);
		cd_media = 1;
		cd_media_cd_rom = 1;
		break;
	case 0x09:
		info(udev, "profile 0x%02x media_cd_r\n", cur_profile);
		cd_media = 1;
		cd_media_cd_r = 1;
		break;
	case 0x0a:
		info(udev, "profile 0x%02x media_cd_rw\n", cur_profile);
		cd_media = 1;
		cd_media_cd_rw = 1;
		break;
	case 0x10:
		info(udev, "profile 0x%02x media_dvd_ro\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_rom = 1;
		break;
	case 0x11:
		info(udev, "profile 0x%02x media_dvd_r\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_r = 1;
		break;
	case 0x12:
		info(udev, "profile 0x%02x media_dvd_ram\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_ram = 1;
		break;
	case 0x13:
		info(udev, "profile 0x%02x media_dvd_rw_ro\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_rw = 1;
		cd_media_dvd_rw_ro = 1;
		break;
	case 0x14:
		info(udev, "profile 0x%02x media_dvd_rw_seq\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_rw = 1;
		cd_media_dvd_rw_seq = 1;
		break;
	case 0x1B:
		info(udev, "profile 0x%02x media_dvd_plus_r\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_plus_r = 1;
		break;
	case 0x1A:
		info(udev, "profile 0x%02x media_dvd_plus_rw\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_plus_rw = 1;
		break;
	case 0x2A:
		info(udev, "profile 0x%02x media_dvd_plus_rw_dl\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_plus_rw_dl = 1;
		break;
	case 0x2B:
		info(udev, "profile 0x%02x media_dvd_plus_r_dl\n", cur_profile);
		cd_media = 1;
		cd_media_dvd_plus_r_dl = 1;
		break;
	case 0x40:
		info(udev, "profile 0x%02x media_bd\n", cur_profile);
		cd_media = 1;
		cd_media_bd = 1;
		break;
	case 0x41:
	case 0x42:
		info(udev, "profile 0x%02x media_bd_r\n", cur_profile);
		cd_media = 1;
		cd_media_bd_r = 1;
		break;
	case 0x43:
		info(udev, "profile 0x%02x media_bd_re\n", cur_profile);
		cd_media = 1;
		cd_media_bd_re = 1;
		break;
	case 0x50:
		info(udev, "profile 0x%02x media_hddvd\n", cur_profile);
		cd_media = 1;
		cd_media_hddvd = 1;
		break;
	case 0x51:
		info(udev, "profile 0x%02x media_hddvd_r\n", cur_profile);
		cd_media = 1;
		cd_media_hddvd_r = 1;
		break;
	case 0x52:
		info(udev, "profile 0x%02x media_hddvd_rw\n", cur_profile);
		cd_media = 1;
		cd_media_hddvd_rw = 1;
		break;
	default:
		info(udev, "profile 0x%02x <ignored>\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 <ignored>, with 0x%02x bytes\n", feature, features[i+3]);
			break;
		}
	}

	return 0;
}
/* returns 0 if media was detected */
static int cd_profiles(struct udev *udev, int fd)
{
        struct scsi_cmd sc;
        unsigned char features[65530];
        unsigned int cur_profile = 0;
        unsigned int len;
        unsigned int i;
        int err;
        int ret;

        ret = -1;

        /* First query the current profile */
        scsi_cmd_init(udev, &sc);
        scsi_cmd_set(udev, &sc, 0, 0x46);
        scsi_cmd_set(udev, &sc, 8, 8);
        scsi_cmd_set(udev, &sc, 9, 0);
        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 */
                if (SK(err) == 0x5 && IN_SET(ASC(err), 0x20, 0x24)) {
                        log_debug("drive is pre-MMC2 and does not support 46h get configuration command");
                        log_debug("trying to work around the problem");
                        ret = cd_profiles_old_mmc(udev, fd);
                }
                goto out;
        }

        cur_profile = features[6] << 8 | features[7];
        if (cur_profile > 0) {
                log_debug("current profile 0x%02x", cur_profile);
                feature_profile_media (udev, cur_profile);
                ret = 0; /* we have media */
        } else {
                log_debug("no current profile, assuming no media");
        }

        len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
        log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);

        if (len > sizeof(features)) {
                log_debug("cannot get features in a single query, truncating");
                len = sizeof(features);
        } else if (len <= 8)
                len = sizeof(features);

        /* Now get the full feature buffer */
        scsi_cmd_init(udev, &sc);
        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];
        log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);

        if (len > sizeof(features)) {
                log_debug("cannot get features in a single query, truncating");
                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:
                        log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4);
                        feature_profiles(udev, &features[i]+4, MIN(features[i+3], len - i - 4));
                        break;
                default:
                        log_debug("GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes", feature, features[i+3]);
                        break;
                }
        }
out:
        return ret;
}