static RBSource * create_source_device_cb (RBRemovableMediaManager *rmm, GObject *device_obj, RBMtpPlugin *plugin) { GUdevDevice *device = G_UDEV_DEVICE (device_obj); LIBMTP_device_entry_t *device_list; int numdevs; int vendor; int model; int busnum; int devnum; int i; /* check subsystem == usb? */ if (g_strcmp0 (g_udev_device_get_subsystem (device), "usb") != 0) { rb_debug ("device %s is not a USB device", g_udev_device_get_name (device)); return NULL; } /* check that it's not an iPhone or iPod Touch */ if (g_udev_device_get_property_as_boolean (device, "USBMUX_SUPPORTED")) { rb_debug ("device %s is supported through AFC, ignore", g_udev_device_get_name (device)); return NULL; } /* get device info */ vendor = get_property_as_int (device, "ID_VENDOR_ID", 16); model = get_property_as_int (device, "ID_MODEL_ID", 16); busnum = get_property_as_int (device, "BUSNUM", 10); devnum = get_property_as_int (device, "DEVNUM", 10); if (vendor == 0 || model == 0) { rb_debug ("couldn't get vendor or model ID for device (%x:%x)", vendor, model); return NULL; } rb_debug ("matching device %x:%x against libmtp device list", vendor, model); LIBMTP_Get_Supported_Devices_List(&device_list, &numdevs); for (i = 0; i < numdevs; i++) { if (device_list[i].vendor_id == vendor && device_list[i].product_id == model) { LIBMTP_raw_device_t rawdevice; RBSource *source; RBShell *shell; rb_debug ("found libmtp device list entry (model: %s, vendor: %s)", device_list[i].vendor, device_list[i].product); rawdevice.device_entry = device_list[i]; rawdevice.bus_location = busnum; rawdevice.devnum = devnum; g_object_get (plugin, "object", &shell, NULL); source = rb_mtp_source_new (shell, G_OBJECT (plugin), device, &rawdevice); plugin->mtp_sources = g_list_prepend (plugin->mtp_sources, source); g_signal_connect_object (G_OBJECT (source), "deleted", G_CALLBACK (source_deleted_cb), plugin, 0); g_object_unref (shell); return source; } } rb_debug ("device didn't match anything"); return NULL; }
int main (int argc, char **argv) { LIBMTP_device_entry_t *entries; int numentries; int i; int ret; enum style style = style_usbmap; int opt; extern int optind; extern char *optarg; char *udev_action = NULL; /* * You could tag on MODE="0666" here to enfore writeable * device nodes, use the command line argument for that. * Current udev default rules will make any device tagged * with ENV{ID_MEDIA_PLAYER}=1 writable for the console * user. */ char default_udev_action[] = "SYMLINK+=\"libmtp-%k\", ENV{ID_MTP_DEVICE}=\"1\", ENV{ID_MEDIA_PLAYER}=\"1\""; char *action; // To hold the action actually used. uint16_t last_vendor = 0x0000U; char mtp_probe_dir[256]; char *udev_group= NULL; char *udev_mode = NULL; while ( (opt = getopt(argc, argv, "uoiHa:p:g:m:")) != -1 ) { switch (opt) { case 'a': udev_action = strdup(optarg); break; case 'u': style = style_udev; break; case 'o': style = style_udev_old; break; case 'H': style = style_hal; break; case 'i': style = style_usbids; break; case 'p': strncpy(mtp_probe_dir,optarg,sizeof(mtp_probe_dir)); mtp_probe_dir[sizeof(mtp_probe_dir)-1] = '\0'; if (strlen(mtp_probe_dir) <= 1) { printf("Supply some sane mtp-probe dir\n"); exit(1); } /* Make sure the dir ends with '/' */ if (mtp_probe_dir[strlen(mtp_probe_dir)-1] != '/') { int index = strlen(mtp_probe_dir); if (index >= (sizeof(mtp_probe_dir)-1)) { exit(1); } mtp_probe_dir[index] = '/'; mtp_probe_dir[index+1] = '\0'; } /* Don't add the standard udev path... */ if (!strcmp(mtp_probe_dir, "/lib/udev/")) { mtp_probe_dir[0] = '\0'; } break; case 'g': udev_group = strdup(optarg); break; case 'm': udev_mode = strdup(optarg); break; default: usage(); } } if (udev_action != NULL) { action = udev_action; } else { action = default_udev_action; } LIBMTP_Init(); ret = LIBMTP_Get_Supported_Devices_List(&entries, &numentries); if (ret == 0) { switch (style) { case style_udev: printf("# UDEV-style hotplug map for libmtp\n"); printf("# Put this file in /etc/udev/rules.d\n\n"); printf("ACTION!=\"add\", GOTO=\"libmtp_rules_end\"\n"); printf("ENV{MAJOR}!=\"?*\", GOTO=\"libmtp_rules_end\"\n"); printf("SUBSYSTEM==\"usb\", GOTO=\"libmtp_usb_rules\"\n" "GOTO=\"libmtp_rules_end\"\n\n" "LABEL=\"libmtp_usb_rules\"\n\n"); printf("# Some sensitive devices we surely don\'t wanna probe, color instruments\n"); printf("ATTR{idVendor}==\"0670\", GOTO=\"libmtp_rules_end\"\n"); printf("ATTR{idVendor}==\"0765\", GOTO=\"libmtp_rules_end\"\n"); printf("ATTR{idVendor}==\"085c\", GOTO=\"libmtp_rules_end\"\n"); printf("ATTR{idVendor}==\"0971\", GOTO=\"libmtp_rules_end\"\n"); printf("\n"); break; case style_udev_old: printf("# UDEV-style hotplug map for libmtp\n"); printf("# Put this file in /etc/udev/rules.d\n\n"); printf("ACTION!=\"add\", GOTO=\"libmtp_rules_end\"\n"); printf("ENV{MAJOR}!=\"?*\", GOTO=\"libmtp_rules_end\"\n"); printf("SUBSYSTEM==\"usb_device\", GOTO=\"libmtp_usb_device_rules\"\n" "GOTO=\"libmtp_rules_end\"\n\n" "LABEL=\"libmtp_usb_device_rules\"\n\n"); break; case style_usbmap: printf("# This usermap will call the script \"libmtp.sh\" whenever a known MTP device is attached.\n\n"); break; case style_hal: printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <!-- -*- SGML -*- -->\n"); printf("<!-- This file was generated by %s - - fdi -->\n", argv[0]); printf("<deviceinfo version=\"0.2\">\n"); printf(" <device>\n"); printf(" <match key=\"info.subsystem\" string=\"usb\">\n"); break; case style_usbids: printf("# usb.ids style device list from libmtp\n"); printf("# Compare: http://www.linux-usb.org/usb.ids\n"); break; } for (i = 0; i < numentries; i++) { LIBMTP_device_entry_t * entry = &entries[i]; switch (style) { case style_udev: case style_udev_old: printf("# %s %s\n", entry->vendor, entry->product); printf("ATTR{idVendor}==\"%04x\", ATTR{idProduct}==\"%04x\", %s", entry->vendor_id, entry->product_id, action); if (udev_group != NULL) printf(", GROUP=\"%s\"", udev_group); if (udev_mode != NULL) printf(", MODE=\"%s\"", udev_mode); printf("\n"); break; case style_usbmap: printf("# %s %s\n", entry->vendor, entry->product); printf("libmtp.sh 0x0003 0x%04x 0x%04x 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000\n", entry->vendor_id, entry->product_id); break; case style_hal: printf(" <!-- %s %s -->\n", entry->vendor, entry->product); printf(" <match key=\"usb.vendor_id\" int=\"0x%04x\">\n", entry->vendor_id); printf(" <match key=\"usb.product_id\" int=\"0x%04x\">\n", entry->product_id); /* FIXME: If hal >=0.5.10 can be depended upon, the matches below with contains_not can instead use addset */ printf(" <match key=\"info.capabilities\" contains_not=\"portable_audio_player\">\n"); printf(" <append key=\"info.capabilities\" type=\"strlist\">portable_audio_player</append>\n"); printf(" </match>\n"); printf(" <merge key=\"info.vendor\" type=\"string\">%s</merge>\n", entry->vendor); printf(" <merge key=\"info.product\" type=\"string\">%s</merge>\n", entry->product); printf(" <merge key=\"info.category\" type=\"string\">portable_audio_player</merge>\n"); printf(" <merge key=\"portable_audio_player.access_method\" type=\"string\">user</merge>\n"); printf(" <match key=\"portable_audio_player.access_method.protocols\" contains_not=\"mtp\">\n"); printf(" <append key=\"portable_audio_player.access_method.protocols\" type=\"strlist\">mtp</append>\n"); printf(" </match>\n"); printf(" <append key=\"portable_audio_player.access_method.drivers\" type=\"strlist\">libmtp</append>\n"); /* FIXME: needs true list of formats ... But all of them can do MP3 and WMA */ printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/mpeg\">\n"); printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/mpeg</append>\n"); printf(" </match>\n"); printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/x-ms-wma\">\n"); printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/x-ms-wma</append>\n"); printf(" </match>\n"); /* Special hack to support the OGG format - irivers, TrekStor and NormSoft (Palm) can always play these files! */ if (entry->vendor_id == 0x4102 || // iriver entry->vendor_id == 0x066f || // TrekStor entry->vendor_id == 0x1703) { // NormSoft, Inc. printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"application/ogg\">\n"); printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">application/ogg</append>\n"); printf(" </match>\n"); } printf(" <merge key=\"portable_audio_player.libmtp.protocol\" type=\"string\">mtp</merge>\n"); printf(" </match>\n"); printf(" </match>\n"); break; case style_usbids: if (last_vendor != entry->vendor_id) { printf("%04x\n", entry->vendor_id); } printf("\t%04x %s %s\n", entry->product_id, entry->vendor, entry->product); break; } last_vendor = entry->vendor_id; } } else { printf("Error.\n"); exit(1); } // Then the footer. switch (style) { case style_usbmap: break; case style_udev: case style_udev_old: /* * This is code that invokes the mtp-probe program on * every USB device that is either PTP or vendor specific */ printf("\n# Autoprobe vendor-specific, communication and PTP devices\n"); printf("ENV{ID_MTP_DEVICE}!=\"1\", ENV{MTP_NO_PROBE}!=\"1\", ENV{COLOR_MEASUREMENT_DEVICE}!=\"1\", ENV{libsane_matched}!=\"yes\", ATTR{bDeviceClass}==\"00|02|06|ef|ff\", PROGRAM=\"%smtp-probe /sys$env{DEVPATH} $attr{busnum} $attr{devnum}\", RESULT==\"1\", %s", mtp_probe_dir, action); if (udev_group != NULL) printf(", GROUP=\"%s\"", udev_group); if (udev_mode != NULL) printf(", MODE=\"%s\"", udev_mode); printf("\n"); printf("\nLABEL=\"libmtp_rules_end\"\n"); break; case style_hal: printf(" </match>\n"); printf(" </device>\n"); printf("</deviceinfo>\n"); break; case style_usbids: printf("\n"); } exit (0); }