Index: libs/libmyth/mythmedia.cpp
===================================================================
--- libs/libmyth/mythmedia.cpp	(revision 7775)
+++ libs/libmyth/mythmedia.cpp	(working copy)
@@ -17,6 +17,8 @@
 
 // end for testing
 
+static const QString PATHTO_PMOUNT("/usr/bin/pmount");
+static const QString PATHTO_PUMOUNT("/usr/bin/pumount");
 static const QString PATHTO_MOUNT("/bin/mount");
 static const QString PATHTO_UNMOUNT("/bin/umount");
 static const QString PATHTO_MOUNTS("/proc/mounts");
@@ -25,6 +27,7 @@
 {
     "MEDIASTAT_ERROR",
     "MEDIASTAT_UNKNOWN",
+    "MEDIASTAT_UNPLUGGED",
     "MEDIASTAT_OPEN",
     "MEDIASTAT_USEABLE",
     "MEDIASTAT_NOTMOUNTED",
@@ -57,7 +60,8 @@
     m_Locked = false;
     m_DeviceHandle = -1;
     m_SuperMount = SuperMount;
-    m_Status = (isMounted(true)) ? MEDIASTAT_MOUNTED : MEDIASTAT_NOTMOUNTED;
+    m_Status = MEDIASTAT_UNKNOWN;
+    m_MediaType = MEDIATYPE_UNKNOWN;
 }
 
 bool MythMediaDevice::openDevice()
