1 /** 2 * \file hotplug.c 3 * Example program to create hotplug scripts. 4 * 5 * Copyright (C) 2005-2007 Linus Walleij <triad (at) df.lth.se> 6 * Copyright (C) 2006-2008 Marcus Meissner <marcus (at) jet.franken.de> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 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, write to the 20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 21 * Boston, MA 02111-1307, USA. 22 */ 23 #include "common.h" 24 #include <unistd.h> 25 #include <stdlib.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 static void usage(void) 30 { 31 fprintf(stderr, "usage: hotplug [-u -H -i -a\"ACTION\"]\n"); 32 fprintf(stderr, " -u: use udev syntax\n"); 33 fprintf(stderr, " -H: use hal syntax\n"); 34 fprintf(stderr, " -i: use usb.ids simple list syntax\n"); 35 fprintf(stderr, " -a\"ACTION\": perform udev action ACTION on attachment\n"); 36 exit(1); 37 } 38 39 enum style { 40 style_usbmap, 41 style_udev, 42 style_hal, 43 style_usbids 44 }; 45 46 int main (int argc, char **argv) 47 { 48 LIBMTP_device_entry_t *entries; 49 int numentries; 50 int i; 51 int ret; 52 enum style style = style_usbmap; 53 int opt; 54 extern int optind; 55 extern char *optarg; 56 char *udev_action = NULL; 57 char default_udev_action[] = "SYMLINK+=\"libmtp-%k\", MODE=\"666\""; 58 char *action; // To hold the action actually used. 59 uint16_t last_vendor = 0x0000U; 60 61 while ( (opt = getopt(argc, argv, "uUiHa:")) != -1 ) { 62 switch (opt) { 63 case 'a': 64 udev_action = strdup(optarg); 65 case 'u': 66 style = style_udev; 67 break; 68 case 'H': 69 style = style_hal; 70 break; 71 case 'i': 72 style = style_usbids; 73 break; 74 default: 75 usage(); 76 } 77 } 78 79 if (udev_action != NULL) { 80 action = udev_action; 81 } else { 82 action = default_udev_action; 83 } 84 85 LIBMTP_Init(); 86 ret = LIBMTP_Get_Supported_Devices_List(&entries, &numentries); 87 if (ret == 0) { 88 switch (style) { 89 case style_udev: 90 printf("# UDEV-style hotplug map for libmtp\n"); 91 printf("# Put this file in /etc/udev/rules.d\n\n"); 92 printf("ACTION!=\"add\", GOTO=\"libmtp_rules_end\"\n"); 93 printf("ENV{MAJOR}!=\"?*\", GOTO=\"libmtp_rules_end\"\n"); 94 printf("SUBSYSTEM==\"usb\", GOTO=\"libmtp_usb_rules\"\n" 95 "# The following thing will be deprecated when older kernels are phased out.\n" 96 "SUBSYSTEM==\"usb_device\", GOTO=\"libmtp_usb_device_rules\"\n" 97 "GOTO=\"libmtp_rules_end\"\n\n" 98 "LABEL=\"libmtp_usb_rules\"\n\n"); 99 break; 100 case style_usbmap: 101 printf("# This usermap will call the script \"libmtp.sh\" whenever a known MTP device is attached.\n\n"); 102 break; 103 case style_hal: 104 printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <!-- -*- SGML -*- -->\n"); 105 printf("<!-- This file was generated by %s - - fdi -->\n", argv[0]); 106 printf("<deviceinfo version=\"0.2\">\n"); 107 printf(" <device>\n"); 108 printf(" <match key=\"info.subsystem\" string=\"usb\">\n"); 109 break; 110 case style_usbids: 111 printf("# usb.ids style device list from libmtp\n"); 112 printf("# Compare: http://www.linux-usb.org/usb.ids\n"); 113 break; 114 } 115 116 for (i = 0; i < numentries; i++) { 117 LIBMTP_device_entry_t * entry = &entries[i]; 118 119 switch (style) { 120 case style_udev: 121 { 122 printf("# %s %s\n", entry->vendor, entry->product); 123 // Old style directly SYSFS named. 124 // printf("SYSFS{idVendor}==\"%04x\", SYSFS{idProduct}==\"%04x\", %s\n", entry->vendor_id, entry->product_id, action); 125 // Newer style 126 printf("ATTR{idVendor}==\"%04x\", ATTR{idProduct}==\"%04x\", %s\n", entry->vendor_id, entry->product_id, action); 127 break; 128 } 129 case style_usbmap: 130 printf("# %s %s\n", entry->vendor, entry->product); 131 printf("libmtp.sh 0x0003 0x%04x 0x%04x 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000\n", entry->vendor_id, entry->product_id); 132 break; 133 case style_hal: 134 printf(" <!-- %s %s -->\n", entry->vendor, entry->product); 135 printf(" <match key=\"usb.vendor_id\" int=\"0x%04x\">\n", entry->vendor_id); 136 printf(" <match key=\"usb.product_id\" int=\"0x%04x\">\n", entry->product_id); 137 /* FIXME: If hal >=0.5.10 can be depended upon, the matches below with contains_not can instead use addset */ 138 printf(" <match key=\"info.capabilities\" contains_not=\"portable_audio_player\">\n"); 139 printf(" <append key=\"info.capabilities\" type=\"strlist\">portable_audio_player</append>\n"); 140 printf(" </match>\n"); 141 printf(" <merge key=\"info.vendor\" type=\"string\">%s</merge>\n", entry->vendor); 142 printf(" <merge key=\"info.product\" type=\"string\">%s</merge>\n", entry->product); 143 printf(" <merge key=\"info.category\" type=\"string\">portable_audio_player</merge>\n"); 144 printf(" <merge key=\"portable_audio_player.access_method\" type=\"string\">user</merge>\n"); 145 printf(" <match key=\"portable_audio_player.access_method.protocols\" contains_not=\"mtp\">\n"); 146 printf(" <append key=\"portable_audio_player.access_method.protocols\" type=\"strlist\">mtp</append>\n"); 147 printf(" </match>\n"); 148 printf(" <append key=\"portable_audio_player.access_method.drivers\" type=\"strlist\">libmtp</append>\n"); 149 /* FIXME: needs true list of formats ... But all of them can do MP3 and WMA */ 150 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/mpeg\">\n"); 151 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/mpeg</append>\n"); 152 printf(" </match>\n"); 153 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/x-ms-wma\">\n"); 154 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/x-ms-wma</append>\n"); 155 printf(" </match>\n"); 156 /* Special hack to support the OGG format - irivers, TrekStor and NormSoft (Palm) can always play these files! */ 157 if (entry->vendor_id == 0x4102 || // iriver 158 entry->vendor_id == 0x066f || // TrekStor 159 entry->vendor_id == 0x1703) { // NormSoft, Inc. 160 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"application/ogg\">\n"); 161 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">application/ogg</append>\n"); 162 printf(" </match>\n"); 163 } 164 printf(" <merge key=\"portable_audio_player.libmtp.protocol\" type=\"string\">mtp</merge>\n"); 165 printf(" </match>\n"); 166 printf(" </match>\n"); 167 break; 168 case style_usbids: 169 if (last_vendor != entry->vendor_id) { 170 printf("%04x\n", entry->vendor_id); 171 } 172 printf("\t%04x %s %s\n", entry->product_id, entry->vendor, entry->product); 173 break; 174 } 175 last_vendor = entry->vendor_id; 176 } 177 } else { 178 printf("Error.\n"); 179 exit(1); 180 } 181 182 // For backward comparibility with the #$!+@! ever changing 183 // udev rule style... 184 if (style == style_udev) { 185 printf("GOTO=\"libmtp_rules_end\"\n\n"); 186 printf("LABEL=\"libmtp_usb_device_rules\"\n"); 187 for (i = 0; i < numentries; i++) { 188 LIBMTP_device_entry_t * entry = &entries[i]; 189 190 printf("# %s %s\n", entry->vendor, entry->product); 191 printf("ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", %s\n", entry->vendor_id, entry->product_id, action); 192 } 193 printf("GOTO=\"libmtp_rules_end\"\n\n"); 194 } 195 196 // Then the footer. 197 switch (style) { 198 case style_usbmap: 199 break; 200 case style_udev: 201 printf("LABEL=\"libmtp_rules_end\"\n"); 202 break; 203 case style_hal: 204 printf(" </match>\n"); 205 printf(" </device>\n"); 206 printf("</deviceinfo>\n"); 207 break; 208 case style_usbids: 209 printf("\n"); 210 } 211 212 exit (0); 213 } 214