5 #include <libubox/blobmsg_json.h>
6 #include <libubox/avl.h>
7 #include <libubox/avl-cmp.h>
10 #define DEFAULT_CONFIG "/etc/usb-mode.json"
14 struct blob_attr
*data
;
18 struct libusb_device_descriptor desc
;
19 libusb_device_handle
*devh
;
20 struct blob_attr
*info
;
23 char mfg
[128], prod
[128], serial
[128];
26 static int verbose
= 0;
27 static const char *config_file
= DEFAULT_CONFIG
;
28 static struct blob_buf conf
;
30 static struct blob_attr
**messages
;
31 static int n_messages
;
33 static struct avl_tree devices
;
35 static struct libusb_context
*usb
;
36 static struct libusb_device
**usbdevs
;
39 static int parse_config(void)
46 static const struct blobmsg_policy policy
[__CONF_MAX
] = {
47 [CONF_MESSAGES
] = { .name
= "messages", .type
= BLOBMSG_TYPE_ARRAY
},
48 [CONF_DEVICES
] = { .name
= "devices", .type
= BLOBMSG_TYPE_TABLE
},
50 struct blob_attr
*tb
[__CONF_MAX
];
51 struct blob_attr
*cur
;
55 blobmsg_parse(policy
, __CONF_MAX
, tb
, blob_data(conf
.head
), blob_len(conf
.head
));
56 if (!tb
[CONF_MESSAGES
] || !tb
[CONF_DEVICES
]) {
57 fprintf(stderr
, "Configuration incomplete\n");
61 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
)
64 messages
= calloc(n_messages
, sizeof(*messages
));
66 blobmsg_for_each_attr(cur
, tb
[CONF_MESSAGES
], rem
)
67 messages
[n_messages
++] = cur
;
69 blobmsg_for_each_attr(cur
, tb
[CONF_DEVICES
], rem
) {
70 dev
= calloc(1, sizeof(*dev
));
71 dev
->avl
.key
= blobmsg_name(cur
);
73 avl_insert(&devices
, &dev
->avl
);
79 static int usage(const char *prog
)
81 fprintf(stderr
, "Usage: %s <command> <options>\n"
83 " -l List matching devices\n"
84 " -s Modeswitch matching devices\n"
87 " -v Verbose output\n"
88 " -c <file> Set configuration file to <file> (default: %s)\n"
89 "\n", prog
, DEFAULT_CONFIG
);
93 typedef void (*cmd_cb_t
)(struct usbdev_data
*data
);
95 static struct blob_attr
*
96 find_dev_data(struct usbdev_data
*data
, struct device
*dev
)
98 struct blob_attr
*cur
;
101 blobmsg_for_each_attr(cur
, dev
->data
, rem
) {
102 const char *name
= blobmsg_name(cur
);
106 if (!strcmp(blobmsg_name(cur
), "*"))
109 next
= strchr(name
, '=');
114 if (!strncmp(name
, "uMa", 3)) {
116 } else if (!strncmp(name
, "uPr", 3)) {
118 } else if (!strncmp(name
, "uSe", 3)) {
121 /* ignore unsupported scsi attributes */
125 if (!strcmp(val
, next
))
132 static void iterate_devs(cmd_cb_t cb
)
134 struct usbdev_data data
;
141 for (i
= 0; i
< n_usbdevs
; i
++) {
142 memset(&data
, 0, sizeof(data
));
144 if (libusb_get_device_descriptor(usbdevs
[i
], &data
.desc
))
147 sprintf(data
.idstr
, "%04x:%04x", data
.desc
.idVendor
, data
.desc
.idProduct
);
149 dev
= avl_find_element(&devices
, data
.idstr
, dev
, avl
);
153 if (libusb_open(usbdevs
[i
], &data
.devh
))
156 libusb_get_string_descriptor_ascii(
157 data
.devh
, data
.desc
.iManufacturer
,
158 (void *) data
.mfg
, sizeof(data
.mfg
));
159 libusb_get_string_descriptor_ascii(
160 data
.devh
, data
.desc
.iProduct
,
161 (void *) data
.prod
, sizeof(data
.prod
));
162 libusb_get_string_descriptor_ascii(
163 data
.devh
, data
.desc
.iSerialNumber
,
164 (void *) data
.serial
, sizeof(data
.serial
));
166 data
.info
= find_dev_data(&data
, dev
);
169 libusb_close(data
.devh
);
173 static void handle_list(struct usbdev_data
*data
)
175 fprintf(stderr
, "Found device: %s (Manufacturer: \"%s\", Product: \"%s\", Serial: \"%s\")\n",
176 data
->idstr
, data
->mfg
, data
->prod
, data
->serial
);
187 static void handle_generic(struct usbdev_data
*data
, struct blob_attr
**tb
)
189 fprintf(stderr
, "Do generic switch!\n");
192 static void handle_huawei(struct usbdev_data
*data
, struct blob_attr
**tb
)
197 static void handle_sierra(struct usbdev_data
*data
, struct blob_attr
**tb
)
202 static void handle_sony(struct usbdev_data
*data
, struct blob_attr
**tb
)
207 static void handle_qisda(struct usbdev_data
*data
, struct blob_attr
**tb
)
212 static void handle_gct(struct usbdev_data
*data
, struct blob_attr
**tb
)
217 static void handle_kobil(struct usbdev_data
*data
, struct blob_attr
**tb
)
222 static void handle_sequans(struct usbdev_data
*data
, struct blob_attr
**tb
)
227 static void handle_mobile_action(struct usbdev_data
*data
, struct blob_attr
**tb
)
232 static void handle_cisco(struct usbdev_data
*data
, struct blob_attr
**tb
)
251 static const struct {
253 void (*cb
)(struct usbdev_data
*data
, struct blob_attr
**tb
);
254 } modeswitch_cb
[__MODE_MAX
] = {
255 [MODE_GENERIC
] = { "Generic", handle_generic
},
256 [MODE_HUAWEI
] = { "Huawei", handle_huawei
},
257 [MODE_SIERRA
] = { "Sierra", handle_sierra
},
258 [MODE_SONY
] = { "Sony", handle_sony
},
259 [MODE_QISDA
] = { "Qisda", handle_qisda
},
260 [MODE_GCT
] = { "GCT", handle_gct
},
261 [MODE_KOBIL
] = { "Kobil", handle_kobil
},
262 [MODE_SEQUANS
] = { "Sequans", handle_sequans
},
263 [MODE_MOBILE_ACTION
] = { "MobileAction", handle_mobile_action
},
264 [MODE_CISCO
] = { "Cisco", handle_cisco
},
267 static void handle_switch(struct usbdev_data
*data
)
269 static const struct blobmsg_policy data_policy
[__DATA_MAX
] = {
270 [DATA_MODE
] = { .name
= "mode", .type
= BLOBMSG_TYPE_STRING
},
271 [DATA_MSG
] = { .name
= "msg", .type
= BLOBMSG_TYPE_INT32
},
272 [DATA_MSG2
] = { .name
= "msg2", .type
= BLOBMSG_TYPE_INT32
},
273 [DATA_MSG3
] = { .name
= "msg3", .type
= BLOBMSG_TYPE_INT32
},
275 struct blob_attr
*tb
[__DATA_MAX
];
276 int mode
= MODE_GENERIC
;
278 blobmsg_parse(data_policy
, __DATA_MAX
, tb
, blobmsg_data(data
->info
), blobmsg_data_len(data
->info
));
284 modestr
= blobmsg_data(tb
[DATA_MODE
]);
285 for (i
= 0; i
< __MODE_MAX
; i
++) {
286 if (strcmp(modeswitch_cb
[i
].name
, modestr
) != 0)
294 modeswitch_cb
[mode
].cb(data
, tb
);
297 int main(int argc
, char **argv
)
303 avl_init(&devices
, avl_strcmp
, false, NULL
);
305 while ((ch
= getopt(argc
, argv
, "lsc:v")) != -1) {
314 config_file
= optarg
;
320 return usage(argv
[0]);
324 blob_buf_init(&conf
, 0);
325 if (!blobmsg_add_json_from_file(&conf
, config_file
) ||
327 fprintf(stderr
, "Failed to load config file\n");
331 ret
= libusb_init(&usb
);
333 fprintf(stderr
, "Failed to initialize libusb: %s\n", libusb_error_name(ret
));
337 n_usbdevs
= libusb_get_device_list(usb
, &usbdevs
);
339 libusb_free_device_list(usbdevs
, 1);