@@ -98,15 +102,23 @@
     if (!m_SuperMount) 
     {
         // Build a command line for mount/unmount and execute it...  Is there a better way to do this?
-        MountCommand = QString("%1 %2")
-            .arg((DoMount) ? PATHTO_MOUNT : PATHTO_UNMOUNT)
-            .arg(m_DevicePath);
+        if (QFile(PATHTO_PMOUNT).exists() && QFile(PATHTO_PUMOUNT).exists())
+            MountCommand = QString("%1 %2")
+                .arg((DoMount) ? PATHTO_PMOUNT : PATHTO_PUMOUNT)
+                .arg(m_DevicePath);
+        else
+            MountCommand = QString("%1 %2")
+                .arg((DoMount) ? PATHTO_MOUNT : PATHTO_UNMOUNT)
+                .arg(m_DevicePath);
     
         VERBOSE(VB_ALL,  QString("Executing '%1'").arg(MountCommand));
         if (0 == myth_system(MountCommand)) 
         {
             if (DoMount)
             {
+                // we cannot tell beforehand what the pmount mount point is
+                // so verify the mount status of the device
+                isMounted(true);
                 m_Status = MEDIASTAT_MOUNTED;
                 onDeviceMounted();
             }
@@ -213,20 +225,14 @@
             // the disk is not / should not be mounted.
             case MEDIASTAT_ERROR:
             case MEDIASTAT_OPEN:
-                if (MEDIASTAT_MOUNTED == OldStatus)
-                    unmount();
-                break;
             case MEDIASTAT_NOTMOUNTED:
-                if (MEDIASTAT_MOUNTED == OldStatus)
+                if (isMounted(true))
                     unmount();
-                // If we're here it's possible there's unmounted media in the device so try to mount it.
-                // The case of no media in the deivce whould be handeled by derived classes and sent
-                // as MEDIASTAT_OPEN, MEDISTAT_ERROR or MEDIASTAT_UNKNOWN.
-                mount();
                 break;
             case MEDIASTAT_UNKNOWN:
             case MEDIASTAT_USEABLE:
             case MEDIASTAT_MOUNTED:
+            case MEDIASTAT_UNPLUGGED:
                 // get rid of the compiler warning...
                 break;
         }
Index: libs/libmyth/mythmediamonitor.h
===================================================================
--- libs/libmyth/mythmediamonitor.h	(revision 7775)
+++ libs/libmyth/mythmediamonitor.h	(working copy)
@@ -48,16 +48,28 @@
 {
     Q_OBJECT
   public:
+    ~MediaMonitor();
+
     bool addFSTab(void);
+#ifdef linux
+    bool addPMountable(void);
+#endif
     void addDevice(MythMediaDevice* pDevice);
     bool addDevice(const char* dev);
     bool addDevice(struct fstab* mep);
+#ifdef linux
+    bool addSysFSDevice(const QString &dev, bool checkPartitions);
+    bool removeDevice(const QString &dev);
+    void checkUDev();
+#endif
 
     bool isActive(void) const { return m_Active; }
     void checkDevices(void);
     void startMonitoring(void);
     void stopMonitoring(void);
     QValueList <MythMediaDevice*> getMedias(MediaType mediatype);
+
+    void chooseAndEjectMedia();
     
     static MediaMonitor* getMediaMonitor();
     
@@ -70,6 +82,15 @@
     bool m_Active;
     MonitorThread m_Thread;
     bool m_AllowEject;
+#ifdef linux
+    int fifo;
+#endif
+
+  private:
+#ifdef linux
+    QString getDeviceFile(QString sysfs);
+    QStringList getCDROMBlockDevices();
+#endif
 };
 
 #endif
Index: libs/libmyth/mythhdd.h
===================================================================
--- libs/libmyth/mythhdd.h	(revision 0)
+++ libs/libmyth/mythhdd.h	(revision 0)
@@ -0,0 +1,31 @@
+#ifndef MYTHHDD_H
+#define MYTHHDD_H
+
+#include "mythmedia.h"
+
+class MythHDD : public MythMediaDevice
+{
+//    Q_OBJECT
+  public:
+    MythHDD(QObject* par, const char* DevicePath, bool SuperMount,
+            bool AllowEject);
+    virtual ~MythHDD() {};
+
+    // Commented out functions are implemented in MythMediaDevice, so can't
+    // be abstract here.
+
+    //virtual MediaError testMedia(void);
+    //virtual bool openDevice(void);
+    virtual MediaStatus checkMedia(void);
+    //virtual MediaError eject(void) = 0;
+    //virtual MediaError lock(void) = 0;
+    //virtual MediaError unlock(void) = 0;
+
+    static MythHDD* get(QObject* par, const char* devicePath, bool SuperMount,
+                          bool AllowEject);
+
+  protected:
+    //virtual void onDeviceMounted();
+};
+
+#endif
Index: libs/libmyth/mythcdrom.h
===================================================================
--- libs/libmyth/mythcdrom.h	(revision 7775)
+++ libs/libmyth/mythcdrom.h	(working copy)
@@ -19,7 +19,7 @@
     virtual bool checkOK(void) = 0;
     virtual bool openDevice(void);
     virtual MediaStatus checkMedia(void) = 0;
-    //virtual MediaError eject(void) = 0;
+    //virtual MediaError eject(bool open_close = true) = 0;
     //virtual MediaError lock(void) = 0;
     //virtual MediaError unlock(void) = 0;
 
@@ -42,7 +42,7 @@
     virtual bool mediaChanged(void);
     virtual bool checkOK(void);
     virtual MediaStatus checkMedia(void);
-    virtual MediaError eject(void);
+    virtual MediaError eject(bool open_close = true);
     virtual MediaError lock(void);
     virtual MediaError unlock(void);
 };
@@ -60,7 +60,7 @@
     virtual bool mediaChanged(void);
     virtual bool checkOK(void);
     virtual MediaStatus checkMedia(void);
-    virtual MediaError eject(void);
+    virtual MediaError eject(bool open_close = true);
     virtual MediaError lock(void);
     virtual MediaError unlock(void);
 };
Index: libs/libmyth/mythdialogs.cpp
===================================================================
--- libs/libmyth/mythdialogs.cpp	(revision 7775)
+++ libs/libmyth/mythdialogs.cpp	(working copy)
@@ -234,6 +234,8 @@
     RegisterKey("Global", "7", "7", "7");
     RegisterKey("Global", "8", "8", "8");
     RegisterKey("Global", "9", "9", "9");
+
+    RegisterKey("Global", "EJECT", "Eject Removable Media", "e");
 }
 
 MythMainWindow::~MythMainWindow()
