예제 #1
0
파일: cdrom_id.c 프로젝트: OPSF/uClinux
static int cd_media_info(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char header[32];
	static const char *media_status[] = {
		"blank",
		"appendable",
		"complete",
		"other"
	};
	int err;

	scsi_cmd_set(udev, &sc, 0, 0x51);
	scsi_cmd_set(udev, &sc, 8, sizeof(header));
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
		return -1;
	};

	info(udev, "disk type %02x\n", header[8]);

	if ((header[2] & 3) < 4)
		cd_media_state = media_status[header[2] & 3];
	if ((header[2] & 3) != 2)
		cd_media_session_next = header[10] << 8 | header[5];
	cd_media_session_count = header[9] << 8 | header[4];
	cd_media_track_count = header[11] << 8 | header[6];

	return 0;
}
예제 #2
0
파일: cdrom_id.c 프로젝트: Keruspe/systemd
static int media_eject(int fd) {
        struct scsi_cmd sc;
        int err;

        scsi_cmd_init(&sc);
        scsi_cmd_set(&sc, 0, 0x1b);
        scsi_cmd_set(&sc, 4, 0x02);
        scsi_cmd_set(&sc, 5, 0);
        err = scsi_cmd_run(&sc, fd, NULL, 0);
        if ((err != 0)) {
                info_scsi_cmd_err("START_STOP_UNIT", err);
                return -1;
        }
        return 0;
}
예제 #3
0
/* returns 0 if media was detected */
static int cd_profiles_old_mmc(struct udev *udev, int fd)
{
        struct scsi_cmd sc;
        int err;

        unsigned char header[32];

        scsi_cmd_init(udev, &sc);
        scsi_cmd_set(udev, &sc, 0, 0x51);
        scsi_cmd_set(udev, &sc, 8, sizeof(header));
        scsi_cmd_set(udev, &sc, 9, 0);
        err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
        if ((err != 0)) {
                info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
                if (cd_media == 1) {
                        log_debug("no current profile, but disc is present; assuming CD-ROM");
                        cd_media_cd_rom = 1;
                        cd_media_track_count = 1;
                        cd_media_track_count_data = 1;
                        return 0;
                } else {
                        log_debug("no current profile, assuming no media");
                        return -1;
                }
        };

        cd_media = 1;

        if (header[2] & 16) {
                cd_media_cd_rw = 1;
                log_debug("profile 0x0a media_cd_rw");
        } else if ((header[2] & 3) < 2 && cd_cd_r) {
                cd_media_cd_r = 1;
                log_debug("profile 0x09 media_cd_r");
        } else {
                cd_media_cd_rom = 1;
                log_debug("profile 0x08 media_cd_rom");
        }
        return 0;
}
예제 #4
0
파일: cdrom_id.c 프로젝트: OPSF/uClinux
static int cd_inquiry(struct udev *udev, int fd) {
	struct scsi_cmd sc;
	unsigned char inq[128];
	int err;

	scsi_cmd_set(udev, &sc, 0, 0x12);
	scsi_cmd_set(udev, &sc, 4, 36);
	scsi_cmd_set(udev, &sc, 5, 0);
	err = scsi_cmd_run(udev, &sc, fd, inq, 36);
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "INQUIRY", err);
		return -1;
	}

	if ((inq[0] & 0x1F) != 5) {
		info(udev, "not an MMC unit\n");
		return -1;
	}

	info(udev, "INQUIRY: [%.8s][%.16s][%.4s]\n", inq + 8, inq + 16, inq + 32);
	return 0;
}
예제 #5
0
파일: cdrom_id.c 프로젝트: Keruspe/systemd
static int cd_inquiry(int fd) {
        struct scsi_cmd sc;
        unsigned char inq[128];
        int err;

        scsi_cmd_init(&sc);
        scsi_cmd_set(&sc, 0, 0x12);
        scsi_cmd_set(&sc, 4, 36);
        scsi_cmd_set(&sc, 5, 0);
        err = scsi_cmd_run(&sc, fd, inq, 36);
        if ((err != 0)) {
                info_scsi_cmd_err("INQUIRY", err);
                return -1;
        }

        if ((inq[0] & 0x1F) != 5) {
                log_debug("not an MMC unit");
                return -1;
        }

        log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32);
        return 0;
}
예제 #6
0
파일: cdrom_id.c 프로젝트: ystk/debian-udev
static int cd_media_toc(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char header[12];
	unsigned char toc[2048];
	unsigned int len, i, num_tracks;
	unsigned char *p;
	int err;

	scsi_cmd_init(udev, &sc, header, sizeof(header));
	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 6, 1);
	scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err != 0)) {
		info_scsi_cmd_err(udev, "READ TOC", err);
		return -1;
	}

	len = (header[0] << 8 | header[1]) + 2;
	info(udev, "READ TOC: len: %d, start track: %d, end track: %d\n", len, header[2], header[3]);
	if (len > sizeof(toc))
		return -1;
	if (len < 2)
		return -1;
	/* 2: first track, 3: last track */
	num_tracks = header[3] - header[2] + 1;

	/* empty media has no tracks */
	if (len < 8)
		return 0;

	scsi_cmd_init(udev, &sc, toc, sizeof(toc));
	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */
	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, toc, len);
	if ((err != 0)) {
		info_scsi_cmd_err(udev, "READ TOC (tracks)", err);
		return -1;
	}

	/* Take care to not iterate beyond the last valid track as specified in
	 * the TOC, but also avoid going beyond the TOC length, just in case
	 * the last track number is invalidly large */
	for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) {
		unsigned int block;
		unsigned int is_data_track;

		is_data_track = (p[1] & 0x04) != 0;

		block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
		info(udev, "track=%u info=0x%x(%s) start_block=%u\n",
		     p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block);

		if (is_data_track)
			cd_media_track_count_data++;
		else
			cd_media_track_count_audio++;
	}

	scsi_cmd_init(udev, &sc, header, sizeof(header));
	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */
	scsi_cmd_set(udev, &sc, 8, sizeof(header));
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err != 0)) {
		info_scsi_cmd_err(udev, "READ TOC (multi session)", err);
		return -1;
	}
	len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7];
	info(udev, "last track %u starts at block %u\n", header[4+2], len);
	cd_media_session_last_offset = (unsigned long long int)len * 2048;
	return 0;
}
예제 #7
0
파일: cdrom_id.c 프로젝트: ystk/debian-udev
static int cd_media_info(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char header[32];
	static const char *media_status[] = {
		"blank",
		"appendable",
		"complete",
		"other"
	};
	int err;

	scsi_cmd_init(udev, &sc, header, sizeof(header));
	scsi_cmd_set(udev, &sc, 0, 0x51);
	scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err != 0)) {
		info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
		return -1;
	};

	cd_media = 1;
	info(udev, "disk type %02x\n", header[8]);
	info(udev, "hardware reported media status: %s\n", media_status[header[2] & 3]);

	/* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */
	if (!cd_media_cd_rom)
		cd_media_state = media_status[header[2] & 3];

	/* fresh DVD-RW in restricted overwite mode reports itself as
	 * "appendable"; change it to "blank" to make it consistent with what
	 * gets reported after blanking, and what userspace expects  */
	if (cd_media_dvd_rw_ro && (header[2] & 3) == 1)
		cd_media_state = media_status[0];

	/* DVD+RW discs (and DVD-RW in restricted mode) once formatted are
	 * always "complete", DVD-RAM are "other" or "complete" if the disc is
	 * write protected; we need to check the contents if it is blank */
	if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) {
		unsigned char buffer[32 * 2048];
		unsigned char result, len;
		int block, offset;

		if (cd_media_dvd_ram) {
			/* a write protected dvd-ram may report "complete" status */

			unsigned char dvdstruct[8];
			unsigned char format[12];

			scsi_cmd_init(udev, &sc, dvdstruct, sizeof(dvdstruct));
			scsi_cmd_set(udev, &sc, 0, 0xAD);
			scsi_cmd_set(udev, &sc, 7, 0xC0);
			scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct));
			scsi_cmd_set(udev, &sc, 11, 0);
			err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct));
			if ((err != 0)) {
				info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err);
				return -1;
			}
			if (dvdstruct[4] & 0x02) {
				cd_media_state = media_status[2];
				info(udev, "write-protected DVD-RAM media inserted\n");
				goto determined;
			}

			/* let's make sure we don't try to read unformatted media */
			scsi_cmd_init(udev, &sc, format, sizeof(format));
			scsi_cmd_set(udev, &sc, 0, 0x23);
			scsi_cmd_set(udev, &sc, 8, sizeof(format));
			scsi_cmd_set(udev, &sc, 9, 0);
			err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format));
			if ((err != 0)) {
				info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err);
				return -1;
			}

			len = format[3];
			if (len & 7 || len < 16) {
				info(udev, "invalid format capacities length\n");
				return -1;
			}

			switch(format[8] & 3) {
			    case 1:
				info(udev, "unformatted DVD-RAM media inserted\n");
				/* This means that last format was interrupted
				 * or failed, blank dvd-ram discs are factory
				 * formatted. Take no action here as it takes
				 * quite a while to reformat a dvd-ram and it's
				 * not automatically started */
				goto determined;

			    case 2:
				info(udev, "formatted DVD-RAM media inserted\n");
				break;

			    case 3:
				cd_media = 0; //return no media
				info(udev, "format capacities returned no media\n");
				return -1;
			}
		}

		/* Take a closer look at formatted media (unformatted DVD+RW
		 * has "blank" status", DVD-RAM was examined earlier) and check
		 * for ISO and UDF PVDs or a fs superblock presence and do it
		 * in one ioctl (we need just sectors 0 and 16) */
		scsi_cmd_init(udev, &sc, buffer, sizeof(buffer));
		scsi_cmd_set(udev, &sc, 0, 0x28);
		scsi_cmd_set(udev, &sc, 5, 0);
		scsi_cmd_set(udev, &sc, 8, 32);
		scsi_cmd_set(udev, &sc, 9, 0);
		err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer));
		if ((err != 0)) {
			info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err);
			return -1;
		}

		/* if any non-zero data is found in sector 16 (iso and udf) or
		 * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc
		 * is assumed non-blank */
		result = 0;

		for (block = 32768; block >= 0 && !result; block -= 32768) {
			offset = block;
			while (offset < (block + 2048) && !result) {
				result = buffer [offset];
				offset++;
			}
		}

		if (!result) {
			cd_media_state = media_status[0];
			info(udev, "no data in blocks 0 or 16, assuming blank\n");
		} else {
			info(udev, "data in blocks 0 or 16, assuming complete\n");
		}
	}

