Add ccdump
[fw/altos] / lib / cp-usb.c
1 /*
2  * Copyright © 2008 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 /*
20  * libusb interface to the GPIO pins on a CP2103.
21  *
22  * Various magic constants came from the cp210x driver published by silabs.
23  */
24
25 #include "cp-usb.h"
26 #include <stdio.h>
27 #include <errno.h>
28 #include <libusb.h>
29
30 struct cp_usb {
31         usb_dev_handle *usb_dev;
32         uint8_t gpio;
33 };
34
35 #define CP2101_UART     0x00
36 #define UART_ENABLE     0x0001
37 #define UART_DISABLE    0x0000
38 #define REQTYPE_HOST_TO_DEVICE  0x41
39 #define REQTYPE_DEVICE_TO_HOST  0xc1
40
41 static int
42 cp_usb_gpio_get(struct cp_usb *cp, uint8_t *gpio_get)
43 {
44         return usb_control_msg(cp->usb_dev,             /* dev */
45                                0xc0,                    /* request */
46                                0xff,                    /* requesttype */
47                                0x00c2,                  /* value */
48                                0,                       /* index */
49                                (char *) gpio_get,       /* bytes */
50                                1,                       /* size */
51                                300);                    /* timeout */
52 }
53
54 static int
55 cp_usb_gpio_set(struct cp_usb *cp, uint8_t mask, uint8_t value)
56 {
57         uint16_t gpio_set = ((uint16_t) value << 8) | mask;
58
59         return usb_control_msg(cp->usb_dev,             /* dev */
60                                0x40,                    /* request */
61                                0xff,                    /* requesttype */
62                                0x37e1,                  /* value */
63                                gpio_set,                /* index */
64                                NULL,                    /* bytes */
65                                0,                       /* size */
66                                300);                    /* timeout */
67 }
68
69 static int
70 cp_usb_uart_enable_disable(struct cp_usb *cp, uint16_t enable)
71 {
72         return usb_control_msg(cp->usb_dev,
73                                CP2101_UART,
74                                REQTYPE_HOST_TO_DEVICE,
75                                enable,
76                                0,
77                                NULL,
78                                0,
79                                300);
80 }
81
82 struct cp_usb *
83 cp_usb_open(void)
84 {
85         struct cp_usb *cp;
86         usb_dev_handle *dev_handle;
87         struct usb_device *dev = NULL;
88         struct usb_bus *bus, *busses;
89         int interface;
90         int ret;
91         uint8_t gpio;
92         
93         usb_init();
94         usb_find_busses();
95         usb_find_devices();
96         
97         busses = usb_get_busses();
98         for (bus = busses; bus; bus = bus->next) {
99                 for (dev = bus->devices; dev; dev = dev->next) {
100                         if (dev->descriptor.idVendor == 0x10c4 &&
101                             dev->descriptor.idProduct == 0xea60)
102                                 break;
103                 }
104                 if (dev)
105                         break;
106         }
107         if (!dev){
108                 perror("No CP2103 found");
109                 return NULL;
110         }
111         cp = calloc(sizeof(struct cp_usb), 1);
112         interface = 0;
113         dev_handle = usb_open(dev);
114         usb_detach_kernel_driver_np(dev_handle, interface);
115         usb_claim_interface(dev_handle, interface);
116         cp->usb_dev = dev_handle;
117         ret = cp_usb_uart_enable_disable(cp, UART_DISABLE);
118         cp->gpio = 0xf;
119         ret = cp_usb_gpio_set(cp, 0xf, cp->gpio);
120         ret = cp_usb_gpio_get(cp, &gpio);
121         return cp;
122 }
123
124 void
125 cp_usb_close(struct cp_usb *cp)
126 {
127         cp_usb_uart_enable_disable(cp, UART_DISABLE);
128         usb_close(cp->usb_dev);
129         free(cp);
130 }
131
132 void
133 cp_usb_write(struct cp_usb *cp, uint8_t mask, uint8_t value)
134 {
135         uint8_t new_gpio;
136         int ret;
137
138         new_gpio = (cp->gpio & ~mask) | (value & mask);
139         if (new_gpio != cp->gpio) {
140                 ret = cp_usb_gpio_set(cp, new_gpio ^ cp->gpio, new_gpio);
141                 if (ret < 0)
142                         perror("gpio_set");
143                 cp->gpio = new_gpio;
144         }
145 }
146
147 uint8_t
148 cp_usb_read(struct cp_usb *cp)
149 {
150         int ret;
151         uint8_t gpio;
152
153         ret = cp_usb_gpio_get(cp, &gpio);
154         if (ret < 0)
155                 perror("gpio_get");
156         return gpio;
157 }