@@ -1099,6 +1101,12 @@
             }
             else if (action == "MENU")
                 emit menuButtonPressed();
+            else if (action == "EJECT")
+            {
+                MediaMonitor *mon = MediaMonitor::getMediaMonitor();
+                if (mon)
+                    mon->chooseAndEjectMedia();
+            }
             else
                 handled = false;
         }
Index: libs/libmyth/libmyth.pro
===================================================================
--- libs/libmyth/libmyth.pro	(revision 7775)
+++ libs/libmyth/libmyth.pro	(working copy)
@@ -68,9 +68,9 @@
 }
 
 unix {
-    SOURCES += mythcdrom.cpp mythmediamonitor.cpp
-    HEADERS += mythcdrom.h   mythmediamonitor.h
-    inc.files += mythcdrom.h mythmediamonitor.h
+    SOURCES += mythhdd.cpp mythcdrom.cpp mythmediamonitor.cpp
+    HEADERS += mythhdd.cpp mythcdrom.h   mythmediamonitor.h
+    inc.files += mythhdd.h mythcdrom.h mythmediamonitor.h
 }
 
 macx {
Index: libs/libmyth/mythmediamonitor.cpp
===================================================================
--- libs/libmyth/mythmediamonitor.cpp	(revision 7775)
+++ libs/libmyth/mythmediamonitor.cpp	(working copy)
@@ -1,6 +1,10 @@
 #include "mythmediamonitor.h"
 #include "mythcdrom.h"
+#include "mythhdd.h"
 #include <qapplication.h>
+#include <qprocess.h>
+#include <qdir.h>
+#include <qfile.h>
 #include <sys/file.h>
 #include <fcntl.h>
 #include <dirent.h>
@@ -9,10 +13,12 @@
 #include <iostream>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include "config.h"
 #include "mythcontext.h"
+#include "mythdialogs.h"
 
 // For testing
 #if 0
@@ -40,6 +46,10 @@
 #endif
 #define SUPER_OPT_DEV "dev="
 
+#ifndef UDEV_FIFO
+#define UDEV_FIFO "/tmp/mythtv_media"
+#endif
+
 using namespace std;
 
 MediaMonitor *theMonitor = NULL;
@@ -53,12 +63,96 @@
         {
             theMonitor = new MediaMonitor(NULL, 500, true);
             theMonitor->addFSTab();
+#ifdef linux
+            theMonitor->addPMountable();
+#endif
         }
     }
 
     return theMonitor;
 }
 
+/** \fn MediaMonitor::chooseAndEjectMedia()
+ *  \brief Unmounts and ejects removable media devices.
+ *
+ *  If no media devices are known to the MediaMonitor this function does
+ *  nothing. If a single device is known, it is unmounted and ejected if
+ *  possible. If mulitple devices are known, a popup box is display so the
+ *  user can choose which device to eject.
+ */
+void MediaMonitor::chooseAndEjectMedia()
+{
+    MythMediaDevice *selected = NULL;
+
+    if (m_Devices.count() == 1)
+    {
+        selected = m_Devices.first();
+    }
+    else if (m_Devices.count() > 1)
+    {
+        MythPopupBox ejectbox(gContext->GetMainWindow(), "eject media");
+
+        ejectbox.addLabel(tr("Select removable media to eject"));
+
+        QValueList <MythMediaDevice *>::Iterator it = m_Devices.begin();
+        while (it != m_Devices.end())
+        {
+            if ((*it)->getVolumeID() != "")
+                ejectbox.addButton((*it)->getVolumeID());
+            else
+                ejectbox.addButton((*it)->getDevicePath());
+
+            it++;
+        }
+
+        ejectbox.addButton(tr("Cancel"))->setFocus();
+
+        int ret = ejectbox.ExecPopup();
+
+        if (ret < (int)m_Devices.count())
+            selected = m_Devices[ret];
+    }
+
+    if (selected)
+    {
+        switch (selected->getStatus())
+        {
+            case MEDIASTAT_OPEN     : selected->eject(false);
+                                      break;
+            case MEDIASTAT_MOUNTED  : cerr << "media is mounted" << endl;
+                                      selected->unmount();
+
+                                      if (selected->isMounted(true))
+                                      {
+                                          MythPopupBox::showOkPopup(
+                                             gContext->GetMainWindow(),
+                                             "eject unmount fail",
+                                             QString(tr("Failed unmounting %1"))
+                                               .arg(selected->getDevicePath()));
+                                          break;
+                                      }
+            default                 : // attempt to unlock and eject media
+                                      selected->unlock();
+                                      if (selected->eject() == MEDIAERR_UNSUPPORTED)
+                                      {
+                                          MythPopupBox::showOkPopup(
+                                             gContext->GetMainWindow(),
+                                             "eject success",
+                                             QString(tr("You may safely remove %1"))
+                                               .arg(selected->getDevicePath()));
+                                      }
+                                      else if (selected->eject() == MEDIAERR_FAILED)
+                                      {
+                                          MythPopupBox::showOkPopup(
+                                             gContext->GetMainWindow(),
+                                             "eject fail",
+                                             QString(tr("Failed Ejecting %1"))
+                                               .arg(selected->getDevicePath()));
+                                      }
+        }
+    }
+}
+
 // MonitorThread
 MonitorThread::MonitorThread(MediaMonitor* pMon, unsigned long interval) 
              : QThread()
