Index: scsi/cd.c =================================================================== RCS file: /cvs/src/sys/scsi/cd.c,v retrieving revision 1.157 diff -u scsi/cd.c --- scsi/cd.c 16 Dec 2009 10:51:28 -0000 1.157 +++ scsi/cd.c 18 Mar 2010 20:06:07 -0000 @@ -67,6 +67,9 @@ #include #include #include +#include +#include +#include #include #include @@ -76,6 +79,8 @@ #include /* for BBSIZE and SBSIZE */ +#include "hotplug.h" + #define CDOUTSTANDING 4 #define MAXTRACK 99 @@ -114,6 +119,7 @@ struct mutex sc_queue_mtx; struct mutex sc_start_mtx; struct timeout sc_timeout; + struct timeout sc_mediatick; /* media check timer */ void *sc_cdpwrhook; /* our power hook */ }; @@ -150,6 +156,10 @@ int dvd_read_manufact(struct cd_softc *, union dvd_struct *); int dvd_read_struct(struct cd_softc *, union dvd_struct *); +void cd_mediatick(void *); +void cd_mediacheck(void *, void *); +int cd_get_media_event(struct cd_softc *); + void cd_powerhook(int why, void *arg); #if defined(__macppc__) @@ -246,6 +256,11 @@ timeout_set(&sc->sc_timeout, cdstart, sc); +#if NHOTPLUG > 0 + timeout_set(&sc->sc_mediatick, cd_mediatick, sc); + timeout_add(&sc->sc_mediatick, hz); +#endif + if ((sc->sc_cdpwrhook = powerhook_establish(cd_powerhook, sc)) == NULL) printf("%s: WARNING: unable to establish power hook\n", sc->sc_dev.dv_xname); @@ -293,6 +308,10 @@ if (sc->sc_cdpwrhook != NULL) powerhook_disestablish(sc->sc_cdpwrhook); +#if NHOTPLUG > 0 + timeout_del(&sc->sc_mediatick); +#endif + /* Detach disk. */ disk_detach(&sc->sc_dk); @@ -1947,6 +1966,75 @@ return (EINVAL); } } + +#if NHOTPLUG > 0 +void +cd_mediatick(void *arg) +{ + workq_add_task(NULL, 0, cd_mediacheck, arg, NULL); +} + +void +cd_mediacheck(void *arg1, void *arg2) +{ + struct cd_softc *sc = arg1; + int event; + + event = cd_get_media_event(sc); + + switch (event) { + case -1: + /* scsi error, not fatal */ + break; + case -2: + /* media events not supported, fatal */ + return; + case MEDIA_EJECT: + hotplug_device_detach(DV_DISK, sc->sc_dev.dv_xname); + break; + case MEDIA_NEW: + hotplug_device_attach(DV_DISK, sc->sc_dev.dv_xname); + break; + } + + timeout_add(&sc->sc_mediatick, hz); +} + +int +cd_get_media_event(struct cd_softc *sc) +{ + struct scsi_get_event_status cmd; + struct scsi_event_hdr *hdr; + struct scsi_media_event_data *me; + void *buf; + int data_len = sizeof(*hdr) + sizeof(*me); + int error; + + buf = malloc(data_len, M_TEMP, M_WAITOK); + if (buf == NULL) + return (-1); + hdr = buf; + me = (struct scsi_media_event_data *)(hdr + 1); + + bzero(&cmd, sizeof(cmd)); + cmd.opcode = GET_EVENT_STATUS; + cmd.immed = 1; + cmd.evclass = EVENT_MEDIAST; + _lto2b(data_len, cmd.data_len); + + error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, + sizeof(cmd), buf, data_len, 1, 1000, NULL, SCSI_DATA_IN); + if (error) + error = -1; + else if (hdr->nea) + error = -2; + else + error = me->event; + + free(buf, M_TEMP); + return (error); +} +#endif /* NHOTPLUG > 0 */ void cd_powerhook(int why, void *arg) Index: scsi/cd.h =================================================================== RCS file: /cvs/src/sys/scsi/cd.h,v retrieving revision 1.25 diff -u scsi/cd.h --- scsi/cd.h 16 Dec 2009 10:51:28 -0000 1.25 +++ scsi/cd.h 18 Mar 2010 20:06:07 -0000 @@ -183,6 +183,23 @@ u_int8_t control; }; +struct scsi_get_event_status { + u_int8_t opcode; + u_int immed:1, + reserved:7; + u_int8_t reserved2[2]; + u_int8_t evclass; +#define EVENT_OPCHANGE 0x02 +#define EVENT_PWRMGMT 0x04 +#define EVENT_EXTREQ 0x08 +#define EVENT_MEDIAST 0x10 +#define EVENT_MULTINIT 0x20 +#define EVENT_DEVBUSY 0x40 + u_int8_t reserved3[2]; + u_int8_t data_len[2]; + u_int8_t control; +}; + /* * Opcodes */ @@ -194,6 +211,7 @@ #define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */ #define PLAY_TRACK 0x48 /* cdrom play track/index mode */ #define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */ +#define GET_EVENT_STATUS 0x4a /* get event/status notification */ #define PAUSE 0x4b /* cdrom pause in 'play audio' mode */ #define READ_TRACK_INFO 0x52 /* read track/rzone info */ #define CLOSE_TRACK 0x5b /* close track/rzone/session/border */ @@ -268,6 +286,28 @@ u_int8_t len[2]; /* Big-endian length of valid data. */ u_int8_t reserved[2]; u_int8_t data[2048]; +}; + +struct scsi_event_hdr { + u_int8_t data_len[2]; + u_int evclass:3, + reserved:4, + nea:1; + u_int8_t supclass; +}; + +struct scsi_media_event_data { + u_int event:4, +#define MEDIA_EJECT 0x01 +#define MEDIA_NEW 0x02 +#define MEDIA_REMOVE 0x03 +#define MEDIA_CHANGE 0x04 + reserved:4; + u_int dooropen:1, + mediapresent:1, + reserved2:6; + u_int8_t startslot; + u_int8_t endslot; }; #endif