summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/usb/usbserial.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/usb/usbserial.c')
-rw-r--r--cfe/cfe/usb/usbserial.c713
1 files changed, 713 insertions, 0 deletions
diff --git a/cfe/cfe/usb/usbserial.c b/cfe/cfe/usb/usbserial.c
new file mode 100644
index 0000000..737d8b4
--- /dev/null
+++ b/cfe/cfe/usb/usbserial.c
@@ -0,0 +1,713 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Serial Port Driver File: usbserial.c
+ *
+ * This device can talk to a few of those usb->serial converters
+ * out there.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_console.h"
+#include "bsp_config.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define USER_FIFOSIZE 256
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbser_linedata_s {
+ uint8_t dLineDataBaud0,dLineDataBaud1,dLineDataBaud2,dLineDataBaud3;
+ uint8_t bLineDataStopBits; /* 0=1, 1=1.5, 2=2 */
+ uint8_t bLineDataParity; /* 0=none, 1=odd, 2=even, 3=mark, 4=space */
+ uint8_t bLineDataBits; /* 5,6,7,8 */
+} usbser_linedata_t;
+
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define GETDWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \
+ ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24))
+#define PUTDWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \
+ (s)->f##1 = ((v)>>8 & 0xFF); \
+ (s)->f##2 = ((v)>>16 & 0xFF); \
+ (s)->f##3 = ((v)>>24 & 0xFF);
+
+
+
+/* *********************************************************************
+ * Forward Definitions
+ ********************************************************************* */
+
+static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv);
+static int usbserial_detach(usbdev_t *dev);
+
+#ifdef _CFE_
+static void usb_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int usb_uart_open(cfe_devctx_t *ctx);
+static int usb_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int usb_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t usb_uart_dispatch = {
+ usb_uart_open,
+ usb_uart_read,
+ usb_uart_inpstat,
+ usb_uart_write,
+ usb_uart_ioctl,
+ usb_uart_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t usb_uart = {
+ "USB UART",
+ "uart",
+ CFE_DEV_SERIAL,
+ &usb_uart_dispatch,
+ usb_uart_probe
+};
+
+typedef struct usb_uart_s {
+ int uart_unit;
+ int uart_speed;
+ int uart_flowcontrol;
+} usb_uart_t;
+
+#define USBUART_MAXUNITS 4
+static usbdev_t *usbuart_units[USBUART_MAXUNITS];
+#endif
+
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbserial_softc_s {
+ int user_inpipe;
+ int user_outpipe;
+ int user_outmps;
+ int user_intpipe;
+ uint8_t user_inbuf[USER_FIFOSIZE];
+ int user_inbuf_in;
+ int user_inbuf_out;
+ uint8_t *user_devinbuf;
+ int user_devinbufsize;
+ int user_unit;
+ uint8_t *user_intbuf;
+ usbser_linedata_t user_linedata;
+} usbserial_softc_t;
+
+usb_driver_t usbserial_driver = {
+ "USB Serial Port",
+ usbserial_attach,
+ usbserial_detach
+};
+
+usbdev_t *usbserial_dev = NULL;
+
+
+#if 0
+/* *********************************************************************
+ * usbserial_get_linedata(dev,linedata)
+ *
+ * Request line data from the device.
+ *
+ * Input parameters:
+ * dev - USB device
+ * linedata - pointer to structure
+ *
+ * Return value:
+ * # of bytes returned
+ * <0 if error
+ ********************************************************************* */
+
+static int usbserial_get_linedata(usbdev_t *dev,usbser_linedata_t *ldata)
+{
+ uint8_t *respbuf;
+ int res;
+
+ respbuf = KMALLOC(32,0);
+
+ res = usb_std_request(dev,0xA1,0x21,0,0,respbuf,sizeof(usbser_linedata_t));
+
+ KFREE(respbuf);
+
+ if ((res >= 0) && ldata) memcpy(ldata,respbuf,sizeof(usbser_linedata_t));
+
+ return res;
+}
+#endif
+
+/* *********************************************************************
+ * usbserial_set_linedata(dev,linedata)
+ *
+ * Set line data to the device.
+ *
+ * Input parameters:
+ * dev - USB device
+ * linedata - pointer to structure
+ *
+ * Return value:
+ * # of bytes returned
+ * <0 if error
+ ********************************************************************* */
+
+static int usbserial_set_linedata(usbdev_t *dev,usbser_linedata_t *ldata)
+{
+ int res;
+
+ /*
+ * Send request to device.
+ */
+
+ res = usb_std_request(dev,0x21,0x20,0,0,(uint8_t *) ldata,sizeof(usbser_linedata_t));
+
+ return res;
+}
+
+#if 0
+/* *********************************************************************
+ * usbserial_song_and_dance(usbdev_t *dev)
+ *
+ * Magic incantations from using the CATC on this device.
+ *
+ * Input parameters:
+ * dev
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_song_and_dance(usbdev_t *dev)
+{
+ int res;
+ char databuf[1];
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0404,0,NULL,0); /* WRITE */
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0404,1,NULL,0); /* WRITE */
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0,1, NULL,0); /* WRITE */
+ res = usb_std_request(dev,0x40,0x01,0x1,0xC0,NULL,0); /* WRITE */
+ res = usb_std_request(dev,0x40,0x01,0x2,4, NULL,0); /* WRITE */
+
+ return 0;
+}
+#endif
+
+/* *********************************************************************
+ * usbserial_tx_data(dev,buffer,len)
+ *
+ * Synchronously transmit data via the USB.
+ *
+ * Input parameters:
+ * dev - device pointer
+ * buffer,len - data we want to send
+ *
+ * Return value:
+ * number of bytes sent.
+ ********************************************************************* */
+
+static int usbserial_tx_data(usbdev_t *dev,uint8_t *buffer,int len)
+{
+ uint8_t *bptr;
+ usbreq_t *ur;
+ usbserial_softc_t *softc = (dev->ud_private);
+ int res;
+
+ bptr = KMALLOC(len,0);
+
+ memcpy(bptr,buffer,len);
+
+ ur = usb_make_request(dev,softc->user_outpipe,bptr,len,UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+
+// printf("Data sent, status=%d, xferred=%d\n",res,ur->ur_xferred);
+
+ res = ur->ur_xferred;
+
+ usb_free_request(ur);
+
+ KFREE(bptr);
+
+ return res;
+}
+
+/* *********************************************************************
+ * usbserial_int_callback(ur)
+ *
+ * Callback routine for the interrupt request, for devices
+ * that have an interrupt pipe. We ignore this.
+ *
+ * Input parameters:
+ * ur - usb request
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static int usbserial_int_callback(usbreq_t *ur)
+{
+// int idx;
+
+ /*
+ * Check to see if the request was cancelled by someone
+ * deleting our endpoint.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+// printf("serial int msg: ");
+// for (idx = 0; idx < ur->ur_xferred; idx++) printf("%02X ",ur->ur_buffer[idx]);
+// printf("\n");
+
+ usb_queue_request(ur);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * usbserial_rx_callback(ur)
+ *
+ * Callback routine for the regular data pipe.
+ *
+ * Input parameters:
+ * ur - usb request
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static int usbserial_rx_callback(usbreq_t *ur)
+{
+ int idx;
+ int iptr;
+ usbserial_softc_t *user = (ur->ur_dev->ud_private);
+
+ /*
+ * Check to see if the request was cancelled by someone
+ * deleting our endpoint.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+ /*
+ * Add characters to the receive fifo
+ */
+
+ for (idx = 0; idx < ur->ur_xferred; idx++) {
+ iptr = (user->user_inbuf_in + 1) & (USER_FIFOSIZE-1);
+ if (iptr == user->user_inbuf_out) break; /* overflow */
+ user->user_inbuf[user->user_inbuf_in] = ur->ur_buffer[idx];
+ user->user_inbuf_in = iptr;
+ }
+
+ /*
+ * Requeue the request
+ */
+
+ usb_queue_request(ur);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * usbserial_attach(dev,drv)
+ *
+ * This routine is called when the bus scan stuff finds a mass-storage
+ * device. We finish up the initialization by configuring the
+ * device and allocating our softc here.
+ *
+ * Input parameters:
+ * dev - usb device, in the "addressed" state.
+ * drv - the driver table entry that matched
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
+ usb_endpoint_descr_t *epdscr;
+ usb_endpoint_descr_t *indscr = NULL;
+ usb_endpoint_descr_t *outdscr = NULL;
+ usb_endpoint_descr_t *intdscr = NULL;
+ usb_interface_descr_t *ifdscr;
+ usbser_linedata_t *ldata;
+ usbserial_softc_t *softc;
+ usbreq_t *ur;
+ int idx;
+
+ dev->ud_drv = drv;
+
+ softc = KMALLOC(sizeof(usbserial_softc_t),0);
+ memset(softc,0,sizeof(usbserial_softc_t));
+ dev->ud_private = softc;
+
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+ if (ifdscr == NULL) {
+ printf("Could not get interface descriptor\n");
+ return -1;
+ }
+
+ for (idx = 0; idx < ifdscr->bNumEndpoints; idx++) {
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx);
+
+ if ((epdscr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
+ USB_ENDPOINT_TYPE_INTERRUPT) {
+ intdscr = epdscr;
+ }
+ else if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) {
+ outdscr = epdscr;
+ }
+ else {
+ indscr = epdscr;
+ }
+ }
+
+
+ if (!indscr || !outdscr) {
+ printf("IN or OUT endpoint descriptors are missing\n");
+ /*
+ * Could not get descriptors, something is very wrong.
+ * Leave device addressed but not configured.
+ */
+ return 0;
+ }
+
+ /*
+ * Choose the standard configuration.
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ /*
+ * Open the pipes.
+ */
+
+ softc->user_inpipe = usb_open_pipe(dev,indscr);
+ softc->user_devinbufsize = GETUSBFIELD(indscr,wMaxPacketSize);
+ softc->user_devinbuf = KMALLOC(softc->user_devinbufsize,0);
+ softc->user_outpipe = usb_open_pipe(dev,outdscr);
+ softc->user_outmps = GETUSBFIELD(outdscr,wMaxPacketSize);
+ if (intdscr) {
+ softc->user_intpipe = usb_open_pipe(dev,intdscr);
+ }
+ else {
+ softc->user_intpipe = -1;
+ }
+
+ ur = usb_make_request(dev,softc->user_inpipe,softc->user_devinbuf,
+ softc->user_devinbufsize,
+ UR_FLAG_IN | UR_FLAG_SHORTOK);
+ ur->ur_callback = usbserial_rx_callback;
+ usb_queue_request(ur);
+
+
+ if (softc->user_intpipe) {
+ softc->user_intbuf = KMALLOC(32,0);
+ ur = usb_make_request(dev,softc->user_intpipe,softc->user_intbuf,
+ GETUSBFIELD(intdscr,wMaxPacketSize),
+ UR_FLAG_IN | UR_FLAG_SHORTOK);
+ ur->ur_callback = usbserial_int_callback;
+ usb_queue_request(ur);
+ }
+
+#ifdef _CFE_
+ softc->user_unit = -1;
+ for (idx = 0; idx < USBUART_MAXUNITS; idx++) {
+ if (usbuart_units[idx] == NULL) {
+ softc->user_unit = idx;
+ usbuart_units[idx] = dev;
+ break;
+ }
+ }
+
+ console_log("USBSERIAL: Unit %d connected",softc->user_unit);
+#endif
+
+// usbserial_song_and_dance(dev);
+
+ ldata = &(softc->user_linedata);
+ PUTDWFIELD(ldata,dLineDataBaud,115200);
+ ldata->bLineDataStopBits = 0;
+ ldata->bLineDataParity = 2;
+ ldata->bLineDataBits = 8;
+
+ usbserial_set_linedata(dev,ldata);
+// usbserial_get_linedata(dev,NULL);
+
+ usbserial_dev = dev;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbserial_detach(dev)
+ *
+ * This routine is called when the bus scanner notices that
+ * this device has been removed from the system. We should
+ * do any cleanup that is required. The pending requests
+ * will be cancelled automagically.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_detach(usbdev_t *dev)
+{
+ usbserial_softc_t *softc;
+
+ softc = dev->ud_private;
+
+
+#ifdef _CFE_
+ console_log("USBSERIAL: USB unit %d disconnected",softc->user_unit);
+ if (softc->user_unit >= 0) usbuart_units[softc->user_unit] = NULL;
+#endif
+
+ if (softc) {
+ if (softc->user_devinbuf) KFREE(softc->user_devinbuf);
+ if (softc->user_intbuf) KFREE(softc->user_intbuf);
+ KFREE(softc);
+ }
+
+ return 0;
+}
+
+
+
+#ifdef _CFE_
+
+
+
+static void usb_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ usb_uart_t *softc;
+ char descr[80];
+
+ softc = (usb_uart_t *) KMALLOC(sizeof(usb_uart_t),0);
+
+ memset(softc,0,sizeof(usb_uart_t));
+
+ softc->uart_unit = (int)probe_a;
+
+ xsprintf(descr,"USB UART unit %d",(int)probe_a);
+
+ cfe_attach(drv,softc,NULL,descr);
+}
+
+
+static int usb_uart_open(cfe_devctx_t *ctx)
+{
+// usb_uart_t *softc = ctx->dev_softc;
+// int baudrate = CFG_SERIAL_BAUD_RATE;
+// usbdev_t *dev = usbuart_units[softc->uart_unit];
+
+ /*
+ * XXX call the uart setup here
+ */
+
+ return 0;
+}
+
+static int usb_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+ unsigned char *bptr;
+ int blen;
+
+ if (!dev) return 0;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ while ((blen > 0) && (user->user_inbuf_out != user->user_inbuf_in)) {
+ *bptr++ = user->user_inbuf[user->user_inbuf_out];
+ user->user_inbuf_out = (user->user_inbuf_out + 1) & (USER_FIFOSIZE-1);
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+static int usb_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+
+ inpstat->inp_status = 0;
+
+ if (!dev) return 0;
+
+ inpstat->inp_status = (user->user_inbuf_in != user->user_inbuf_out);
+
+ return 0;
+}
+
+static int usb_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ if (!dev) {
+ buffer->buf_retlen = blen;
+ return 0;
+ }
+
+ if (blen > user->user_outmps) blen = user->user_outmps;
+
+ usbserial_tx_data(dev,bptr,blen);
+
+ buffer->buf_retlen = blen;
+ return 0;
+}
+
+static int usb_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+// usbserial_softc_t *user = dev->ud_private;
+
+ if (!dev) return -1;
+
+ unsigned int *info = (unsigned int *) buffer->buf_ptr;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_SERIAL_GETSPEED:
+ *info = softc->uart_speed;
+ break;
+ case IOCTL_SERIAL_SETSPEED:
+ softc->uart_speed = *info;
+ /* NYI */
+ break;
+ case IOCTL_SERIAL_GETFLOW:
+ *info = softc->uart_flowcontrol;
+ break;
+ case IOCTL_SERIAL_SETFLOW:
+ softc->uart_flowcontrol = *info;
+ /* NYI */
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int usb_uart_close(cfe_devctx_t *ctx)
+{
+// usb_uart_t *softc = ctx->dev_softc;
+
+ return 0;
+}
+
+
+
+#endif
+