@@ -88,8 +182,22 @@
     m_AllowEject = allowEject;
     m_Active = false;
     m_Thread.setMonitor(this);
+#ifdef linux
+    fifo = 0;
+#endif
 }
 
+MediaMonitor::~MediaMonitor()
+{
+#ifdef linux
+    if (fifo)
+    {
+        close(fifo);
+        unlink(UDEV_FIFO);
+    }
+#endif
+}
+
 // Loop through the file system table and add any supported devices.
 bool MediaMonitor::addFSTab()
 {
@@ -119,6 +227,108 @@
     return true;
 }
 
+#ifdef linux
+/** \fn MediaMonitor::addPMountable()
+ *  \brief Search /sys/block for valid removable media devices.
+ *
+ *  This function creates MediaDevice instances for valid removable media
+ *  devices found under the /sys/block filesystem in Linux.  CD and DVD
+ *  devices are created as MythCDROM instances.  MythHDD instances will be
+ *  created for each partition on removable hard disc devices, if they exists.
+ *  Otherwise a single MythHDD instance will be created for the entire disc.
+ *  Floppy discs are ignored.
+ */
+bool MediaMonitor::addPMountable()
+{
+    mkfifo(UDEV_FIFO, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+    fifo = open(UDEV_FIFO, O_RDONLY | O_NONBLOCK);
+
+    QDir sysfs("/sys/block");
+    sysfs.setFilter(QDir::Dirs);
+
+    QStringList devices = sysfs.entryList();
+
+    for (QStringList::Iterator it = devices.begin(); it != devices.end(); ++it)
+    {
+        if (*it == "." || *it == "..")
+            continue;
+
+        // we don't do floppies.
+        if ((*it).startsWith("fd"))
+            continue;
+
+        sysfs.cd(*it);
+
+        QFile removable(sysfs.absFilePath("removable"));
+        if (removable.exists())
+        {
+            removable.open(IO_ReadOnly);
+            int c = removable.getch();
+            removable.close();
+
+            if (c == '1')
+                addSysFSDevice(sysfs.absPath(), true);
+        }
+        sysfs.cdUp();
+    }
+    return true;
+}
+
+/** \fn MediaMonitor::getDeviceFile(QString)
+ *  \brief Returns the device special file associated with the /sys/block node.
+ *  \param [in]sysfs sysfs path of removable block device.
+ *  \return path to the device special file
+ */
+QString MediaMonitor::getDeviceFile(QString sysfs)
+{
+    QProcess udevinfo(this);
+    udevinfo.addArgument("udevinfo");
+    udevinfo.addArgument("-q");
+    udevinfo.addArgument("name");
+    udevinfo.addArgument("-p");
+    udevinfo.addArgument(sysfs);
+    udevinfo.setCommunication(QProcess::Stdout);
+
+    udevinfo.start();
+
+    int status;
+    waitpid(udevinfo.processIdentifier(), &status, 0);
+
+    QString ret = udevinfo.readLineStdout();
+    if (ret == "device not found in database")
+        return QString::null;
+    else
+        return ret;
+}
+
+/** \fn MediaMonitor::getCDROMBlockDevices()
+ *  \brief Reads the list devices known to be CD or DVD devices.
+ *  \return list of CD and DVD device names.
+ */
+QStringList MediaMonitor::getCDROMBlockDevices()
+{
+    QStringList l;
+
+    QFile file("/proc/sys/dev/cdrom/info");
+    if (file.open(IO_ReadOnly))
+    {
+        QTextStream stream(&file);
+        QString line;
+        while (!stream.atEnd())
+        {
+            line = stream.readLine();
+            if (line.startsWith("drive name:"))
+            {
+                QString s = line.section('\t', 2, 2);
+                l.append(s);
+            }
+        }
+        file.close();
+    }
+    return l;
+}
+#endif
+
 // Given a media deivce add it to our collection.
 void MediaMonitor::addDevice(MythMediaDevice* pDevice)
 {
@@ -271,9 +481,161 @@
     return false;
 }
 
+#ifdef linux
+/** \fn MediaMonitor::addSysFSDevice(const QString &, bool)
+ *  \brief Creates MythMedia instances for sysfs removable media devices.
+ *  \param [in]dev path to sysfs block device.
+ *  \param [in]checkPartitions check for partitions on block device.
+ *  \return true if MythMedia instances are created.
+ *
+ *  Block devices are represented as directories in sysfs with directories for
+ *  each partition underneath the parent device directory.
+ *
+ *  This function recursively calls itself to find all partitions on a block
+ *  device and creates a MythHDD instance for each partition found.  If no
+ *  partitions are found and the device is a CD or DVD device a MythCDROM
+ *  instance is created.  Otherwise a MythHDD instance is created for the
+ *  entire block device.
+ */
+bool MediaMonitor::addSysFSDevice(const QString &dev, bool checkPartitions)
+{
+    if (checkPartitions)
+    {
+        // check for partitions
+        QDir sysfs(dev);
+        sysfs.setFilter(QDir::Dirs);
+
+        bool found_partitions = false;
+        QStringList parts = sysfs.entryList();
+        for (QStringList::Iterator pit = parts.begin();
+             pit != parts.end(); pit++)
+        {
+            if (*pit == "." || *pit == "..")
+                continue;
+
+            found_partitions |= addSysFSDevice(sysfs.absFilePath(*pit), false);
+        }
+
+        // no partitions on block device, use main device
+        if (!found_partitions)
+            found_partitions |= addSysFSDevice(sysfs.absPath(), false);
+
+        return found_partitions;
+    }
+    else
+    {
+        QStringList cdroms = getCDROMBlockDevices();
+
+        if (cdroms.contains(dev.section('/', -1)))
+        {
+            // found cdrom device
+            QString device_file = getDeviceFile(dev);
+            if (!device_file.isNull())
+            {
+                device_file.prepend("/dev/");
+                //cerr << "cdrom: " << device_file.ascii() << endl;
+
+                addDevice(MythCDROM::get(this, device_file, false, m_AllowEject));
+                return true;
+            }
+        }
+        else
+        {
+            // found block or partition device
+            QString device_file = getDeviceFile(dev);
+            if (!device_file.isNull())
+            {
+                device_file.prepend("/dev/");
+                //cerr << "block: " << device_file.ascii() << endl;
+
+                addDevice(MythHDD::get(this, device_file, false, false));
+
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/** \fn MediaMonitor::removeDevice(const QString &)
+ *  \brief Remove a device from the media monitor.
+ *  \param [in]dev path to device special file to remove.
+ *  \return true if device is removed from the Media Monitor.
+ *
+ *  This function is usually called after a hotpluggable device is unplugged.
+ */
+bool MediaMonitor::removeDevice(const QString &dev)
+{
+    QValueList<MythMediaDevice*>::iterator it;
+    for (it = m_Devices.begin(); it != m_Devices.end(); it++)
+    {
+        if ((*it)->getDevicePath() == dev)
+        {
+            m_Devices.remove(it);
+            //cerr << "remove device: " << dev.ascii() << endl;
+            return true;
+        }
+    }
+    return false;
+}
+
+/** \fn MediaMonitor::checkUDev()
+ *  \brief Checks the named pipe, UDEV_FIFO, for hotplug events from the udev system.
+ */
+void MediaMonitor::checkUDev()
+{
+    char buffer[256];
+    QString qBuffer;
+
+    if (fifo)
+    {
+        int size = read(fifo, buffer, 255);
+        while (size > 0)
+        {
+            // append buffer to QString
+            buffer[size] = '\0';
+
+            qBuffer.append(buffer);
+
+            size = read(fifo, buffer, 255);
+        }
+        QStringList devs = QStringList::split('\n', qBuffer);
+
+        for (QStringList::Iterator it = devs.begin(); it != devs.end(); it++)
+        {
+            if ((*it).startsWith("add"))
+            {
+                QString dev = (*it).section(' ', 1, 1);
+
+                // check if removeable
+                QFile removable(dev + "/removable");
+                if (removable.exists())
+                {
+                    removable.open(IO_ReadOnly);
+                    int c = removable.getch();
+                    removable.close();
+
+                    if (c == '1')
+                        addSysFSDevice((*it).section(' ', 1, 1), true);
+                }
+            }
+            else if ((*it).startsWith("remove"))
+            {
+                removeDevice((*it).section(' ', 2, 2));
+            }
+        }
+    }
+}
+#endif
+
 // Poll the devices in our list.
 void MediaMonitor::checkDevices()
 {
+#ifdef linux
+    /* check if new devices have been plugged in */
+    checkUDev();
+#endif
+
     QValueList<MythMediaDevice*>::iterator itr = m_Devices.begin();
     MythMediaDevice* pDev;
     while (itr != m_Devices.end()) 
@@ -317,7 +679,8 @@
         pDev = *itr;
         if ((pDev->getMediaType()==mediatype) &&
             ((pDev->getStatus()==MEDIASTAT_USEABLE) ||
-            (pDev->getStatus()==MEDIASTAT_MOUNTED)))
+             (pDev->getStatus()==MEDIASTAT_MOUNTED) ||
+             (pDev->getStatus()==MEDIASTAT_NOTMOUNTED)))
             medias.push_back(pDev);
         itr++;
     }
@@ -345,3 +708,4 @@
                                 new MediaEvent(oldStatus, pMedia));
     }
 }
