1 /*
2 Copyright 2010 Michael Zanetti <mzanetti@kde.org>
3 Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) version 3, or any
9 later version accepted by the membership of KDE e.V. (or its
10 successor approved by the membership of KDE e.V.), which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29
30 #include <QFile>
31 #include <QDebug>
32
33 #include "udisksopticaldrive.h"
34 #include "udisks2.h"
35 #include "udisksdevice.h"
36 #include "dbus/manager.h"
37
38 using namespace Solid::Backends::UDisks2;
39
OpticalDrive(Device * device)40 OpticalDrive::OpticalDrive(Device *device)
41 : StorageDrive(device)
42 , m_ejectInProgress(false)
43 , m_readSpeed(0)
44 , m_writeSpeed(0)
45 , m_speedsInit(false)
46 {
47 m_device->registerAction("eject", this,
48 SLOT(slotEjectRequested()),
49 SLOT(slotEjectDone(int, const QString&)));
50
51 connect(m_device, SIGNAL(changed()), this, SLOT(slotChanged()));
52 }
53
~OpticalDrive()54 OpticalDrive::~OpticalDrive()
55 {
56 }
57
eject()58 bool OpticalDrive::eject()
59 {
60 if (m_ejectInProgress)
61 return false;
62 m_ejectInProgress = true;
63 m_device->broadcastActionRequested("eject");
64
65 const QString path = m_device->udi();
66 QDBusConnection c = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "Solid::Udisks2::OpticalDrive::" + path);
67
68 // if the device is mounted, unmount first
69 QString blockPath;
70 org::freedesktop::DBus::ObjectManager manager(UD2_DBUS_SERVICE, UD2_DBUS_PATH, c);
71 QDBusPendingReply<DBUSManagerStruct> reply = manager.GetManagedObjects();
72 reply.waitForFinished();
73 if (!reply.isError()) { // enum devices
74 Q_FOREACH(const QDBusObjectPath &objPath, reply.value().keys()) {
75 const QString udi = objPath.path();
76
77 //qDebug() << "Inspecting" << udi;
78
79 if (udi == UD2_DBUS_PATH_MANAGER || udi == UD2_UDI_DISKS_PREFIX || udi.startsWith(UD2_DBUS_PATH_JOBS))
80 continue;
81
82 Device device(udi);
83 if (device.drivePath() == path && device.isMounted()) {
84 //qDebug() << "Got mounted block device:" << udi;
85 blockPath = udi;
86 break;
87 }
88 }
89 }
90 else // show error
91 {
92 qWarning() << "Failed enumerating UDisks2 objects:" << reply.error().name() << "\n" << reply.error().message();
93 }
94
95 if (!blockPath.isEmpty()) {
96 //qDebug() << "Calling unmount on" << blockPath;
97 QDBusMessage msg = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, blockPath, UD2_DBUS_INTERFACE_FILESYSTEM, "Unmount");
98 msg << QVariantMap(); // options, unused now
99 c.call(msg, QDBus::BlockWithGui);
100 }
101
102 QDBusMessage msg = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, path, UD2_DBUS_INTERFACE_DRIVE, "Eject");
103 msg << QVariantMap();
104 return c.callWithCallback(msg, this, SLOT(slotDBusReply(const QDBusMessage &)), SLOT(slotDBusError(const QDBusError &)));
105 }
106
slotDBusReply(const QDBusMessage &)107 void OpticalDrive::slotDBusReply(const QDBusMessage &/*reply*/)
108 {
109 m_ejectInProgress = false;
110 m_device->broadcastActionDone("eject");
111 }
112
slotDBusError(const QDBusError & error)113 void OpticalDrive::slotDBusError(const QDBusError &error)
114 {
115 m_ejectInProgress = false;
116 m_device->broadcastActionDone("eject", m_device->errorToSolidError(error.name()),
117 m_device->errorToString(error.name()) + ": " +error.message());
118 }
119
slotEjectRequested()120 void OpticalDrive::slotEjectRequested()
121 {
122 m_ejectInProgress = true;
123 Q_EMIT ejectRequested(m_device->udi());
124 }
125
slotEjectDone(int error,const QString & errorString)126 void OpticalDrive::slotEjectDone(int error, const QString &errorString)
127 {
128 m_ejectInProgress = false;
129 Q_EMIT ejectDone(static_cast<Solid::ErrorType>(error), errorString, m_device->udi());
130 }
131
initReadWriteSpeeds() const132 void OpticalDrive::initReadWriteSpeeds() const
133 {
134 #if 0
135 int read_speed, write_speed;
136 char *write_speeds = 0;
137 QByteArray device_file = QFile::encodeName(m_device->property("Device").toString());
138
139 //qDebug("Doing open (\"%s\", O_RDONLY | O_NONBLOCK)", device_file.constData());
140 int fd = open(device_file, O_RDONLY | O_NONBLOCK);
141 if (fd < 0) {
142 qWarning("Cannot open %s: %s", device_file.constData(), strerror (errno));
143 return;
144 }
145
146 if (get_read_write_speed(fd, &read_speed, &write_speed, &write_speeds) >= 0) {
147 m_readSpeed = read_speed;
148 m_writeSpeed = write_speed;
149
150 QStringList list = QString::fromLatin1(write_speeds).split(',', QString::SkipEmptyParts);
151 Q_FOREACH (const QString & speed, list)
152 m_writeSpeeds.append(speed.toInt());
153
154 free(write_speeds);
155
156 m_speedsInit = true;
157 }
158
159 close(fd);
160 #endif
161 }
162
writeSpeeds() const163 QList<int> OpticalDrive::writeSpeeds() const
164 {
165 if (!m_speedsInit)
166 initReadWriteSpeeds();
167 //qDebug() << "solid write speeds:" << m_writeSpeeds;
168 return m_writeSpeeds;
169 }
170
writeSpeed() const171 int OpticalDrive::writeSpeed() const
172 {
173 if (!m_speedsInit)
174 initReadWriteSpeeds();
175 return m_writeSpeed;
176 }
177
readSpeed() const178 int OpticalDrive::readSpeed() const
179 {
180 if (!m_speedsInit)
181 initReadWriteSpeeds();
182 return m_readSpeed;
183 }
184
supportedMedia() const185 Solid::OpticalDrive::MediumTypes OpticalDrive::supportedMedia() const
186 {
187 const QStringList mediaTypes = m_device->prop("MediaCompatibility").toStringList();
188 Solid::OpticalDrive::MediumTypes supported;
189
190 QMap<Solid::OpticalDrive::MediumType, QString> map;
191 map[Solid::OpticalDrive::Cdr] = "optical_cd_r";
192 map[Solid::OpticalDrive::Cdrw] = "optical_cd_rw";
193 map[Solid::OpticalDrive::Dvd] = "optical_dvd";
194 map[Solid::OpticalDrive::Dvdr] = "optical_dvd_r";
195 map[Solid::OpticalDrive::Dvdrw] ="optical_dvd_rw";
196 map[Solid::OpticalDrive::Dvdram] ="optical_dvd_ram";
197 map[Solid::OpticalDrive::Dvdplusr] ="optical_dvd_plus_r";
198 map[Solid::OpticalDrive::Dvdplusrw] ="optical_dvd_plus_rw";
199 map[Solid::OpticalDrive::Dvdplusdl] ="optical_dvd_plus_r_dl";
200 map[Solid::OpticalDrive::Dvdplusdlrw] ="optical_dvd_plus_rw_dl";
201 map[Solid::OpticalDrive::Bd] ="optical_bd";
202 map[Solid::OpticalDrive::Bdr] ="optical_bd_r";
203 map[Solid::OpticalDrive::Bdre] ="optical_bd_re";
204 map[Solid::OpticalDrive::HdDvd] ="optical_hddvd";
205 map[Solid::OpticalDrive::HdDvdr] ="optical_hddvd_r";
206 map[Solid::OpticalDrive::HdDvdrw] ="optical_hddvd_rw";
207 // TODO add these to Solid
208 //map[Solid::OpticalDrive::Mo] ="optical_mo";
209 //map[Solid::OpticalDrive::Mr] ="optical_mrw";
210 //map[Solid::OpticalDrive::Mrw] ="optical_mrw_w";
211
212 Q_FOREACH ( const Solid::OpticalDrive::MediumType & type, map.keys() )
213 {
214 if ( mediaTypes.contains( map[type] ) )
215 {
216 supported |= type;
217 }
218 }
219
220 return supported;
221 }
222
slotChanged()223 void OpticalDrive::slotChanged()
224 {
225 m_speedsInit = false; // reset the read/write speeds, changes eg. with an inserted media
226 }
227