Support new ID_DRIVE_THUMB udev property and 'thumb' media type
authorDavid Zeuthen <davidz@redhat.com>
Fri, 9 Dec 2011 19:22:07 +0000 (14:22 -0500)
committerDavid Zeuthen <davidz@redhat.com>
Fri, 9 Dec 2011 19:22:07 +0000 (14:22 -0500)
This will also set Drive:Removable to FALSE to override what the
hardware (wrongly) reports. So also add new Drive:Ejectable property
since we still want to display an Eject icon for thumb drives.

Use the icon 'media-removable' for drives of this type.

http://people.freedesktop.org/~david/gdu2-ID_DRIVE_THUMB-support.png

Signed-off-by: David Zeuthen <davidz@redhat.com>
data/80-udisks2.rules
data/org.freedesktop.UDisks2.xml
doc/man/udisks.xml
src/udiskslinuxdrive.c
udisks/udisksclient.c

index 14accc9..a2b4743 100644 (file)
@@ -26,3 +26,37 @@ KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ENV{DEVTYPE}=="disk", ENV{ID_DRIV
 
 # TODO: maybe automatically convert udisks1 properties to udisks2 ones?
 # (e.g. UDISKS_PRESENTATION_HIDE -> UDISKS_IGNORE)
+
+# ------------------------------------------------------------------------
+# ------------------------------------------------------------------------
+# ------------------------------------------------------------------------
+# Whitelist for tagging drives with the property media type.
+# TODO: figure out where to store this database
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0248", ENV{ID_INSTANCE}=="0:0", ENV{ID_DRIVE_FLASH_CF}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0248", ENV{ID_INSTANCE}=="0:1", ENV{ID_DRIVE_FLASH_MS}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0248", ENV{ID_INSTANCE}=="0:2", ENV{ID_DRIVE_FLASH_SM}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0248", ENV{ID_INSTANCE}=="0:3", ENV{ID_DRIVE_FLASH_SD}="1"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="05e3", ATTRS{idProduct}=="070e", ENV{ID_INSTANCE}=="0:0", ENV{ID_DRIVE_FLASH_CF}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="05e3", ATTRS{idProduct}=="070e", ENV{ID_INSTANCE}=="0:1", ENV{ID_DRIVE_FLASH_SM}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="05e3", ATTRS{idProduct}=="070e", ENV{ID_INSTANCE}=="0:2", ENV{ID_DRIVE_FLASH_SD}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="05e3", ATTRS{idProduct}=="070e", ENV{ID_INSTANCE}=="0:3", ENV{ID_DRIVE_FLASH_MS}="1"
+
+# APPLE SD Card Reader (MacbookPro5,4)
+#
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="05ac", ATTRS{idProduct}=="8403", ENV{ID_DRIVE_FLASH_SD}="1"
+
+# Realtek card readers
+DRIVERS=="rts_pstor", ENV{ID_DRIVE_FLASH_SD}="1"
+
+# Common theme
+#
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="*Reader*SD*", ENV{ID_DRIVE_FLASH_SD}="1"
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="*CF_Reader*", ENV{ID_DRIVE_FLASH_CF}="1"
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="*SM_Reader*", ENV{ID_DRIVE_FLASH_SM}="1"
+SUBSYSTEMS=="usb", ENV{ID_MODEL}=="*MS_Reader*", ENV{ID_DRIVE_FLASH_MS}="1"
+
+# USB sticks
+#
+SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="*Kingston*", ENV{ID_MODEL}=="*DataTraveler*", ENV{ID_DRIVE_THUMB}="1"
index b4ed330..e88af62 100644 (file)
     <property name="Media" type="s" access="read"/>
 
     <!-- MediaCompatibility:
-      The physical kind of media the drive uses or blank if unknown.
+      The physical kind of media the drive uses or the type of the drive or blank if unknown.
       Known values include
       <variablelist>
+      <varlistentry><term>thumb</term><listitem><para>The device is a thumb-drive with non-removable media (e.g. a USB stick)</para></listitem></varlistentry>
       <varlistentry><term>flash</term><listitem><para>Flash Card</para></listitem></varlistentry>
       <varlistentry><term>flash_cf</term><listitem><para>CompactFlash</para></listitem></varlistentry>
       <varlistentry><term>flash_ms</term><listitem><para>MemoryStick</para></listitem></varlistentry>
     -->
     <property name="MediaCompatibility" type="as" access="read"/>
 
-    <!-- MediaRemovable: Whether the media can be removed from the drive. -->
+    <!-- MediaRemovable:
+         Whether the media can be removed from the drive.
+
+         Note that this may be overridden from what the hardware
+         reports - for example, USB thumb drives often report that
+         they are using removable media while in fact the media
+         is not removable.
+    -->
     <property name="MediaRemovable" type="b" access="read"/>
 
     <!-- MediaAvailable: Set to %FALSE if no medium is available.
     -->
     <property name="Removable" type="b" access="read"/>
 
+    <!-- Ejectable:
+         Whether the media can be ejected from the drive or the drive
+         accepts an eject command to switch its state so it displays
+         e.g. a "Safe To Remove" message to the user.
+
+         Note that this is only a <emphasis>guess</emphasis>.
+    -->
+    <property name="Ejectable" type="b" access="read"/>
+
     <!-- SortKey:
          A string that can be used for sorting drive objects.
     -->
index b349b7e..2988178 100644 (file)
     </para>
     <variablelist>
       <varlistentry>
+        <term><option>ID_DRIVE_THUMB</option></term>
+        <listitem><para>The device is a thumb-drive with non-removable media (e.g. a USB stick).
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
         <term><option>ID_DRIVE_FLASH</option></term>
         <listitem><para>The device is compatible with flash.
         </para></listitem>
index d628149..2ed5edd 100644 (file)
@@ -109,40 +109,42 @@ static const struct
 {
   const gchar *udev_property;
   const gchar *media_name;
+  gboolean force_non_removable;
 } drive_media_mapping[] =
 {
-  { "ID_DRIVE_FLASH", "flash" },
-  { "ID_DRIVE_FLASH_CF", "flash_cf" },
-  { "ID_DRIVE_FLASH_MS", "flash_ms" },
-  { "ID_DRIVE_FLASH_SM", "flash_sm" },
-  { "ID_DRIVE_FLASH_SD", "flash_sd" },
-  { "ID_DRIVE_FLASH_SDHC", "flash_sdhc" },
-  { "ID_DRIVE_FLASH_SDXC", "flash_sdxc" },
-  { "ID_DRIVE_FLASH_MMC", "flash_mmc" },
-  { "ID_DRIVE_FLOPPY", "floppy" },
-  { "ID_DRIVE_FLOPPY_ZIP", "floppy_zip" },
-  { "ID_DRIVE_FLOPPY_JAZ", "floppy_jaz" },
-  { "ID_CDROM", "optical_cd" },
-  { "ID_CDROM_CD_R", "optical_cd_r" },
-  { "ID_CDROM_CD_RW", "optical_cd_rw" },
-  { "ID_CDROM_DVD", "optical_dvd" },
-  { "ID_CDROM_DVD_R", "optical_dvd_r" },
-  { "ID_CDROM_DVD_RW", "optical_dvd_rw" },
-  { "ID_CDROM_DVD_RAM", "optical_dvd_ram" },
-  { "ID_CDROM_DVD_PLUS_R", "optical_dvd_plus_r" },
-  { "ID_CDROM_DVD_PLUS_RW", "optical_dvd_plus_rw" },
-  { "ID_CDROM_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
-  { "ID_CDROM_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
-  { "ID_CDROM_BD", "optical_bd" },
-  { "ID_CDROM_BD_R", "optical_bd_r" },
-  { "ID_CDROM_BD_RE", "optical_bd_re" },
-  { "ID_CDROM_HDDVD", "optical_hddvd" },
-  { "ID_CDROM_HDDVD_R", "optical_hddvd_r" },
-  { "ID_CDROM_HDDVD_RW", "optical_hddvd_rw" },
-  { "ID_CDROM_MO", "optical_mo" },
-  { "ID_CDROM_MRW", "optical_mrw" },
-  { "ID_CDROM_MRW_W", "optical_mrw_w" },
-  { NULL, NULL }
+  { "ID_DRIVE_THUMB", "thumb", TRUE },
+  { "ID_DRIVE_FLASH", "flash", FALSE },
+  { "ID_DRIVE_FLASH_CF", "flash_cf", FALSE },
+  { "ID_DRIVE_FLASH_MS", "flash_ms", FALSE },
+  { "ID_DRIVE_FLASH_SM", "flash_sm", FALSE },
+  { "ID_DRIVE_FLASH_SD", "flash_sd", FALSE },
+  { "ID_DRIVE_FLASH_SDHC", "flash_sdhc", FALSE },
+  { "ID_DRIVE_FLASH_SDXC", "flash_sdxc", FALSE },
+  { "ID_DRIVE_FLASH_MMC", "flash_mmc", FALSE },
+  { "ID_DRIVE_FLOPPY", "floppy", FALSE },
+  { "ID_DRIVE_FLOPPY_ZIP", "floppy_zip", FALSE },
+  { "ID_DRIVE_FLOPPY_JAZ", "floppy_jaz", FALSE },
+  { "ID_CDROM", "optical_cd", FALSE },
+  { "ID_CDROM_CD_R", "optical_cd_r", FALSE },
+  { "ID_CDROM_CD_RW", "optical_cd_rw", FALSE },
+  { "ID_CDROM_DVD", "optical_dvd", FALSE },
+  { "ID_CDROM_DVD_R", "optical_dvd_r", FALSE },
+  { "ID_CDROM_DVD_RW", "optical_dvd_rw", FALSE },
+  { "ID_CDROM_DVD_RAM", "optical_dvd_ram", FALSE },
+  { "ID_CDROM_DVD_PLUS_R", "optical_dvd_plus_r", FALSE },
+  { "ID_CDROM_DVD_PLUS_RW", "optical_dvd_plus_rw", FALSE },
+  { "ID_CDROM_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl", FALSE },
+  { "ID_CDROM_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl", FALSE },
+  { "ID_CDROM_BD", "optical_bd", FALSE },
+  { "ID_CDROM_BD_R", "optical_bd_r", FALSE },
+  { "ID_CDROM_BD_RE", "optical_bd_re", FALSE },
+  { "ID_CDROM_HDDVD", "optical_hddvd", FALSE },
+  { "ID_CDROM_HDDVD_R", "optical_hddvd_r", FALSE },
+  { "ID_CDROM_HDDVD_RW", "optical_hddvd_rw", FALSE },
+  { "ID_CDROM_MO", "optical_mo", FALSE },
+  { "ID_CDROM_MRW", "optical_mrw", FALSE },
+  { "ID_CDROM_MRW_W", "optical_mrw_w", FALSE },
+  { NULL, NULL, FALSE }
 };
 
 static const struct
@@ -205,35 +207,47 @@ set_media (UDisksDrive      *iface,
   guint disc_track_count = 0;
   guint disc_track_count_audio = 0;
   guint disc_track_count_data = 0;
+  gboolean force_non_removable = FALSE;
+  gboolean kernel_removable;
+  gboolean removable;
 
   media_compat_array = g_ptr_array_new ();
   for (n = 0; drive_media_mapping[n].udev_property != NULL; n++)
     {
-      if (!g_udev_device_has_property (device, drive_media_mapping[n].udev_property))
-        continue;
-      g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
+      if (g_udev_device_get_property_as_boolean (device, drive_media_mapping[n].udev_property))
+        {
+          udisks_debug ("adding num %d: %s", n, drive_media_mapping[n].media_name);
+          g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
+          if (drive_media_mapping[n].force_non_removable)
+            force_non_removable = TRUE;
+        }
     }
   g_ptr_array_sort (media_compat_array, (GCompareFunc) ptr_str_array_compare);
   g_ptr_array_add (media_compat_array, NULL);
 
-  media_in_drive = "";
+  removable = kernel_removable = g_udev_device_get_sysfs_attr_as_boolean (device, "removable");
+  if (force_non_removable)
+    removable = FALSE;
+  udisks_drive_set_media_removable (iface, removable);
+  udisks_drive_set_ejectable (iface, kernel_removable);
+
+  media_in_drive = NULL;
   if (udisks_drive_get_media_available (iface))
     {
       for (n = 0; media_mapping[n].udev_property != NULL; n++)
         {
-          if (!g_udev_device_has_property (device, media_mapping[n].udev_property))
-            continue;
-
-          media_in_drive = drive_media_mapping[n].media_name;
-          break;
+          if (g_udev_device_get_property_as_boolean (device, media_mapping[n].udev_property))
+            {
+              media_in_drive = media_mapping[n].media_name;
+              break;
+            }
         }
       /* If the media isn't set (from e.g. udev rules), just pick the first one in media_compat - note
        * that this may be NULL (if we don't know what media is compatible with the drive) which is OK.
        */
-      if (strlen (media_in_drive) == 0)
+      if (media_in_drive == NULL)
         media_in_drive = ((const gchar **) media_compat_array->pdata)[0];
     }
-
   udisks_drive_set_media_compatibility (iface, (const gchar* const *) media_compat_array->pdata);
   udisks_drive_set_media (iface, media_in_drive);
   g_ptr_array_free (media_compat_array, TRUE);
@@ -479,7 +493,6 @@ udisks_linux_drive_update (UDisksLinuxDrive       *drive,
     }
 
   /* common bits go here */
-  udisks_drive_set_media_removable (iface, g_udev_device_get_sysfs_attr_as_boolean (device, "removable"));
   size = udisks_daemon_util_block_get_size (device,
                                             &media_available,
                                             &media_change_detected);
index 9ec88eb..63138db 100644 (file)
@@ -716,6 +716,7 @@ udisks_client_get_drive_for_block (UDisksClient  *client,
 typedef enum
 {
   DRIVE_TYPE_UNSET,
+  DRIVE_TYPE_DRIVE,
   DRIVE_TYPE_DISK,
   DRIVE_TYPE_CARD,
   DRIVE_TYPE_DISC
@@ -731,6 +732,8 @@ static const struct
   const gchar *drive_icon;
 } media_data[] =
 {
+  {"thumb",      N_("Thumb"),        N_("Thumb"),        "media-removable",   DRIVE_TYPE_DRIVE, "media-removable"},
+
   {"floppy",     N_("Floppy"),       N_("Floppy"), "media-floppy",      DRIVE_TYPE_DISK, "drive-removable-media-floppy"},
   {"floppy_zip", N_("Zip"),          N_("Zip"),    "media-floppy-jaz",  DRIVE_TYPE_DISK, "drive-removable-media-floppy-jaz"},
   {"floppy_jaz", N_("Jaz"),          N_("Jaz"),    "media-floppy-zip",  DRIVE_TYPE_DISK, "drive-removable-media-floppy-zip"},
@@ -806,8 +809,9 @@ strv_has (const gchar * const *haystack,
  * If there is no media in @drive, then @out_media_icon is set to the
  * same value as @out_drive_icon.
  *
- * If the @drive doesn't support removable media, then %NULL is always
- * returned for @out_media_description and @out_media_icon.
+ * If the @drive doesn't support removable media or if no media is
+ * available, then %NULL is always returned for @out_media_description
+ * and @out_media_icon.
  *
  * If the <link linkend="gdbus-property-org-freedesktop-UDisks2-Block.HintName">HintName</link>
  * and/or
@@ -831,6 +835,14 @@ strv_has (const gchar * const *haystack,
  *     </thead>
  *     <tbody>
  *       <row>
+ *         <entry>USB Thumb Drive</entry>
+ *         <entry>Kingston DataTraveler 2.0</entry>
+ *         <entry>4.0 GB Thumb Drive</entry>
+ *         <entry>media-removable</entry>
+ *         <entry>NULL</entry>
+ *         <entry>NULL</entry>
+ *       </row>
+ *       <row>
  *         <entry>Internal System Disk (Hard Disk)</entry>
  *         <entry>ST3320620AS</entry>
  *         <entry>320 GB Hard Disk</entry>
@@ -940,7 +952,8 @@ udisks_client_get_drive_info (UDisksClient  *client,
   const gchar *model;
   const gchar *media;
   const gchar *const *media_compat;
-  gboolean removable;
+  gboolean media_available;
+  gboolean media_removable;
   gboolean rotation_rate;
   guint64 size;
   gchar *size_str;
@@ -963,7 +976,8 @@ udisks_client_get_drive_info (UDisksClient  *client,
   vendor = udisks_drive_get_vendor (drive);
   model = udisks_drive_get_model (drive);
   size = udisks_drive_get_size (drive);
-  removable = udisks_drive_get_media_removable (drive);
+  media_removable = udisks_drive_get_media_removable (drive);
+  media_available = udisks_drive_get_media_available (drive);
   rotation_rate = udisks_drive_get_rotation_rate (drive);
   if (size > 0)
     size_str = udisks_client_get_size_for_display (client, size, FALSE, FALSE);
@@ -1003,36 +1017,42 @@ udisks_client_get_drive_info (UDisksClient  *client,
           desc_type = media_data[n].media_type;
         }
 
-      /* media */
-      if (g_strcmp0 (media, media_data[n].id) == 0)
+      if (media_removable && media_available)
         {
-          if (media_description == NULL)
+          /* media */
+          if (g_strcmp0 (media, media_data[n].id) == 0)
             {
-              switch (media_data[n].media_type)
+              if (media_description == NULL)
                 {
-                case DRIVE_TYPE_UNSET:
-                  g_assert_not_reached ();
-                  break;
-                case DRIVE_TYPE_DISK:
-                  media_description = g_strdup_printf (_("%s Disk"), _(media_data[n].media_name));
-                  break;
-                case DRIVE_TYPE_CARD:
-                  media_description = g_strdup_printf (_("%s Card"), _(media_data[n].media_name));
-                  break;
-                case DRIVE_TYPE_DISC:
-                  media_description = g_strdup_printf (_("%s Disc"), _(media_data[n].media_name));
-                  break;
+                  switch (media_data[n].media_type)
+                    {
+                    case DRIVE_TYPE_UNSET:
+                      g_assert_not_reached ();
+                      break;
+                    case DRIVE_TYPE_DRIVE:
+                      media_description = g_strdup_printf (_("%s Drive"), _(media_data[n].media_name));
+                      break;
+                    case DRIVE_TYPE_DISK:
+                      media_description = g_strdup_printf (_("%s Disk"), _(media_data[n].media_name));
+                      break;
+                    case DRIVE_TYPE_CARD:
+                      media_description = g_strdup_printf (_("%s Card"), _(media_data[n].media_name));
+                      break;
+                    case DRIVE_TYPE_DISC:
+                      media_description = g_strdup_printf (_("%s Disc"), _(media_data[n].media_name));
+                      break;
+                    }
                 }
+              if (media_icon == NULL)
+                media_icon = g_themed_icon_new_with_default_fallbacks (media_data[n].media_icon);
             }
-          if (media_icon == NULL)
-            media_icon = g_themed_icon_new_with_default_fallbacks (media_data[n].media_icon);
         }
     }
 
   switch (desc_type)
     {
     case DRIVE_TYPE_UNSET:
-      if (removable)
+      if (media_removable)
         {
           if (size_str != NULL)
             {
@@ -1074,32 +1094,37 @@ udisks_client_get_drive_info (UDisksClient  *client,
       description = g_strdup_printf (_("%s Card Reader"), desc_str->str);
       break;
 
-    case DRIVE_TYPE_DISK:
-      /* explicit fall-through */
+    case DRIVE_TYPE_DRIVE: /* explicit fall-through */
+    case DRIVE_TYPE_DISK: /* explicit fall-through */
     case DRIVE_TYPE_DISC:
-      description = g_strdup_printf (_("%s Drive"), desc_str->str);
+      if (!media_removable && size_str != NULL)
+        description = g_strdup_printf (_("%s %s Drive"), size_str, desc_str->str);
+      else
+        description = g_strdup_printf (_("%s Drive"), desc_str->str);
       break;
     }
   g_string_free (desc_str, TRUE);
 
-  if (media_icon == NULL)
+  /* fallback for icon */
+  if (icon == NULL)
     {
       gchar *s;
-      if (removable)
+      if (media_removable)
         s = g_strdup_printf ("drive-removable-media%s", hyphenated_connection_bus);
       else
         s = g_strdup_printf ("drive-harddisk%s", hyphenated_connection_bus);
-      media_icon = g_themed_icon_new_with_default_fallbacks (s);
+      icon = g_themed_icon_new_with_default_fallbacks (s);
       g_free (s);
     }
-  if (icon == NULL)
+  /* fallback for media_icon */
+  if (media_removable && media_available && media_icon == NULL)
     {
       gchar *s;
-      if (removable)
+      if (media_removable)
         s = g_strdup_printf ("drive-removable-media%s", hyphenated_connection_bus);
       else
         s = g_strdup_printf ("drive-harddisk%s", hyphenated_connection_bus);
-      icon = g_themed_icon_new_with_default_fallbacks (s);
+      media_icon = g_themed_icon_new_with_default_fallbacks (s);
       g_free (s);
     }
 
@@ -1156,6 +1181,17 @@ udisks_client_get_drive_info (UDisksClient  *client,
         }
     }
 
+#if 0
+  /* for debugging */
+  g_print ("mr=%d,ma=%d dd=%s, md=%s and di='%s', mi='%s'\n",
+           media_removable,
+           media_available,
+           description,
+           media_description,
+           icon == NULL ? "" : g_icon_to_string (icon),
+           media_icon == NULL ? "" : g_icon_to_string (media_icon));
+#endif
+
   /* return values to caller */
   if (out_name != NULL)
     *out_name = name;