1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * This driver supports FTDI FT232R USB-to-serial adapters. It is a
  29  * device-specific driver (DSD) working with the USB generic serial
  30  * driver (GSD) usbser.
  31  *
  32  * It implements the USB-to-serial device-specific driver interface (DSDI)
  33  * which is exported by GSD. The DSDI is defined by ds_ops_t structure.
  34  *
  35  * Also may work with the older FTDI 8U232AM devices.
  36  */
  37 
  38 #include <sys/types.h>
  39 #include <sys/param.h>
  40 #include <sys/stream.h>
  41 #include <sys/conf.h>
  42 #include <sys/ddi.h>
  43 #include <sys/sunddi.h>
  44 
  45 #include <sys/usb/clients/usbser/usbser.h>
  46 #include <sys/usb/clients/usbser/usbftdi/uftdi_var.h>
  47 
  48 static void *usbser_uftdi_statep;       /* soft state handle for usbser */
  49 
  50 extern ds_ops_t uftdi_ds_ops;   /* DSD operations */
  51 
  52 static int
  53 usbser_uftdi_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
  54     void **result)
  55 {
  56         return (usbser_getinfo(dip, infocmd, arg, result, usbser_uftdi_statep));
  57 }
  58 
  59 
  60 static int
  61 usbser_uftdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
  62 {
  63         return (usbser_attach(dip, cmd, usbser_uftdi_statep, &uftdi_ds_ops));
  64 }
  65 
  66 
  67 static int
  68 usbser_uftdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
  69 {
  70         return (usbser_detach(dip, cmd, usbser_uftdi_statep));
  71 }
  72 
  73 
  74 static int
  75 usbser_uftdi_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
  76 {
  77         return (usbser_open(rq, dev, flag, sflag, cr, usbser_uftdi_statep));
  78 }
  79 
  80 /*
  81  * Several linked data structures to tie it together ..
  82  */
  83 struct module_info uftdi_modinfo = {
  84         0,                      /* module id */
  85         "uftdi",                /* module name */
  86         USBSER_MIN_PKTSZ,       /* min pkt size */
  87         USBSER_MAX_PKTSZ,       /* max pkt size */
  88         USBSER_HIWAT,           /* hi watermark */
  89         USBSER_LOWAT            /* low watermark */
  90 };
  91 
  92 static struct qinit uftdi_rinit = {
  93         putq,
  94         usbser_rsrv,
  95         usbser_uftdi_open,
  96         usbser_close,
  97         NULL,
  98         &uftdi_modinfo,
  99 };
 100 
 101 static struct qinit uftdi_winit = {
 102         usbser_wput,
 103         usbser_wsrv,
 104         NULL,
 105         NULL,
 106         NULL,
 107         &uftdi_modinfo,
 108 };
 109 
 110 static struct streamtab uftdi_str_info = {
 111         &uftdi_rinit,
 112         &uftdi_winit,
 113 };
 114 
 115 static struct cb_ops uftdi_cb_ops = {
 116         nodev,                  /* cb_open */
 117         nodev,                  /* cb_close */
 118         nodev,                  /* cb_strategy */
 119         nodev,                  /* cb_print */
 120         nodev,                  /* cb_dump */
 121         nodev,                  /* cb_read */
 122         nodev,                  /* cb_write */
 123         nodev,                  /* cb_ioctl */
 124         nodev,                  /* cb_devmap */
 125         nodev,                  /* cb_mmap */
 126         nodev,                  /* cb_segmap */
 127         nochpoll,               /* cb_chpoll */
 128         ddi_prop_op,            /* cb_prop_op */
 129         &uftdi_str_info,    /* cb_stream */
 130         (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG)       /* cb_flag */
 131 };
 132 
 133 static struct dev_ops uftdi_ops = {
 134         DEVO_REV,               /* devo_rev */
 135         0,                      /* devo_refcnt */
 136         usbser_uftdi_getinfo,
 137         nulldev,                /* devo_identify */
 138         nulldev,                /* devo_probe */
 139         usbser_uftdi_attach,
 140         usbser_uftdi_detach,
 141         nodev,                  /* devo_reset */
 142         &uftdi_cb_ops,
 143         (struct bus_ops *)NULL, /* devo_bus_ops */
 144         usbser_power,           /* devo_power */
 145         ddi_quiesce_not_needed
 146 };
 147 
 148 static struct modldrv modldrv = {
 149         &mod_driverops,
 150         "FTDI FT232R USB UART driver",
 151         &uftdi_ops,
 152 };
 153 
 154 static struct modlinkage modlinkage = {
 155         MODREV_1,
 156         &modldrv
 157 };
 158 
 159 int
 160 _init(void)
 161 {
 162         int error;
 163 
 164         if ((error = mod_install(&modlinkage)) != 0)
 165                 return (error);
 166         if ((error = ddi_soft_state_init(&usbser_uftdi_statep,
 167             usbser_soft_state_size(), 1)) != 0)
 168                 (void) mod_remove(&modlinkage);
 169         return (error);
 170 }
 171 
 172 
 173 int
 174 _fini(void)
 175 {
 176         int error;
 177 
 178         if ((error = mod_remove(&modlinkage)) == 0)
 179                 ddi_soft_state_fini(&usbser_uftdi_statep);
 180         return (error);
 181 }
 182 
 183 
 184 int
 185 _info(struct modinfo *modinfop)
 186 {
 187         return (mod_info(&modlinkage, modinfop));
 188 }