usb-serial: export usb-serial interface via KFile
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 20 Sep 2010 15:27:37 +0000 (15:27 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 20 Sep 2010 15:27:37 +0000 (15:27 +0000)
TODO:
 - properly implement error handling
 - support more distinct usb-serial channels

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4243 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/drv/usb_serial.c
bertos/drv/usb_serial.h

index e3054bbd9b97490ba21fbae279157c40b5f56691..cdc4b63ff8b71272bfd890fbfe6f5e55f574ddf5 100644 (file)
@@ -150,11 +150,11 @@ static usb_descriptor_header_t *usb_serial_config[] =
 
 static DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
 static DEFINE_USB_STRING(manufacturer_str,
-                       USB_STRING("B", "e", "R", "T", "O", "S"));
+               USB_STRING("B", "e", "R", "T", "O", "S"));
 static DEFINE_USB_STRING(product_str,
-                       USB_STRING("U", "S", "B", "-", "s", "e", "r", "i", "a", "l"));
+               USB_STRING("U", "S", "B", "-", "s", "e", "r", "i", "a", "l"));
 static DEFINE_USB_STRING(serial_str,
-                       USB_STRING("0", "0", "1"));
+               USB_STRING("0", "0", "1"));
 
 static usb_string_descriptor_t *usb_serial_strings[] =
 {
@@ -165,31 +165,146 @@ static usb_string_descriptor_t *usb_serial_strings[] =
        NULL,
 };
 
+/* Global usb-serial descriptor that identifies the usb-serial device */
 static struct usb_device usb_serial = {
        .device = &usb_serial_device_descriptor,
        .config = usb_serial_config,
        .strings = usb_serial_strings,
 };
 
-ssize_t usb_serial_read(void *buffer, ssize_t size)
+/* Low-level usb-serial device initialization */
+static int usb_serial_hw_init(void)
 {
-       return usb_ep_read(usb_serial_ep_out_descriptor.bEndpointAddress,
-                               buffer, size);
+#if CONFIG_KERN
+       MOD_CHECK(proc);
+#endif
+       if (usb_device_register(&usb_serial) < 0)
+               return -1;
+       LOG_INFO("usb-serial: registered new USB interface driver\n");
+       return 0;
 }
 
-ssize_t usb_serial_write(const void *buffer, ssize_t size)
+/**
+ * \brief Write a buffer to a usb-serial port.
+ *
+ * \return number of bytes actually written.
+ */
+static size_t usb_serial_write(struct KFile *fd,
+                       const void *buf, size_t size)
 {
+       DB(USBSerial *fds = USB_SERIAL_CAST(fd));
+
+       /* Silent compiler warnings if _DEBUG is not enabled */
+       (void)fd;
+       ASSERT(fds->is_open);
        return usb_ep_write(usb_serial_ep_in_descriptor.bEndpointAddress,
-                               buffer, size);
+                               buf, size);
 }
 