determined:
	/* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in
	 * restricted overwrite mode can never append, only in sequential mode */
	if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro)
		cd_media_session_next = header[10] << 8 | header[5];
	cd_media_session_count = header[9] << 8 | header[4];
	cd_media_track_count = header[11] << 8 | header[6];

	return 0;
}
예제 #8
0
파일: cdrom_id.c 프로젝트: ystk/debian-udev
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;
}
예제 #9
0
파일: cdrom_id.c 프로젝트: OPSF/uClinux
static int cd_media_toc(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char header[12];
	unsigned char toc[2048];
	unsigned int len, i;
	unsigned char *p;
	int err;

	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 6, 1);
	scsi_cmd_set(udev, &sc, 8, sizeof(header));
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "READ TOC", err);
		return -1;
	}

	len = (header[0] << 8 | header[1]) + 2;
	info(udev, "READ TOC: len: %d\n", len);
	if (len > sizeof(toc))
		return -1;
	if (len < 2)
		return -1;

	/* empty media has no tracks */
	if (len < 8)
		return 0;

	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */
	scsi_cmd_set(udev, &sc, 7, len >> 8);
	scsi_cmd_set(udev, &sc, 8, len);
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, toc, len);
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "READ TOC (tracks)", err);
		return -1;
	}

	for (p = toc+4, i = 4; i < len-8; i += 8, p += 8) {
		unsigned int block;
		unsigned int is_data_track;

		is_data_track = (p[1] & 0x04) != 0;

		block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
		info(udev, "track=%u info=0x%x(%s) start_block=%u\n",
		     p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block);

		if (is_data_track)
			cd_media_track_count_data++;
		else
			cd_media_track_count_audio++;
	}

	scsi_cmd_set(udev, &sc, 0, 0x43);
	scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */
	scsi_cmd_set(udev, &sc, 8, 12);
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "READ TOC (multi session)", err);
		return -1;
	}
	len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7];
	info(udev, "last track %u starts at block %u\n", header[4+2], len);
	cd_media_session_last_offset = (unsigned long long int)len * 2048;
	return 0;
}
예제 #10
0
파일: cdrom_id.c 프로젝트: OPSF/uClinux
static int cd_profiles(struct udev *udev, int fd)
{
	struct scsi_cmd sc;
	unsigned char header[8];
	unsigned char profiles[512];
	unsigned int cur_profile;
	unsigned int len;
	unsigned int i;
	int err;

	scsi_cmd_set(udev, &sc, 0, 0x46);
	scsi_cmd_set(udev, &sc, 1, 0);
	scsi_cmd_set(udev, &sc, 8, sizeof(header));
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
		return -1;
	}

	len = 4 + (header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3]);
	info(udev, "GET CONFIGURATION: number of profiles %i\n", len);
	if (len > sizeof(profiles)) {
		info(udev, "invalid number of profiles\n");
		return -1;
	}

	scsi_cmd_set(udev, &sc, 0, 0x46);
	scsi_cmd_set(udev, &sc, 1, 1);
	scsi_cmd_set(udev, &sc, 6, len >> 16);
	scsi_cmd_set(udev, &sc, 7, len >> 8);
	scsi_cmd_set(udev, &sc, 8, len);
	scsi_cmd_set(udev, &sc, 9, 0);
	err = scsi_cmd_run(udev, &sc, fd, profiles, len);
	if ((err < 0)) {
		info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
		return -1;
	}

	/* device profiles */
	for (i = 12; i < profiles[11]; i += 4) {
		unsigned int profile = (profiles[i] << 8 | profiles[i + 1]);
		if (profile == 0)
			continue;
		info(udev, "profile 0x%02x\n", profile);

		switch (profile) {
		case 0x03:
		case 0x04:
		case 0x05:
			cd_mo = 1;
		break;
		case 0x10:
			cd_dvd_rom = 1;
			break;
		case 0x12:
			cd_dvd_ram = 1;
			break;
		case 0x13:
		case 0x14:
			cd_dvd_rw = 1;
			break;
		case 0x1B:
			cd_dvd_plus_r = 1;
			break;
		case 0x1A:
			cd_dvd_plus_rw = 1;
			break;
		case 0x2A:
			cd_dvd_plus_rw_dl = 1;
			break;
		case 0x2B:
			cd_dvd_plus_r_dl = 1;
			break;
		case 0x40:
			cd_bd = 1;
			break;
		case 0x41:
		case 0x42:
			cd_bd_r = 1;
			break;
		case 0x43:
			cd_bd_re = 1;
			break;
		case 0x50:
			cd_hddvd = 1;
			break;
		case 0x51:
			cd_hddvd_r = 1;
			break;
		case 0x52:
			cd_hddvd_rw = 1;
			break;
		default:
			break;
		}
	}

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

	switch (cur_profile) {
	case 0x03:
	case 0x04:
	case 0x05:
		cd_media_mo = 1;
		break;
	case 0x08:
		cd_media_cd_rom = 1;
		break;
	case 0x09:
		cd_media_cd_r = 1;
		break;
	case 0x0a:
		cd_media_cd_rw = 1;
		break;
	case 0x10:
		cd_media_dvd_rom = 1;
		break;
	case 0x11:
		cd_media_dvd_r = 1;
		break;
	case 0x12:
		cd_media_dvd_ram = 1;
		break;
	case 0x13:
	case 0x14:
		cd_media_dvd_rw = 1;
		break;
	case 0x1B:
		cd_media_dvd_plus_r = 1;
		break;
	case 0x1A:
		cd_media_dvd_plus_rw = 1;
		break;
	case 0x2A:
		cd_media_dvd_plus_rw_dl = 1;
		break;
	case 0x2B:
		cd_media_dvd_plus_r_dl = 1;
		break;
	case 0x40:
		cd_media_bd = 1;
		break;
	case 0x41:
	case 0x42:
		cd_media_bd_r = 1;
		break;
	case 0x43:
		cd_media_bd_re = 1;
		break;
	case 0x50:
		cd_media_hddvd = 1;
		break;
	case 0x51:
		cd_media_hddvd_r = 1;
		break;
	case 0x52:
		cd_media_hddvd_rw = 1;
		break;
	default:
		break;
	}
	return 0;
}
예제 #11
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;
}