forked from mkorenkov/ipad_charge
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ipad_charge.c
154 lines (134 loc) · 4.82 KB
/
ipad_charge.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libusb-1.0/libusb.h>
#define VERSION "1.3"
#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
#define VENDOR_APPLE 0x05ac
#define PRODUCT_IPAD1 0x129a
#define PRODUCT_IPAD2 0x129f
#define PRODUCT_IPAD2_3G 0x12a2
#define PRODUCT_IPAD3 0x12a4
int set_charging_mode(libusb_device *dev, bool enable) {
int ret;
struct libusb_device_handle *dev_handle;
if ((ret = libusb_open(dev, &dev_handle)) < 0) {
fprintf(stderr, "ipad_charge: unable to open device: error %d\n", ret);
return ret;
}
if ((ret = libusb_claim_interface(dev_handle, 0)) < 0) {
fprintf(stderr, "ipad_charge: unable to claim interface: error %d\n", ret);
goto out_close;
}
if ((ret = libusb_control_transfer(dev_handle, CTRL_OUT, 0x40, 0x6400, enable ? 0x6400 : 0, NULL, 0, 2000)) < 0) {
fprintf(stderr, "ipad_charge: unable to send command: error %d\n", ret);
goto out_release;
}
ret = 0;
out_release:
libusb_release_interface(dev_handle, 0);
out_close:
libusb_close(dev_handle);
return ret;
}
void help(char *progname) {
printf("Usage: %s [OPTION]\n", progname);
printf("iPad USB charging control utility\n\n");
printf("Available OPTIONs:\n");
printf(" -0, --off\t\t\tdisable charging instead of enabling it\n");
printf(" -h, --help\t\t\tdisplay this help and exit\n");
printf(" -V, --version\t\t\tdisplay version information and exit\n");
printf("\nExamples:\n");
printf(" ipad_charge\t\t\t\t\tenable charging on all connected iPads\n");
printf(" BUSNUM=004 DEVNUM=014 ipad_charge -off\tdisable charging on iPad connected on bus 4, device 14\n");
}
void version() {
printf("ipad_charge v%s - iPad USB charging control utility\n", VERSION);
printf("Copyright (c) 2010 Ondrej Zary - http://www.rainbow-software.org\n");
printf("License: GLPv2\n");
}
int main(int argc, char *argv[]) {
int ret, devnum = 0, busnum = 0;
bool enable = 1;
while (1) {
struct option long_options[] = {
{ .name = "off", .has_arg = 0, .val = '0' },
{ .name = "help", .has_arg = 0, .val = 'h' },
{ .name = "version", .has_arg = 0, .val = 'V' },
{ .name = NULL },
};
int opt = getopt_long(argc, argv, "0hV", long_options, NULL);
if (opt < 0)
break;
switch (opt) {
case '0':
enable = 0;
break;
case 'h':
help(argv[0]);
exit(0);
case 'V':
version();
exit(0);
default:
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
exit(100);
}
}
if (getenv("BUSNUM") && getenv("DEVNUM")) {
busnum = atoi(getenv("BUSNUM"));
devnum = atoi(getenv("DEVNUM"));
}
if (libusb_init(NULL) < 0) {
fprintf(stderr, "ipad_charge: failed to initialise libusb\n");
exit(1);
}
libusb_device **devs;
if (libusb_get_device_list(NULL, &devs) < 0) {
fprintf(stderr, "ipad_charge: unable to enumerate USB devices\n");
ret = 2;
goto out_exit;
}
libusb_device *dev;
int i = 0, count = 0;
/* if BUSNUM and DEVNUM were specified (by udev), find device by address */
if (busnum && devnum) {
while ((dev = devs[i++]) != NULL) {
if (libusb_get_bus_number(dev) == busnum &&
libusb_get_device_address(dev) == devnum) {
if (set_charging_mode(dev, enable) < 0)
fprintf(stderr, "ipad_charge: error setting charge mode\n");
else
count++;
break;
}
}
/* otherwise apply to all devices */
} else {
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
if ((ret = libusb_get_device_descriptor(dev, &desc)) < 0) {
fprintf(stderr, "ipad_charge: failed to get device descriptor: error %d\n", ret);
continue;
}
if (desc.idVendor == VENDOR_APPLE && (desc.idProduct == PRODUCT_IPAD1 || desc.idProduct == PRODUCT_IPAD2 || desc.idProduct == PRODUCT_IPAD2_3G || desc.idProduct == PRODUCT_IPAD3 )) {
if (set_charging_mode(dev, enable) < 0)
fprintf(stderr, "ipad_charge: error setting charge mode\n");
else
count++;
}
}
}
if (count < 1) {
fprintf(stderr, "ipad_charge: no such device or an error occured\n");
ret = 3;
} else
ret = 0;
libusb_free_device_list(devs, 1);
out_exit:
libusb_exit(NULL);
return ret;
}