Bump debug speed back up
[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
29 struct cp_usb {
30         usb_dev_handle *usb_dev;
31         uint8_t gpio;
32 };
33
34 #define CP2101_UART     0x00
35 #define UART_ENABLE     0x0001
36 #define UART_DISABLE    0x0000
37 #define REQTYPE_HOST_TO_DEVICE  0x41
38 #define REQTYPE_DEVICE_TO_HOST  0xc1
39
40 static int
41 cp_usb_gpio_get(struct cp_usb *cp, uint8_t *gpio_get)
42 {
43         return usb_control_msg(cp->usb_dev,             /* dev */
44                                0xc0,                    /* request */
45                                0xff,                    /* requesttype */
46                                0x00c2,                  /* value */
47                                0,                       /* index */
48                                (char *) gpio_get,       /* bytes */
49                                1,                       /* size */
50                                300);                    /* timeout */
51 }
52
53 static int
54 cp_usb_gpio_set(struct cp_usb *cp, uint8_t mask, uint8_t value)
55 {
56         uint16_t gpio_set = ((uint16_t) value << 8) | mask;
57
58         return usb_control_msg(cp->usb_dev,             /* dev */
59                                0x40,                    /* request */
60                                0xff,                    /* requesttype */
61                                0x37e1,                  /* value */
62                                gpio_set,                /* index */
63                                NULL,                    /* bytes */
64                                0,                       /* size */
65                                300);                    /* timeout */
66 }
67
68 static int
69 cp_usb_uart_enable_disable(struct cp_usb *cp, uint16_t enable)
70 {
71         return usb_control_msg(cp->usb_dev,
72                                CP2101_UART,
73                                REQTYPE_HOST_TO_DEVICE,
74                                enable,
75                                0,
76                                NULL,
77                                0,
78                                300);
79 }
80
81 struct cp_usb *
82 cp_usb_open(void)
83 {
84         struct cp_usb *cp;
85         usb_dev_handle *dev_handle;
86         struct usb_device *dev = NULL;
87         struct usb_bus *bus, *busses;
88         int interface;
89         int ret;
90         uint8_t gpio;
91         
92         usb_init();
93         usb_find_busses();
94         usb_find_devices();
95         
96         busses = usb_get_busses();
97         for (bus = busses; bus; bus = bus->next) {
98                 for (dev = bus->devices; dev; dev = dev->next) {
99                         if (dev->descriptor.idVendor == 0x10c4 &&
100                             dev->descriptor.idProduct == 0xea60)
101                                 break;
102                 }
103                 if (dev)
104                         break;
105         }
106         if (!dev){
107                 perror("No CP2103 found");
108                 return NULL;
109         }
110         cp = calloc(sizeof(struct cp_usb), 1);
111         interface = 0;
112         dev_handle = usb_open(dev);
113         usb_detach_kernel_driver_np(dev_handle, interface);
114         usb_claim_interface(dev_handle, interface);
115         cp->usb_dev = dev_handle;
116         ret = cp_usb_uart_enable_disable(cp, UART_DISABLE);
117         cp->gpio = 0xf;
118         ret = cp_usb_gpio_set(cp, 0xf, cp->gpio);
119         ret = cp_usb_gpio_get(cp, &gpio);
120         return cp;
121 }
122
123 void
124 cp_usb_close(struct cp_usb *cp)
125 {
126         cp_usb_uart_enable_disable(cp, UART_DISABLE);
127         usb_close(cp->usb_dev);
128         free(cp);
129 }
130
131 void
132 cp_usb_write(struct cp_usb *cp, uint8_t mask, uint8_t value)
133 {
134         uint8_t new_gpio;
135         int ret;
136
137         new_gpio = (cp->gpio & ~mask) | (value & mask);
138         if (new_gpio != cp->gpio) {
139                 ret = cp_usb_gpio_set(cp, new_gpio ^ cp->gpio, new_gpio);
140                 if (ret < 0)
141                         perror("gpio_set");
142                 cp->gpio = new_gpio;
143         }
144 }
145
146 uint8_t
147 cp_usb_read(struct cp_usb *cp)
148 {
149         int ret;
150         uint8_t gpio;
151
152         ret = cp_usb_gpio_get(cp, &gpio);
153         if (ret < 0)
154                 perror("gpio_get");
155         return gpio;
156 }