+
Index: libs/libmyth/mythhdd.cpp
===================================================================
--- libs/libmyth/mythhdd.cpp	(revision 0)
+++ libs/libmyth/mythhdd.cpp	(revision 0)
@@ -0,0 +1,68 @@
+#include "mythhdd.h"
+
+#include <iostream>
+
+/** \fn MythHDD::get(QObject*, const char*, bool, bool)
+ *  \brief Helper function used to create a new instance of a hard disc device.
+ *  \param [in]devicePath path to the device special file representing the device.
+ *  \return new MythHDD instance.
+ */
+MythHDD *MythHDD::get(QObject* par, const char* devicePath, bool SuperMount,
+                      bool AllowEject)
+{
+    return new MythHDD(par, devicePath, SuperMount, AllowEject);
+}
+
+/** \fn MythHDD::MythHDD(QObject *, const char *, bool, bool)
+ *  \brief Creates a new instance of a hard disc device.
+ *  \param [in]DevicePath path to the device special file representing the device.
+ *  \return new MythHDD instance.
+ */
+MythHDD::MythHDD(QObject *par, const char *DevicePath, bool SuperMount,
+                 bool AllowEject)
+       : MythMediaDevice(par, DevicePath, SuperMount, AllowEject)
+{
+    m_Status = MEDIASTAT_UNPLUGGED;
+    m_MediaType = MEDIATYPE_DATA;       // default type is data
+}
+
+/** \fn MythHDD::checkMedia()
+ *  \brief Checks the status of this media device.
+ */
+MediaStatus MythHDD::checkMedia()
+{
+    if (isMounted(true))
+    {
+        // device is mounted, trigger event
+        //std::cerr << "status -> mounted" << std::endl;
+        return setStatus(MEDIASTAT_MOUNTED);
+    }
+    else
+    {
+        // device is not mounted
+        if (m_Status == MEDIASTAT_UNPLUGGED)
+        {
+            // a removable device was just plugged in try to mount it.
+            mount();
+            if (isMounted(true))
+            {
+                m_Status = MEDIASTAT_NOTMOUNTED;
+                return setStatus(MEDIASTAT_MOUNTED);
+            }
+            else
+                return setStatus(MEDIASTAT_NOTMOUNTED);
+        }
+        else if (m_Status == MEDIASTAT_MOUNTED)
+        {
+            // device was mounted and someone unmounted it.
+            // set its status to NOTMOUNTED */
+            //std::cerr << "status -> useable (via unmount)" << std::endl;
+            return m_Status = setStatus(MEDIASTAT_NOTMOUNTED);
+        }
+        else
+        {
+            // leave device state as is
+            return m_Status;
+        }
+    }
+}
Index: libs/libmyth/mythcdrom-linux.cpp
===================================================================
--- libs/libmyth/mythcdrom-linux.cpp	(revision 7775)
+++ libs/libmyth/mythcdrom-linux.cpp	(working copy)
@@ -8,10 +8,14 @@
 
 #define ASSUME_WANT_AUDIO 1
 
