1 /**
2 * \file hotplug.c
3 * Example program to create hotplug scripts.
4 *
5 * Copyright (C) 2005-2007 Linus Walleij <triad@df.lth.se>
6 * Copyright (C) 2006-2008 Marcus Meissner <marcus@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
usage(void)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
main(int argc,char ** argv)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