blob: 8e118ae0a5d61f7c2402c5180905fa912e278397 [file] [log] [blame]
Linus Walleij6d3c2222010-11-30 23:42:32 +00001/**
2 * \file mtp-hotplug.c
Linus Walleij4f4082b2010-12-01 23:00:00 +00003 * Program to create hotplug scripts.
Linus Walleij543badf2007-02-05 19:07:38 +00004 *
Linus Walleij1ff1a642012-01-28 10:54:37 +01005 * Copyright (C) 2005-2012 Linus Walleij <triad@df.lth.se>
Linus Walleij161fcce2008-03-12 22:02:59 +00006 * Copyright (C) 2006-2008 Marcus Meissner <marcus@jet.franken.de>
Linus Walleij543badf2007-02-05 19:07:38 +00007 *
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 */
Linus Walleij6d3c2222010-11-30 23:42:32 +000023#include <libmtp.h>
Linus Walleij6fd2f082006-03-28 07:19:22 +000024#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28
29static void usage(void)
30{
Denis Dupeyron83e79a22011-02-07 22:40:45 -070031 fprintf(stderr, "usage: hotplug [-u -H -i -a\"ACTION\"] -p\"DIR\" -g\"GROUP\" -m\"MODE\"\n");
Marcus Meissner4b1b2c72015-03-22 18:37:30 +010032 fprintf(stderr, " -w: use hwdb syntax\n");
Linus Walleij2d069e22006-08-23 19:05:18 +000033 fprintf(stderr, " -u: use udev syntax\n");
Linus Walleije5272542010-11-30 23:26:11 +000034 fprintf(stderr, " -o: use old udev syntax\n");
Linus Walleijf73de152006-11-25 21:44:44 +000035 fprintf(stderr, " -H: use hal syntax\n");
Linus Walleij99466e32007-05-11 21:42:53 +000036 fprintf(stderr, " -i: use usb.ids simple list syntax\n");
Linus Walleij6fd2f082006-03-28 07:19:22 +000037 fprintf(stderr, " -a\"ACTION\": perform udev action ACTION on attachment\n");
Denis Dupeyronb9eed542011-01-26 22:31:16 -070038 fprintf(stderr, " -p\"DIR\": directory where mtp-probe will be installed\n");
Denis Dupeyron83e79a22011-02-07 22:40:45 -070039 fprintf(stderr, " -g\"GROUP\": file group for device nodes\n");
40 fprintf(stderr, " -m\"MODE\": file mode for device nodes\n");
Linus Walleij6fd2f082006-03-28 07:19:22 +000041 exit(1);
42}
43
Linus Walleijf73de152006-11-25 21:44:44 +000044enum style {
jefferaif28f2a12007-05-24 23:07:41 +000045 style_usbmap,
46 style_udev,
Linus Walleije5272542010-11-30 23:26:11 +000047 style_udev_old,
jefferaif28f2a12007-05-24 23:07:41 +000048 style_hal,
Marcus Meissner4b1b2c72015-03-22 18:37:30 +010049 style_usbids,
50 style_hwdb
Linus Walleijf73de152006-11-25 21:44:44 +000051};
52
Linus Walleij6fd2f082006-03-28 07:19:22 +000053int main (int argc, char **argv)
54{
55 LIBMTP_device_entry_t *entries;
56 int numentries;
57 int i;
58 int ret;
Linus Walleijf73de152006-11-25 21:44:44 +000059 enum style style = style_usbmap;
Linus Walleij6fd2f082006-03-28 07:19:22 +000060 int opt;
61 extern int optind;
62 extern char *optarg;
63 char *udev_action = NULL;
Linus Walleijc4cd50b2011-01-08 22:50:07 +000064 /*
65 * You could tag on MODE="0666" here to enfore writeable
66 * device nodes, use the command line argument for that.
67 * Current udev default rules will make any device tagged
68 * with ENV{ID_MEDIA_PLAYER}=1 writable for the console
69 * user.
70 */
71 char default_udev_action[] = "SYMLINK+=\"libmtp-%k\", ENV{ID_MTP_DEVICE}=\"1\", ENV{ID_MEDIA_PLAYER}=\"1\"";
Linus Walleij71b8c0f2007-09-06 09:09:14 +000072 char *action; // To hold the action actually used.
Linus Walleijcbfe1772010-11-28 21:20:51 +000073 uint16_t last_vendor = 0x0000U;
Linus Walleij59d69ab2011-02-09 21:44:37 +010074 char mtp_probe_dir[256];
Denis Dupeyron83e79a22011-02-07 22:40:45 -070075 char *udev_group= NULL;
76 char *udev_mode = NULL;
Linus Walleij6fd2f082006-03-28 07:19:22 +000077
Marcus Meissner4b1b2c72015-03-22 18:37:30 +010078 while ( (opt = getopt(argc, argv, "wuoiHa:p:g:m:")) != -1 ) {
Linus Walleij6fd2f082006-03-28 07:19:22 +000079 switch (opt) {
80 case 'a':
81 udev_action = strdup(optarg);
Denis Dupeyronb9eed542011-01-26 22:31:16 -070082 break;
Linus Walleij6fd2f082006-03-28 07:19:22 +000083 case 'u':
Linus Walleijf73de152006-11-25 21:44:44 +000084 style = style_udev;
85 break;
Linus Walleije5272542010-11-30 23:26:11 +000086 case 'o':
87 style = style_udev_old;
88 break;
Linus Walleijf73de152006-11-25 21:44:44 +000089 case 'H':
90 style = style_hal;
Linus Walleij6fd2f082006-03-28 07:19:22 +000091 break;
Linus Walleij99466e32007-05-11 21:42:53 +000092 case 'i':
93 style = style_usbids;
94 break;
Marcus Meissner4b1b2c72015-03-22 18:37:30 +010095 case 'w':
96 style = style_hwdb;
97 break;
Denis Dupeyronb9eed542011-01-26 22:31:16 -070098 case 'p':
Linus Walleij59d69ab2011-02-09 21:44:37 +010099 strncpy(mtp_probe_dir,optarg,sizeof(mtp_probe_dir));
100 mtp_probe_dir[sizeof(mtp_probe_dir)-1] = '\0';
101 if (strlen(mtp_probe_dir) <= 1) {
102 printf("Supply some sane mtp-probe dir\n");
103 exit(1);
104 }
105 /* Make sure the dir ends with '/' */
106 if (mtp_probe_dir[strlen(mtp_probe_dir)-1] != '/') {
107 int index = strlen(mtp_probe_dir);
108 if (index >= (sizeof(mtp_probe_dir)-1)) {
109 exit(1);
110 }
111 mtp_probe_dir[index] = '/';
112 mtp_probe_dir[index+1] = '\0';
113 }
Linus Walleijdf3ef0f2011-02-09 22:05:52 +0100114 /* Don't add the standard udev path... */
115 if (!strcmp(mtp_probe_dir, "/lib/udev/")) {
116 mtp_probe_dir[0] = '\0';
117 }
Denis Dupeyronb9eed542011-01-26 22:31:16 -0700118 break;
Denis Dupeyron83e79a22011-02-07 22:40:45 -0700119 case 'g':
120 udev_group = strdup(optarg);
121 break;
122 case 'm':
123 udev_mode = strdup(optarg);
124 break;
125 default:
Linus Walleij6fd2f082006-03-28 07:19:22 +0000126 usage();
127 }
128 }
129
Linus Walleij71b8c0f2007-09-06 09:09:14 +0000130 if (udev_action != NULL) {
131 action = udev_action;
132 } else {
133 action = default_udev_action;
134 }
135
Linus Walleij6fd2f082006-03-28 07:19:22 +0000136 LIBMTP_Init();
137 ret = LIBMTP_Get_Supported_Devices_List(&entries, &numentries);
138 if (ret == 0) {
Linus Walleijf73de152006-11-25 21:44:44 +0000139 switch (style) {
140 case style_udev:
Linus Walleij6fd2f082006-03-28 07:19:22 +0000141 printf("# UDEV-style hotplug map for libmtp\n");
142 printf("# Put this file in /etc/udev/rules.d\n\n");
Linus Walleij50d47a52007-09-05 07:59:40 +0000143 printf("ACTION!=\"add\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleij1d829652009-06-02 19:53:01 +0000144 printf("ENV{MAJOR}!=\"?*\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleij71b8c0f2007-09-06 09:09:14 +0000145 printf("SUBSYSTEM==\"usb\", GOTO=\"libmtp_usb_rules\"\n"
Linus Walleij8632a4d2007-07-30 14:51:41 +0000146 "GOTO=\"libmtp_rules_end\"\n\n"
Linus Walleij71b8c0f2007-09-06 09:09:14 +0000147 "LABEL=\"libmtp_usb_rules\"\n\n");
Linus Walleij1ff1a642012-01-28 10:54:37 +0100148 printf("# Some sensitive devices we surely don\'t wanna probe\n");
149 printf("# Color instruments\n");
Linus Walleijc65bc902011-10-22 21:16:22 +0200150 printf("ATTR{idVendor}==\"0670\", GOTO=\"libmtp_rules_end\"\n");
151 printf("ATTR{idVendor}==\"0765\", GOTO=\"libmtp_rules_end\"\n");
152 printf("ATTR{idVendor}==\"085c\", GOTO=\"libmtp_rules_end\"\n");
153 printf("ATTR{idVendor}==\"0971\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleij1ff1a642012-01-28 10:54:37 +0100154 printf("# Canon scanners that look like MTP devices (PID 0x22nn)\n");
155 printf("ATTR{idVendor}==\"04a9\", ATTR{idProduct}==\"22*\", GOTO=\"libmtp_rules_end\"\n");
Alessio Treglia35e6d202012-09-11 22:00:22 +0200156 printf("# Canon digital camera (EOS 3D) that looks like MTP device (PID 0x3113)\n");
157 printf("ATTR{idVendor}==\"04a9\", ATTR{idProduct}==\"3113\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleijf7ff08a2012-03-22 23:10:33 +0100158 printf("# Sensitive Atheros devices that look like MTP devices\n");
159 printf("ATTR{idVendor}==\"0cf3\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleij25e40ec2012-06-27 22:21:22 +0200160 printf("# Sensitive Atmel JTAG programmers\n");
161 printf("ATTR{idVendor}==\"03eb\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleij01324212012-10-20 21:40:03 +0200162 printf("# Sensitive Philips device\n");
163 printf("ATTR{idVendor}==\"0471\", ATTR{idProduct}==\"083f\", GOTO=\"libmtp_rules_end\"\n");
Linus Walleijf73de152006-11-25 21:44:44 +0000164 break;
Linus Walleije5272542010-11-30 23:26:11 +0000165 case style_udev_old:
166 printf("# UDEV-style hotplug map for libmtp\n");
167 printf("# Put this file in /etc/udev/rules.d\n\n");
168 printf("ACTION!=\"add\", GOTO=\"libmtp_rules_end\"\n");
169 printf("ENV{MAJOR}!=\"?*\", GOTO=\"libmtp_rules_end\"\n");
170 printf("SUBSYSTEM==\"usb_device\", GOTO=\"libmtp_usb_device_rules\"\n"
171 "GOTO=\"libmtp_rules_end\"\n\n"
172 "LABEL=\"libmtp_usb_device_rules\"\n\n");
173 break;
Linus Walleijf73de152006-11-25 21:44:44 +0000174 case style_usbmap:
Linus Walleij6fd2f082006-03-28 07:19:22 +0000175 printf("# This usermap will call the script \"libmtp.sh\" whenever a known MTP device is attached.\n\n");
Linus Walleijf73de152006-11-25 21:44:44 +0000176 break;
177 case style_hal:
178 printf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <!-- -*- SGML -*- -->\n");
179 printf("<!-- This file was generated by %s - - fdi -->\n", argv[0]);
180 printf("<deviceinfo version=\"0.2\">\n");
jefferaif28f2a12007-05-24 23:07:41 +0000181 printf(" <device>\n");
Linus Walleij161fcce2008-03-12 22:02:59 +0000182 printf(" <match key=\"info.subsystem\" string=\"usb\">\n");
Linus Walleijf73de152006-11-25 21:44:44 +0000183 break;
Linus Walleij99466e32007-05-11 21:42:53 +0000184 case style_usbids:
185 printf("# usb.ids style device list from libmtp\n");
186 printf("# Compare: http://www.linux-usb.org/usb.ids\n");
187 break;
Marcus Meissner4b1b2c72015-03-22 18:37:30 +0100188 case style_hwdb:
189 printf("# hardware database file for libmtp supported devices\n");
190 break;
Linus Walleij6fd2f082006-03-28 07:19:22 +0000191 }
192
193 for (i = 0; i < numentries; i++) {
194 LIBMTP_device_entry_t * entry = &entries[i];
jefferaif28f2a12007-05-24 23:07:41 +0000195
Linus Walleijf73de152006-11-25 21:44:44 +0000196 switch (style) {
Linus Walleije5272542010-11-30 23:26:11 +0000197 case style_udev:
198 case style_udev_old:
199 printf("# %s %s\n", entry->vendor, entry->product);
Denis Dupeyron83e79a22011-02-07 22:40:45 -0700200 printf("ATTR{idVendor}==\"%04x\", ATTR{idProduct}==\"%04x\", %s", entry->vendor_id, entry->product_id, action);
201 if (udev_group != NULL) printf(", GROUP=\"%s\"", udev_group);
202 if (udev_mode != NULL) printf(", MODE=\"%s\"", udev_mode);
203 printf("\n");
Linus Walleije5272542010-11-30 23:26:11 +0000204 break;
Linus Walleij50d47a52007-09-05 07:59:40 +0000205 case style_usbmap:
jefferaida9687e2007-10-16 16:44:15 +0000206 printf("# %s %s\n", entry->vendor, entry->product);
jefferaif28f2a12007-05-24 23:07:41 +0000207 printf("libmtp.sh 0x0003 0x%04x 0x%04x 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000\n", entry->vendor_id, entry->product_id);
208 break;
Marcus Meissner4b1b2c72015-03-22 18:37:30 +0100209 case style_hal:
jefferaida9687e2007-10-16 16:44:15 +0000210 printf(" <!-- %s %s -->\n", entry->vendor, entry->product);
jefferaif28f2a12007-05-24 23:07:41 +0000211 printf(" <match key=\"usb.vendor_id\" int=\"0x%04x\">\n", entry->vendor_id);
212 printf(" <match key=\"usb.product_id\" int=\"0x%04x\">\n", entry->product_id);
Linus Walleij3e13dda2007-07-09 22:42:17 +0000213 /* FIXME: If hal >=0.5.10 can be depended upon, the matches below with contains_not can instead use addset */
jefferaif28f2a12007-05-24 23:07:41 +0000214 printf(" <match key=\"info.capabilities\" contains_not=\"portable_audio_player\">\n");
215 printf(" <append key=\"info.capabilities\" type=\"strlist\">portable_audio_player</append>\n");
216 printf(" </match>\n");
jefferai0bfe3ab2007-10-09 22:23:48 +0000217 printf(" <merge key=\"info.vendor\" type=\"string\">%s</merge>\n", entry->vendor);
218 printf(" <merge key=\"info.product\" type=\"string\">%s</merge>\n", entry->product);
jefferaif28f2a12007-05-24 23:07:41 +0000219 printf(" <merge key=\"info.category\" type=\"string\">portable_audio_player</merge>\n");
220 printf(" <merge key=\"portable_audio_player.access_method\" type=\"string\">user</merge>\n");
221 printf(" <match key=\"portable_audio_player.access_method.protocols\" contains_not=\"mtp\">\n");
222 printf(" <append key=\"portable_audio_player.access_method.protocols\" type=\"strlist\">mtp</append>\n");
223 printf(" </match>\n");
224 printf(" <append key=\"portable_audio_player.access_method.drivers\" type=\"strlist\">libmtp</append>\n");
Linus Walleij3e13dda2007-07-09 22:42:17 +0000225 /* FIXME: needs true list of formats ... But all of them can do MP3 and WMA */
jefferaif28f2a12007-05-24 23:07:41 +0000226 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/mpeg\">\n");
227 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/mpeg</append>\n");
228 printf(" </match>\n");
229 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"audio/x-ms-wma\">\n");
230 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">audio/x-ms-wma</append>\n");
231 printf(" </match>\n");
Linus Walleij3e13dda2007-07-09 22:42:17 +0000232 /* Special hack to support the OGG format - irivers, TrekStor and NormSoft (Palm) can always play these files! */
233 if (entry->vendor_id == 0x4102 || // iriver
234 entry->vendor_id == 0x066f || // TrekStor
235 entry->vendor_id == 0x1703) { // NormSoft, Inc.
236 printf(" <match key=\"portable_audio_player.output_formats\" contains_not=\"application/ogg\">\n");
237 printf(" <append key=\"portable_audio_player.output_formats\" type=\"strlist\">application/ogg</append>\n");
238 printf(" </match>\n");
239 }
jefferaif28f2a12007-05-24 23:07:41 +0000240 printf(" <merge key=\"portable_audio_player.libmtp.protocol\" type=\"string\">mtp</merge>\n");
jefferaif28f2a12007-05-24 23:07:41 +0000241 printf(" </match>\n");
242 printf(" </match>\n");
243 break;
Marcus Meissner4b1b2c72015-03-22 18:37:30 +0100244 case style_usbids:
jefferaif28f2a12007-05-24 23:07:41 +0000245 if (last_vendor != entry->vendor_id) {
246 printf("%04x\n", entry->vendor_id);
247 }
jefferaida9687e2007-10-16 16:44:15 +0000248 printf("\t%04x %s %s\n", entry->product_id, entry->vendor, entry->product);
jefferaif28f2a12007-05-24 23:07:41 +0000249 break;
Marcus Meissner4b1b2c72015-03-22 18:37:30 +0100250 case style_hwdb:
251 printf("# %s %s\n", entry->vendor, entry->product);
252 printf("usb:v%04xp%04x*\n", entry->vendor_id, entry->product_id);
253 printf(" ID_MEDIA_PLAYER=1\n");
254 printf(" ID_MTP_DEVICE=1\n");
255 printf("\n");
256 break;
Linus Walleij6fd2f082006-03-28 07:19:22 +0000257 }
Linus Walleij99466e32007-05-11 21:42:53 +0000258 last_vendor = entry->vendor_id;
Linus Walleij6fd2f082006-03-28 07:19:22 +0000259 }
260 } else {
261 printf("Error.\n");
262 exit(1);
263 }
264
Linus Walleij71b8c0f2007-09-06 09:09:14 +0000265 // Then the footer.
Linus Walleijf73de152006-11-25 21:44:44 +0000266 switch (style) {
267 case style_usbmap:
Marcus Meissner4b1b2c72015-03-22 18:37:30 +0100268 case style_hwdb:
Linus Walleijf73de152006-11-25 21:44:44 +0000269 break;
270 case style_udev:
Linus Walleij6d3c2222010-11-30 23:42:32 +0000271 case style_udev_old:
Linus Walleij549f49a2010-12-05 14:00:34 +0000272 /*
273 * This is code that invokes the mtp-probe program on
274 * every USB device that is either PTP or vendor specific
275 */
Linus Walleij94381832011-01-19 17:47:39 +0100276 printf("\n# Autoprobe vendor-specific, communication and PTP devices\n");
Linus Walleijd5ab76b2011-10-22 15:04:02 +0200277 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);
Denis Dupeyron83e79a22011-02-07 22:40:45 -0700278 if (udev_group != NULL) printf(", GROUP=\"%s\"", udev_group);
279 if (udev_mode != NULL) printf(", MODE=\"%s\"", udev_mode);
280 printf("\n");
281 printf("\nLABEL=\"libmtp_rules_end\"\n");
Linus Walleijf73de152006-11-25 21:44:44 +0000282 break;
283 case style_hal:
jefferaif28f2a12007-05-24 23:07:41 +0000284 printf(" </match>\n");
285 printf(" </device>\n");
Linus Walleijf73de152006-11-25 21:44:44 +0000286 printf("</deviceinfo>\n");
287 break;
Linus Walleij99466e32007-05-11 21:42:53 +0000288 case style_usbids:
289 printf("\n");
Linus Walleij6fd2f082006-03-28 07:19:22 +0000290 }
291
292 exit (0);
293}