-MediaError MythCDROMLinux::eject() 
+MediaError MythCDROMLinux::eject(bool open_close)
 {
-    return (ioctl(m_DeviceHandle, CDROMEJECT) == 0) ? MEDIAERR_OK : 
-                                                      MEDIAERR_FAILED;
+    if (open_close)
+        return (ioctl(m_DeviceHandle, CDROMEJECT) == 0) ? MEDIAERR_OK :
+                                                          MEDIAERR_FAILED;
+    else
+        return (ioctl(m_DeviceHandle, CDROMCLOSETRAY) == 0) ? MEDIAERR_OK :
+                                                              MEDIAERR_FAILED;
 }
 
 bool MythCDROMLinux::mediaChanged()
@@ -85,8 +89,9 @@
         {
             case CDS_DISC_OK:
                 //cout << "disk ok - ";
-                if (isMounted(true))
-                    //cout << "it's mounted" << endl;
+                // If the disc is ok and we already know it's mediatype
+                // returns MOUNTED.
+                if (isMounted(true) && m_MediaType != MEDIATYPE_UNKNOWN)
                     return setStatus(MEDIASTAT_MOUNTED, OpenedHere);
                 // If the disk is ok but not yet mounted we'll test it further down after this switch exits.
                 break;
@@ -110,7 +115,7 @@
         if (mediaChanged()) 
         {
             //cout << "media changed - ";
-            // Regardless of the actual status lie here and say it's open for now, so we can over the case of a missed open.
+            // Regardless of the actual status lie here and say it's open for now, so we can cover the case of a missed open.
             return setStatus(MEDIASTAT_OPEN, OpenedHere);
         } 
         else 
@@ -136,9 +141,21 @@
                         this->m_KeyID = QString("%1%2")
                                       .arg(this->m_VolumeID)
                                       .arg(QString(buf.creation_date).left(16));
-                        // We'll return NOTMOUNTED  here because we're switching media.
-                        // The base class will try to mount the deivce causing the next pass to pick up the MOUNTED status.
-                        return setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
+
+                        // attempt to mount the disc
+                        // the base class's onDeviceMounted will do fine
+                        // grained detection of the type of data on this disc
+                        mount();
+
+                        if (isMounted(true))
+                        {
+                            // pretend we're NOTMOUNTED so setStatus emits
+                            // a signal
+                            m_Status = MEDIASTAT_NOTMOUNTED;
+                            return setStatus(MEDIASTAT_MOUNTED, OpenedHere);
+                        }
+                        else
+                            return setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
                         break;
                     case CDS_AUDIO:
                         //cout << "found an audio disk" << endl;
@@ -154,7 +171,15 @@
                             return setStatus(MEDIASTAT_USEABLE, OpenedHere);
                         #else
                             mount();
-                            return setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
+                            if (isMounted(true))
+                            {
+                                // pretend we're NOTMOUNTED so setStatus
+                                // emits a signal
+                                m_Status = MEDIASTAT_NOTMOUNTED;
+                                return setStatus(MEDIASTAT_MOUNTED, OpenedHere);
+                            }
+                            else
+                                return setStatus(MEDIASTAT_USEABLE, OpenedHere);
                         #endif
                         break;
                     case CDS_NO_INFO:
@@ -174,7 +199,10 @@
                      m_Status == MEDIASTAT_NOTMOUNTED) 
             {
                 //cout << "current status == " << MythMediaDevice::MediaStatusStrings[m_Status] << " setting status to not mounted - ";
-                setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
+                if (isMounted(true))
+                    setStatus(MEDIASTAT_MOUNTED, OpenedHere);
+                else
+                    setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
             }
 
             if (m_AllowEject)
