Add a README
[pub/pl2303-ft232-gpio.git] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 /* According to POSIX.1-2001 */
4 #include <sys/select.h>
5 #include <string.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <termios.h>
10 #include <fcntl.h>
11 #include <signal.h>
12 #include <usb.h>
13 #include <getopt.h>
14
15
16 #define _GNU_SOURCE
17 #include <getopt.h>
18
19
20 #define I_VENDOR_NUM 0x67b
21 #define I_PRODUCT_NUM 0x2303
22
23
24 #define VENDOR_READ_REQUEST_TYPE 0xc0
25 #define VENDOR_READ_REQUEST 0x01
26
27 #define VENDOR_WRITE_REQUEST_TYPE 0x40
28 #define VENDOR_WRITE_REQUEST 0x01
29
30
31 void handle_error(int ret)
32 {
33 if (ret<0) {
34 perror("Failed to write to PL2303 device");
35 fprintf(stderr, "Have you installed the correct udev rules?\n");
36 exit(1);
37 }
38 }
39
40
41 /* Get current GPIO register from PL2303 */
42 char gpio_read_reg(usb_dev_handle *h)
43 {
44 char buf;
45 int bytes = usb_control_msg(
46 h, // handle obtained with usb_open()
47 VENDOR_READ_REQUEST_TYPE, // bRequestType
48 VENDOR_READ_REQUEST, // bRequest
49 0x0081, // wValue
50 0, // wIndex
51 &buf, // pointer to destination buffer
52 1, // wLength
53 100
54 );
55 handle_error(bytes);
56 return buf;
57 }
58
59 void gpio_write_reg(usb_dev_handle *h, unsigned char reg)
60 {
61 int bytes = usb_control_msg(
62 h, // handle obtained with usb_open()
63 VENDOR_WRITE_REQUEST_TYPE, // bRequestType
64 VENDOR_WRITE_REQUEST, // bRequest
65 1, // wValue
66 reg, // wIndex
67 0, // pointer to destination buffer
68 0, // wLength
69 6000
70 );
71 handle_error(bytes);
72
73 }
74
75 int gpio_dir_shift(int gpio) {
76 if (gpio == 0)
77 return 4;
78 if (gpio == 1)
79 return 5;
80 return 4; /* default to 0 */
81 }
82
83 int gpio_val_shift(int gpio) {
84 if (gpio == 0)
85 return 6;
86 if (gpio == 1)
87 return 7;
88 return 6; /* default to 0 */
89 }
90
91
92 void gpio_out(usb_dev_handle *h, int gpio, int value)
93 {
94 int shift_dir = gpio_dir_shift(gpio);
95 int shift_val = gpio_val_shift(gpio);
96 unsigned char reg = gpio_read_reg(h);
97 reg |= (1 << shift_dir);
98 reg &= ~(1 << shift_val);
99 reg |= (value << shift_val);
100 gpio_write_reg(h, reg);
101 }
102
103 void gpio_in(usb_dev_handle *h, int gpio, int pullup)
104 {
105 int shift_dir = gpio_dir_shift(gpio);
106 int shift_val = gpio_val_shift(gpio);
107
108 unsigned char reg = gpio_read_reg(h);
109 reg &= ~(1 << shift_dir);
110 reg &= ~(1 << shift_val);
111 reg |= (pullup << shift_val);
112 gpio_write_reg(h, reg);
113 }
114
115 int gpio_read(usb_dev_handle *h, int gpio)
116 {
117 unsigned char r = gpio_read_reg(h);
118 int shift = gpio_val_shift(gpio);
119 return (r & (1<<shift));
120 }
121
122 static struct option long_options[] =
123 {
124 /* These options set a flag. */
125 {"help", no_argument, 0, 'h'},
126 {"gpio", required_argument, 0, 'g'},
127 {"in", optional_argument, 0, 'i'},
128 {"out", required_argument, 0, 'o'},
129 {"read", no_argument, 0, 'r'},
130 {0, 0, 0, 0}
131 };
132
133 void usage(const char *self)
134 {
135 printf("PL2303HXA userspace GPIO control tool\n"
136 "(c) Andrew 'Necromant' Andrianov 2014, License: GPLv3\n"
137 "Usage: %s [action1] [action2] ...\n"
138 "Options are: \n"
139 "\t -g/--gpio n - select GPIO, n=0, 1\n"
140 "\t -i/--in - configure GPIO as input\n"
141 "\t -o/--out v - configure GPIO as output with value v\n"
142 "\t -r/--read v - Read current GPIO value\n\n"
143 "Examples: \n"
144 "\t%s --gpio=1 --out 1\n"
145 "\t%s --gpio=0 --out 0 --gpio=1 --in\n"
146 "\n", self, self, self);
147 }
148
149 extern usb_dev_handle *nc_usb_open(int vendor, int product, char *vendor_name, char *product_name, char *serial);
150 void check_handle(usb_dev_handle **h)
151 {
152 if (*h)
153 return;
154
155 /* TODO: Make a proper way to select different PL2303 devices. */
156 *h = nc_usb_open(I_VENDOR_NUM, I_PRODUCT_NUM, NULL, NULL, NULL);
157 if (!h) {
158 fprintf(stderr, "No PL2303 USB device found ;(\n");
159 exit(1);
160 }
161
162 /* We don't set config or claim interface, pl2303 kernel driver does
163 * that for us.
164 */
165 }
166
167 int main(int argc, char* argv[])
168 {
169 char c;
170 usb_dev_handle *h = NULL;
171 int gpio=0;
172 if (argc == 1)
173 {
174 usage(argv[0]);
175 exit(1);
176 }
177 while(1) {
178 int option_index = 0;
179
180 c = getopt_long (argc, argv, "hg:i:o:r:",
181 long_options, &option_index);
182
183 /* Detect the end of the options. */
184 if (c == -1)
185 break;
186
187 switch (c)
188 {
189 case 'h':
190 usage(argv[0]);
191 exit(1);
192 break;
193 case 'g':
194 gpio = atoi(optarg);
195 break;
196 case 'i':
197 {
198 int v=0;
199 check_handle(&h);
200 if (optarg)
201 v = atoi(optarg);
202 gpio_in(h, gpio, v);
203 break;
204 }
205 case 'o':
206 {
207 int v=0;
208 check_handle(&h);
209 if (optarg)
210 v = atoi(optarg);
211 gpio_out(h, gpio, v);
212 break;
213 }
214 case 'r':
215 {
216 check_handle(&h);
217 printf("%d\n", gpio_read(h, gpio) ? 1 : 0);
218 break;
219 }
220
221 }
222 }
223
224 return 0;
225
226 //GP0 == LDR
227 //GP1 == RST
228 }