From b20fd3cb3423676a86f12189126b012d2297d5f7 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Jun 2011 20:54:47 +0200 Subject: [PATCH] cdrom_id: add tray lock and eject handling --- extras/cdrom_id/60-cdrom_id.rules | 12 ++-- extras/cdrom_id/cdrom_id.c | 124 +++++++++++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 31 deletions(-) diff --git a/extras/cdrom_id/60-cdrom_id.rules b/extras/cdrom_id/60-cdrom_id.rules index 1ad1d0c..896af34 100644 --- a/extras/cdrom_id/60-cdrom_id.rules +++ b/extras/cdrom_id/60-cdrom_id.rules @@ -5,10 +5,14 @@ SUBSYSTEM!="block", GOTO="cdrom_end" KERNEL!="sr[0-9]*|xvd*", GOTO="cdrom_end" ENV{DEVTYPE}!="disk", GOTO="cdrom_end" -# this is only a button press event -ENV{DISK_EJECT_REQUEST}=="?*", GOTO="cdrom_end" - +# unconditionally tag device as CDROM KERNEL=="sr[0-9]*", ENV{ID_CDROM}="1" -IMPORT{program}="cdrom_id $tempnode" + +# media eject button pressed +ENV{DISK_EJECT_REQUEST}=="?*", RUN+="cdrom_id --eject-media $tempnode", GOTO="cdrom_end" + +# import device and media properties and lock tray to +# enable the receiving of media eject button events +IMPORT{program}="cdrom_id --lock-media $tempnode" LABEL="cdrom_end" diff --git a/extras/cdrom_id/cdrom_id.c b/extras/cdrom_id/cdrom_id.c index 7908f6d..664a00d 100644 --- a/extras/cdrom_id/cdrom_id.c +++ b/extras/cdrom_id/cdrom_id.c @@ -41,7 +41,7 @@ #include "libudev.h" #include "libudev-private.h" -static int debug; +static bool debug; static void log_fn(struct udev *udev, int priority, const char *file, int line, const char *fn, @@ -156,13 +156,11 @@ struct scsi_cmd { struct sg_io_hdr sg_io; }; -static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd, unsigned char *buf, size_t bufsize) +static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd) { memset(cmd, 0x00, sizeof(struct scsi_cmd)); - memset(buf, 0x00, bufsize); cmd->cgc.quiet = 1; cmd->cgc.sense = &cmd->_sense.s; - memset(&cmd->sg_io, 0, sizeof(cmd->sg_io)); cmd->sg_io.interface_id = 'S'; cmd->sg_io.mx_sb_len = sizeof(cmd->_sense); cmd->sg_io.cmdp = cmd->cgc.cmd; @@ -182,9 +180,13 @@ static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigne { int ret = 0; - cmd->sg_io.dxferp = buf; - cmd->sg_io.dxfer_len = bufsize; - cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV; + if (bufsize > 0) { + cmd->sg_io.dxferp = buf; + cmd->sg_io.dxfer_len = bufsize; + cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV; + } else { + cmd->sg_io.dxfer_direction = SG_DXFER_NONE; + } if (ioctl(fd, SG_IO, &cmd->sg_io)) return -1; @@ -200,6 +202,39 @@ static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigne return ret; } +static int media_lock(struct udev *udev, int fd, bool lock) +{ + int err; + + /* disable the kernel's lock logic */ + err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK); + if (err < 0) + info(udev, "CDROM_CLEAR_OPTIONS, CDO_LOCK failed\n"); + + err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0); + if (err < 0) + info(udev, "CDROM_LOCKDOOR failed\n"); + + return err; +} + +static int media_eject(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + int err; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x1b); + scsi_cmd_set(udev, &sc, 4, 0x02); + scsi_cmd_set(udev, &sc, 5, 0); + err = scsi_cmd_run(udev, &sc, fd, NULL, 0); + if ((err != 0)) { + info_scsi_cmd_err(udev, "START_STOP_UNIT", err); + return -1; + } + return 0; +} + static int cd_capability_compat(struct udev *udev, int fd) { int capability; @@ -237,12 +272,13 @@ static int cd_media_compat(struct udev *udev, int fd) return 0; } -static int cd_inquiry(struct udev *udev, int fd) { +static int cd_inquiry(struct udev *udev, int fd) +{ struct scsi_cmd sc; unsigned char inq[128]; int err; - scsi_cmd_init(udev, &sc, inq, sizeof(inq)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x12); scsi_cmd_set(udev, &sc, 4, 36); scsi_cmd_set(udev, &sc, 5, 0); @@ -467,7 +503,7 @@ static int cd_profiles_old_mmc(struct udev *udev, int fd) unsigned char header[32]; - scsi_cmd_init(udev, &sc, header, sizeof(header)); + 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); @@ -513,7 +549,7 @@ static int cd_profiles(struct udev *udev, int fd) ret = -1; /* First query the current profile */ - scsi_cmd_init(udev, &sc, features, sizeof(features)); + 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); @@ -549,7 +585,7 @@ static int cd_profiles(struct udev *udev, int fd) } /* Now get the full feature buffer */ - scsi_cmd_init(udev, &sc, features, len); + 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); @@ -601,7 +637,7 @@ static int cd_media_info(struct udev *udev, int fd) }; int err; - scsi_cmd_init(udev, &sc, header, sizeof(header)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x51); scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); scsi_cmd_set(udev, &sc, 9, 0); @@ -639,7 +675,7 @@ static int cd_media_info(struct udev *udev, int fd) unsigned char dvdstruct[8]; unsigned char format[12]; - scsi_cmd_init(udev, &sc, dvdstruct, sizeof(dvdstruct)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0xAD); scsi_cmd_set(udev, &sc, 7, 0xC0); scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct)); @@ -656,7 +692,7 @@ static int cd_media_info(struct udev *udev, int fd) } /* let's make sure we don't try to read unformatted media */ - scsi_cmd_init(udev, &sc, format, sizeof(format)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x23); scsi_cmd_set(udev, &sc, 8, sizeof(format)); scsi_cmd_set(udev, &sc, 9, 0); @@ -697,7 +733,7 @@ static int cd_media_info(struct udev *udev, int fd) * 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_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x28); scsi_cmd_set(udev, &sc, 5, 0); scsi_cmd_set(udev, &sc, 8, 32); @@ -750,7 +786,7 @@ static int cd_media_toc(struct udev *udev, int fd) unsigned char *p; int err; - scsi_cmd_init(udev, &sc, header, sizeof(header)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x43); scsi_cmd_set(udev, &sc, 6, 1); scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); @@ -774,7 +810,7 @@ static int cd_media_toc(struct udev *udev, int fd) if (len < 8) return 0; - scsi_cmd_init(udev, &sc, toc, sizeof(toc)); + scsi_cmd_init(udev, &sc); 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); @@ -805,7 +841,7 @@ static int cd_media_toc(struct udev *udev, int fd) cd_media_track_count_audio++; } - scsi_cmd_init(udev, &sc, header, sizeof(header)); + scsi_cmd_init(udev, &sc); scsi_cmd_set(udev, &sc, 0, 0x43); scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */ scsi_cmd_set(udev, &sc, 8, sizeof(header)); @@ -825,10 +861,16 @@ int main(int argc, char *argv[]) { struct udev *udev; static const struct option options[] = { + { "lock-media", no_argument, NULL, 'l' }, + { "unlock-media", no_argument, NULL, 'u' }, + { "eject-media", no_argument, NULL, 'e' }, { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, {} }; + bool eject = false; + bool lock = false; + bool unlock = false; const char *node = NULL; int fd = -1; int cnt; @@ -844,18 +886,30 @@ int main(int argc, char *argv[]) while (1) { int option; - option = getopt_long(argc, argv, "dh", options, NULL); + option = getopt_long(argc, argv, "deluh", options, NULL); if (option == -1) break; switch (option) { + case 'l': + lock = true; + break; + case 'u': + unlock = true; + break; + case 'e': + eject = true; + break; case 'd': - debug = 1; + debug = true; if (udev_get_log_priority(udev) < LOG_INFO) udev_set_log_priority(udev, LOG_INFO); break; case 'h': printf("Usage: cdrom_id [options] \n" + " --lock-media lock the media (to enable eject request events)\n" + " --unlock-media unlock the media\n" + " --eject-media eject the media\n" " --debug debug to stderr\n" " --help print this help text\n\n"); goto exit; @@ -904,14 +958,13 @@ int main(int argc, char *argv[]) /* check if drive talks MMC */ if (cd_inquiry(udev, fd) < 0) - goto print; + goto work; /* read drive and possibly current profile */ if (cd_profiles(udev, fd) != 0) - goto print; + goto work; - /* at this point we are guaranteed to have media in the - * drive - find out more about it */ + /* at this point we are guaranteed to have media in the drive - find out more about it */ /* get session/track info */ cd_media_toc(udev, fd); @@ -919,7 +972,25 @@ int main(int argc, char *argv[]) /* get writable media state */ cd_media_info(udev, fd); -print: +work: + /* lock the media, so we enable eject button events */ + if (lock && cd_media) { + info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (lock)\n"); + media_lock(udev, fd, true); + } + + if (unlock && cd_media) { + info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n"); + media_lock(udev, fd, false); + } + + if (eject) { + info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n"); + media_lock(udev, fd, false); + info(udev, "START_STOP_UNIT (eject)\n"); + media_eject(udev, fd); + } + printf("ID_CDROM=1\n"); if (cd_cd_rom) printf("ID_CDROM_CD=1\n"); @@ -1026,4 +1097,3 @@ exit: udev_log_close(); return rc; } - -- 2.7.4