usbser: remove duplicate definitions
[bertos.git] / bertos / drv / usbser.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \author Andrea Righi <arighi@develer.com>
34  *
35  * \brief Generic USB serial device driver.
36  *
37  */
38
39 #include "cfg/cfg_usbser.h"
40
41 #define LOG_LEVEL  USB_SERIAL_LOG_LEVEL
42 #define LOG_FORMAT USB_SERIAL_LOG_FORMAT
43
44 #include <cfg/log.h>
45 #include <cfg/debug.h>
46 #include <cfg/macros.h>
47
48 #include <cfg/compiler.h>
49 #include <cfg/module.h>
50
51 #include <cpu/irq.h> /* IRQ_DISABLE / IRQ_ENABLE */
52 #include <cpu/power.h> /* cpu_relax() */
53
54 #include <drv/usb.h>
55 #include <drv/usb_endpoint.h>
56
57 #include <string.h> /* memcpy() */
58
59 #include "drv/usbser.h"
60
61 #define USB_SERIAL_INTERFACES   1
62 #define USB_SERIAL_ENDPOINTS    3
63
64 #define USB_STRING_MANUFACTURER 1
65 #define USB_STRING_PRODUCT      2
66 #define USB_STRING_SERIAL       3
67
68 static UsbDeviceDesc usb_serial_device_descriptor =
69 {
70         .bLength = sizeof(usb_serial_device_descriptor),
71         .bDescriptorType = USB_DT_DEVICE,
72         .bcdUSB = 0x110,
73         .bDeviceClass = USB_CLASS_COMM,
74         .bDeviceSubClass = 0,
75         .bDeviceProtocol = 0,
76         .idVendor = USB_SERIAL_VENDOR_ID,
77         .idProduct = USB_SERIAL_PRODUCT_ID,
78         .bcdDevice = 0,
79         .iManufacturer = USB_STRING_MANUFACTURER,
80         .iProduct = USB_STRING_PRODUCT,
81         .iSerialNumber = USB_STRING_SERIAL,
82         .bNumConfigurations = 1,
83 };
84
85 static const UsbConfigDesc usb_serial_config_descriptor =
86 {
87         .bLength = sizeof(usb_serial_config_descriptor),
88         .bDescriptorType = USB_DT_CONFIG,
89         .bNumInterfaces = USB_SERIAL_INTERFACES,
90         .bConfigurationValue = 1,
91         .iConfiguration = 0,
92         .bmAttributes = USB_CONFIG_ATT_ONE,
93         .bMaxPower = 50, /* 100 mA */
94 };
95
96 static const UsbInterfaceDesc usb_serial_interface_descriptor =
97 {
98         .bLength = sizeof(usb_serial_interface_descriptor),
99         .bDescriptorType = USB_DT_INTERFACE,
100         .bInterfaceNumber = 0,
101         .bAlternateSetting = 0,
102         .bNumEndpoints = USB_SERIAL_ENDPOINTS,
103         .bInterfaceClass = 0xff,
104         .bInterfaceSubClass = 0,
105         .bInterfaceProtocol = 0,
106         .iInterface = 0,
107 };
108
109 static const UsbEndpointDesc usb_serial_ep_report_descriptor =
110 {
111         .bLength = sizeof(usb_serial_ep_report_descriptor),
112         .bDescriptorType = USB_DT_ENDPOINT,
113         .bEndpointAddress = USB_DIR_IN | USB_SERIAL_EP_REPORT,
114         .bmAttributes = USB_ENDPOINT_XFER_INT,
115         .wMaxPacketSize = usb_cpu_to_le16((uint16_t)8),
116         .bInterval = 1,
117 };
118
119 static const UsbEndpointDesc usb_serial_ep_in_descriptor =
120 {
121         .bLength = sizeof(usb_serial_ep_in_descriptor),
122         .bDescriptorType = USB_DT_ENDPOINT,
123         .bEndpointAddress = USB_DIR_IN | USB_SERIAL_EP_IN,
124         .bmAttributes = USB_ENDPOINT_XFER_BULK,
125         .wMaxPacketSize = usb_cpu_to_le16((uint16_t)64),
126         .bInterval = 0,
127 };
128
129 static const UsbEndpointDesc usb_serial_ep_out_descriptor =
130 {
131         .bLength = sizeof(usb_serial_ep_in_descriptor),
132         .bDescriptorType = USB_DT_ENDPOINT,
133         .bEndpointAddress = USB_DIR_OUT | USB_SERIAL_EP_OUT,
134         .bmAttributes = USB_ENDPOINT_XFER_BULK,
135         .wMaxPacketSize = usb_cpu_to_le16((uint16_t)64),
136         .bInterval = 0,
137 };
138
139 static const UsbDescHeader *usb_serial_config[] =
140 {
141         (const UsbDescHeader *)&usb_serial_config_descriptor,
142         (const UsbDescHeader *)&usb_serial_interface_descriptor,
143         (const UsbDescHeader *)&usb_serial_ep_report_descriptor,
144         (const UsbDescHeader *)&usb_serial_ep_in_descriptor,
145         (const UsbDescHeader *)&usb_serial_ep_out_descriptor,
146         NULL,
147 };
148
149 static const DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
150 static const DEFINE_USB_STRING(manufacturer_str,
151                 USB_STRING("B", "e", "R", "T", "O", "S"));
152 static const DEFINE_USB_STRING(product_str,
153                 USB_STRING("U", "S", "B", "-", "s", "e", "r", "i", "a", "l"));
154 static const DEFINE_USB_STRING(serial_str,
155                 USB_STRING("0", "0", "1"));
156
157 static const UsbStringDesc *usb_serial_strings[] =
158 {
159         (const UsbStringDesc *)&language_str,
160         (const UsbStringDesc *)&manufacturer_str,
161         (const UsbStringDesc *)&product_str,
162         (const UsbStringDesc *)&serial_str,
163         NULL,
164 };
165
166 /* Global usb-serial descriptor that identifies the usb-serial device */
167 static UsbDevice usb_serial = {
168         .device = &usb_serial_device_descriptor,
169         .config = usb_serial_config,
170         .strings = usb_serial_strings,
171 };
172
173 /* Low-level usb-serial device initialization */
174 static int usb_serial_hw_init(void)
175 {
176 #if CONFIG_KERN
177         MOD_CHECK(proc);
178 #endif
179         if (usb_deviceRegister(&usb_serial) < 0)
180                 return -1;
181         LOG_INFO("usb-serial: registered new USB interface driver\n");
182         return 0;
183 }
184
185 /**
186  * \brief Write a buffer to a usb-serial port.
187  *
188  * \return number of bytes actually written.
189  */
190 static size_t usb_serial_write(struct KFile *fd,
191                         const void *buf, size_t size)
192 {
193         DB(USBSerial *fds = USB_SERIAL_CAST(fd));
194
195         /* Silent compiler warnings if _DEBUG is not enabled */
196         (void)fd;
197         ASSERT(fds->is_open);
198         return usb_endpointWrite(usb_serial_ep_in_descriptor.bEndpointAddress,
199                                 buf, size);
200 }
201
202 /**
203  * Read at most \a size bytes from a usb-serial port and put them in \a buf
204  *
205  * \return number of bytes actually read.
206  */
207 static size_t usb_serial_read(struct KFile *fd, void *buf, size_t size)
208 {
209         DB(USBSerial *fds = USB_SERIAL_CAST(fd));
210
211         /* Silent compiler warnings if _DEBUG is not enabled */
212         (void)fd;
213         ASSERT(fds->is_open);
214         return usb_endpointRead(usb_serial_ep_out_descriptor.bEndpointAddress,
215                                 buf, size);
216 }
217
218 /**
219  * Return the status of a usb-serial port.
220  *
221  * \todo properly implement usb-serial error handling.
222  */
223 static int usb_serial_error(struct KFile *fd)
224 {
225         USBSerial *fds = USB_SERIAL_CAST(fd);
226         return fds->status;
227 }
228
229 /**
230  * Clear the status of a usb-serial port.
231  *
232  * \todo properly implement usb-serial error handling.
233  */
234 static void usb_serial_clearerr(struct KFile *fd)
235 {
236         USBSerial *fds = USB_SERIAL_CAST(fd);
237         fds->status = 0;
238 }
239
240 /**
241  * Close an USB serial port.
242  */
243 static int usb_serial_close(struct KFile *fd)
244 {
245         DB(USBSerial *fds = USB_SERIAL_CAST(fd));
246
247         /* Silent compiler warnings if _DEBUG is not enabled */
248         (void)fd;
249         ASSERT(fds->is_open);
250         DB(fds->is_open = false);
251         return 0;
252 }
253
254 /**
255  * Initialize an USB serial port.
256  *
257  * \param fds KFile Serial struct interface.
258  * \param unit Serial unit to open.
259  */
260 static int usb_serial_open(struct USBSerial *fds, int unit)
261 {
262         unit = unit;
263         ASSERT(!fds->is_open);
264         /* TODO: only a single usb-serial unit is supported for now */
265         ASSERT(unit == 0);
266
267         /* Initialize usb-serial driver */
268         if (usb_serial_hw_init() < 0)
269                 return -1;
270         /* Clear error flags */
271         fds->status = 0;
272         DB(fds->is_open = true);
273
274         return 0;
275 }
276
277 /**
278  * Reopen a usb-serial port.
279  */
280 static struct KFile *usb_serial_reopen(struct KFile *fd)
281 {
282         USBSerial *fds = USB_SERIAL_CAST(fd);
283
284         usb_serial_close(fd);
285         usb_serial_open(fds, fds->unit);
286         return 0;
287 }
288
289 /**
290  * Init serial driver for a usb-serial port \a unit.
291  *
292  * \return 0 if OK, a negative value in case of error.
293  */
294 int usbser_init(struct USBSerial *fds, int unit)
295 {
296         memset(fds, 0, sizeof(*fds));
297
298         DB(fds->fd._type = KFT_USB_SERIAL);
299         fds->fd.reopen = usb_serial_reopen;
300         fds->fd.close = usb_serial_close;
301         fds->fd.read = usb_serial_read;
302         fds->fd.write = usb_serial_write;
303         /* TODO: properly implement error handling. */
304         fds->fd.error = usb_serial_error;
305         fds->fd.clearerr = usb_serial_clearerr;
306
307         return usb_serial_open(fds, unit);
308 }