-int usb_serial_init(void)
+/**
+ * Read at most \a size bytes from a usb-serial port and put them in \a buf
+ *
+ * \return number of bytes actually read.
+ */
+static size_t usb_serial_read(struct KFile *fd, void *buf, size_t size)
 {
-#if CONFIG_KERN
-       MOD_CHECK(proc);
-#endif
-       if (usb_device_register(&usb_serial) < 0)
+       DB(USBSerial *fds = USB_SERIAL_CAST(fd));
+
+       /* Silent compiler warnings if _DEBUG is not enabled */
+       (void)fd;
+       ASSERT(fds->is_open);
+       return usb_ep_read(usb_serial_ep_out_descriptor.bEndpointAddress,
+                               buf, size);
+}
+
+/**
+ * Return the status of a usb-serial port.
+ *
+ * \todo properly implement usb-serial error handling.
+ */
+static int usb_serial_error(struct KFile *fd)
+{
+       USBSerial *fds = USB_SERIAL_CAST(fd);
+       return fds->status;
+}
+
+/**
+ * Clear the status of a usb-serial port.
+ *
+ * \todo properly implement usb-serial error handling.
+ */
+static void usb_serial_clearerr(struct KFile *fd)
+{
+       USBSerial *fds = USB_SERIAL_CAST(fd);
+       fds->status = 0;
+}
+
+/**
+ * Close an USB serial port.
+ */
+static int usb_serial_close(struct KFile *fd)
+{
+       DB(USBSerial *fds = USB_SERIAL_CAST(fd));
+
+       /* Silent compiler warnings if _DEBUG is not enabled */
+       (void)fd;
+       ASSERT(fds->is_open);
+       DB(fds->is_open = false);
+       return 0;
+}
+
+/**
+ * Initialize an USB serial port.
+ *
+ * \param fd KFile Serial struct interface.
+ * \param unit Serial unit to open.
+ */
+static int usb_serial_open(struct USBSerial *fds, int unit)
+{
+       unit = unit;
+       ASSERT(!fds->is_open);
+       /* TODO: only a single usb-serial unit is supported for now */
+       ASSERT(unit == 0);
+
+       /* Initialize usb-serial driver */
+       if (usb_serial_hw_init() < 0)
                return -1;
-       LOG_INFO("usb-serial: registered new USB interface driver\n");
+       /* Clear error flags */
+       fds->status = 0;
+       DB(fds->is_open = true);
+
+       return 0;
+}
+
+/**
+ * Reopen a usb-serial port.
+ */
+static struct KFile *usb_serial_reopen(struct KFile *fd)
+{
+       USBSerial *fds = USB_SERIAL_CAST(fd);
+
+       usb_serial_close(fd);
+       usb_serial_open(fds, fds->unit);
        return 0;
 }
+
+/**
+ * Init serial driver for a usb-serial port \a unit.
+ *
+ * \return 0 if OK, a negative value in case of error.
+ */
+int usb_serial_init(struct USBSerial *fds, int unit)
+{
+       memset(fds, 0, sizeof(*fds));
+
+       DB(fds->fd._type = KFT_USB_SERIAL);
+       fds->fd.reopen = usb_serial_reopen;
+       fds->fd.close = usb_serial_close;
+       fds->fd.read = usb_serial_read;
+       fds->fd.write = usb_serial_write;
+       /* TODO: properly implement error handling. */
+       fds->fd.error = usb_serial_error;
+       fds->fd.clearerr = usb_serial_clearerr;
+
+       return usb_serial_open(fds, unit);
+}
index d27f7a98d92163db1c8a70ef75d341b9b14f3246..0406cebfca0865bf70e631fece9c89b30a780857 100644 (file)
 #ifndef USB_SERIAL_H
 #define USB_SERIAL_H
 
-ssize_t usb_serial_read(void *buf, ssize_t size);
-ssize_t usb_serial_write(const void *buf, ssize_t size);
+#include <io/kfile.h>
 
-int usb_serial_init(void);
+typedef uint32_t usbser_status_t;
+
+typedef struct USBSerial
+{
+        /** KFile structure implementation **/
+        KFile fd;
+        /** Logical port number */
+        unsigned int unit;
+#ifdef _DEBUG
+       /** Used for debugging only */
+        bool is_open;
+#endif
+        /** Holds the status flags. Set to 0 when no errors have occurred. */
+        usbser_status_t status;
+} USBSerial;
+
+/**
+ * ID for usb-serial.
+ */
+#define KFT_USB_SERIAL MAKE_ID('U', 'S', 'B', 'S')
+
+INLINE USBSerial *USB_SERIAL_CAST(KFile *fd)
+{
+        ASSERT(fd->_type == KFT_USB_SERIAL);
+        return (USBSerial *)fd;
+}
+
+int usb_serial_init(struct USBSerial *fds, int unit);
 
 #endif /* USB_SERIAL_H */