Index: libs/libmyth/mythcdrom-freebsd.cpp
===================================================================
--- libs/libmyth/mythcdrom-freebsd.cpp	(revision 7775)
+++ libs/libmyth/mythcdrom-freebsd.cpp	(working copy)
@@ -7,11 +7,13 @@
 
 #define ASSUME_WANT_AUDIO 1
 
-MediaError MythCDROMFreeBSD::eject() 
+MediaError MythCDROMFreeBSD::eject(bool open_close)
 {
-    if (ioctl(m_DeviceHandle, CDIOCEJECT) == 0)
-        return MEDIAERR_OK;
-    return MEDIAERR_FAILED;
+    if (open_close)
+        return (ioctl(m_DeviceHandle, CDIOCEJECT) == 0) ? MEDIAERR_OK :
+                                                          MEDIAERR_FAILED;
+    else
+        return MEDIAERR_UNSUPPORTED;
 }
 
 bool MythCDROMFreeBSD::mediaChanged()
Index: libs/libmyth/mythmedia.h
===================================================================
--- libs/libmyth/mythmedia.h	(revision 7775)
+++ libs/libmyth/mythmedia.h	(working copy)
@@ -7,6 +7,7 @@
 typedef enum {
     MEDIASTAT_ERROR,
     MEDIASTAT_UNKNOWN,
+    MEDIASTAT_UNPLUGGED,
     MEDIASTAT_OPEN,
     MEDIASTAT_USEABLE,    
     MEDIASTAT_NOTMOUNTED,
@@ -65,7 +66,7 @@
     virtual bool openDevice();
     virtual bool closeDevice();
     virtual MediaStatus checkMedia() = 0; // Derived classes MUST implement this.
-    virtual MediaError eject() { return MEDIAERR_UNSUPPORTED; }
+    virtual MediaError eject(bool open_close = true) { return MEDIAERR_UNSUPPORTED; }
     virtual MediaError lock();
     virtual MediaError unlock();
     virtual bool performMountCmd( bool DoMount );    
Index: contrib/mythtv_media_monitor.sh
===================================================================
--- contrib/mythtv_media_monitor.sh	(revision 0)
+++ contrib/mythtv_media_monitor.sh	(revision 0)
@@ -0,0 +1,7 @@
+#!/bin/sh -e
+
+MYTH_FIFO=/tmp/mythtv_media
+
+if [ -p $MYTH_FIFO ]; then
+    echo $ACTION /sys$DEVPATH $DEVNAME > $MYTH_FIFO
+fi
Index: contrib/mythtv.rules
===================================================================
--- contrib/mythtv.rules	(revision 0)
+++ contrib/mythtv.rules	(revision 0)
@@ -0,0 +1,2 @@
+
+SUBSYSTEM="block", RUN+="/etc/udev/scripts/mythtv.sh"
