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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 /*
  29  * This driver includes code for Keyspan USA49WG/USA49WLC/USA19HS adapters. It
  30  * is a device-specific driver (DSD) working with USB generic serial driver
  31  * (GSD). It implements the USB-to-serial device-specific driver interface
  32  * (DSDI) which is offered by GSD. The interface is defined by ds_ops_t
  33  * structure.
  34  *
  35  * For USA49WLC, it's necessary to download firmware every time the device is
  36  * plugged. Before the firmware is downloaded, we say that the device is in
  37  * "firmware mode", and the attach routin is keyspan_pre_attach(). After
  38  * downloading, the device's product id will change to 0x12a. Then the device
  39  * will be enumerated again and another attach for the new product id will
  40  * begin. No firmware is included in the driver. The functions of USA49WLC is
  41  * disabled.
  42  *
  43  * For USA49WG and USA19HS, no need to download firmware since it can be kept
  44  * in the device's memory.
  45  *
  46  * For USA49WLC and USA19HS, it's necessary to check and switch their
  47  * configrations at the beginning of attach, since each of them has two
  48  * configrations. This driver uses the one whose endpoints are all bulk.
  49  *
  50  * For USA49WG, this driver uses the third configuration which has 6 endpoints,
  51  * 3 bulk out eps, 1 bulk in ep, 1 intr in ep, 1 intr out ep. Bulk in ep is
  52  * shared by 4 ports for receiving data.
  53  *
  54  * Some of Keyspan adapters have only one port, some have two or four ports.
  55  * This driver supports up to four ports. Each port has its own states (traced
  56  * by keyspan_port structure) and can be operated independently.
  57  *
  58  * port_state:
  59  *
  60  *   KEYSPAN_PORT_NOT_INIT
  61  *          |
  62  *          |
  63  *     attach_ports
  64  *          |
  65  *          |
  66  *          |
  67  *          v
  68  *   KEYSPAN_PORT_CLOSED <-----close-------<---- +
  69  *      |                                        |
  70  *      |                                        |
  71  *      |                                        |
  72  *  open_port                                    |
  73  *      |                                        |
  74  *      |                                        |
  75  *      v                                        |
  76  * KEYSPAN_PORT_OPENING ---open_hw_port---> USBSER_PORT_OPEN
  77  *
  78  * Each port has its own data in/out pipes and each pipe also has its own states
  79  * (traced by keyspan_pipe structure). The pipe states is as following:
  80  *
  81  * pipe_state:
  82  *
  83  *        KEYSPAN_PIPE_NOT_INIT
  84  *              |       ^
  85  *              |       |
  86  * keyspan_init_pipes  keyspan_fini_pipes
  87  *              |       |
  88  *              v       |
  89  *         KEYSPAN_PIPE_CLOSED ------------->-----------+
  90  *                ^                                     |
  91  *                |                       reconnect/resume/open_port
  92  *                |                                     |
  93  *    disconnect/suspend/close_port                     |
  94  *                |                                     v
  95  *                +---------<------------------ KEYSPAN_PIPE_OPEN
  96  *
  97  * To control the device and get its status in a timely way, this driver makes
  98  * use of two global bulk endpoints for cmd and status on the device. The pipes
  99  * for cmd/status will be opened during attach. For multi-port devices, one of
 100  * the cmd/status message fields will designate which port this message is for.
 101  *
 102  * This driver can be easily extended to support more Keyspan adapter models.
 103  * You need the following steps to reach the aim:
 104  * 1. Add the model specific data structures, like cmd/status message structure.
 105  * 2. If the device need firmware downloaded, add the firmware code as a header
 106  * file, and add code to keyspan_pre_attach() as what were done for USA49WLC.
 107  * 3. Add several model specific functions, like keyspan_build_cmd_msg_*,
 108  * keyspan_default_port_params_*, keyspan_save_port_params_*, etc. The functions
 109  * for USA19HS and USA49WLC can be taken as examples.
 110  * 4. Add model specific code to the "switch (id_product) {...}" sentences.
 111  */
 112 
 113 /*
 114  *
 115  * keyspan driver glue code
 116  *
 117  */
 118 #include <sys/types.h>
 119 #include <sys/param.h>
 120 #include <sys/stream.h>
 121 #include <sys/conf.h>
 122 #include <sys/ddi.h>
 123 #include <sys/sunddi.h>
 124 
 125 #define USBDRV_MAJOR_VER        2
 126 #define USBDRV_MINOR_VER        0
 127 
 128 #include <sys/usb/usba.h>
 129 
 130 #include <sys/usb/clients/usbser/usbser.h>
 131 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
 132 
 133 #include <sys/byteorder.h>
 134 #include <sys/strsun.h>
 135 
 136 /* configuration entry points */
 137 static int      usbser_keyspan_getinfo(dev_info_t *, ddi_info_cmd_t, void *,
 138                 void **);
 139 static int      usbser_keyspan_attach(dev_info_t *, ddi_attach_cmd_t);
 140 static int      usbser_keyspan_detach(dev_info_t *, ddi_detach_cmd_t);
 141 static int      usbser_keyspan_open(queue_t *, dev_t *, int, int, cred_t *);
 142 
 143 /* functions related with set config or firmware download */
 144 static int      keyspan_pre_attach(dev_info_t *, ddi_attach_cmd_t, void *);
 145 static int      keyspan_set_cfg(dev_info_t *, uint8_t);
 146 static int      keyspan_pre_detach(dev_info_t *, ddi_detach_cmd_t, void *);
 147 static boolean_t keyspan_need_fw(usb_client_dev_data_t *);
 148 static int      keyspan_set_reg(keyspan_pipe_t *, uchar_t);
 149 static int      keyspan_write_memory(keyspan_pipe_t *, uint16_t, uchar_t *,
 150                 uint16_t, uint8_t);
 151 static int      keyspan_download_firmware(keyspan_pre_state_t *);
 152 
 153 static void    *usbser_keyspan_statep;  /* soft state */
 154 
 155 extern ds_ops_t keyspan_ds_ops;         /* DSD operations */
 156 
 157 /*
 158  * STREAMS structures
 159  */
 160 struct module_info usbser_keyspan_modinfo = {
 161         0,                      /* module id */
 162         "usbsksp",              /* module name */
 163         USBSER_MIN_PKTSZ,       /* min pkt size */
 164         USBSER_MAX_PKTSZ,       /* max pkt size */
 165         USBSER_HIWAT,           /* hi watermark */
 166         USBSER_LOWAT            /* low watermark */
 167 };
 168 
 169 static struct qinit usbser_keyspan_rinit = {
 170         putq,
 171         usbser_rsrv,
 172         usbser_keyspan_open,
 173         usbser_close,
 174         NULL,
 175         &usbser_keyspan_modinfo,
 176         NULL
 177 };
 178 
 179 static struct qinit usbser_keyspan_winit = {
 180         usbser_wput,
 181         usbser_wsrv,
 182         NULL,
 183         NULL,
 184         NULL,
 185         &usbser_keyspan_modinfo,
 186         NULL
 187 };
 188 
 189 struct streamtab usbser_keyspan_str_info = {
 190         &usbser_keyspan_rinit, &usbser_keyspan_winit, NULL, NULL
 191 };
 192 
 193 static struct cb_ops usbser_keyspan_cb_ops = {
 194         nodev,                  /* cb_open */
 195         nodev,                  /* cb_close */
 196         nodev,                  /* cb_strategy */
 197         nodev,                  /* cb_print */
 198         nodev,                  /* cb_dump */
 199         nodev,                  /* cb_read */
 200         nodev,                  /* cb_write */
 201         nodev,                  /* cb_ioctl */
 202         nodev,                  /* cb_devmap */
 203         nodev,                  /* cb_mmap */
 204         nodev,                  /* cb_segmap */
 205         nochpoll,               /* cb_chpoll */
 206         ddi_prop_op,            /* cb_prop_op */
 207         &usbser_keyspan_str_info,   /* cb_stream */
 208         (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG)       /* cb_flag */
 209 };
 210 
 211 /*
 212  * auto configuration ops
 213  */
 214 struct dev_ops usbser_keyspan_ops = {
 215         DEVO_REV,               /* devo_rev */
 216         0,                      /* devo_refcnt */
 217         usbser_keyspan_getinfo, /* devo_getinfo */
 218         nulldev,                /* devo_identify */
 219         nulldev,                /* devo_probe */
 220         usbser_keyspan_attach,  /* devo_attach */
 221         usbser_keyspan_detach,  /* devo_detach */
 222         nodev,                  /* devo_reset */
 223         &usbser_keyspan_cb_ops,     /* devo_cb_ops */
 224         (struct bus_ops *)NULL, /* devo_bus_ops */
 225         usbser_power,           /* devo_power */
 226         ddi_quiesce_not_needed,         /* devo_quiesce */
 227 };
 228 
 229 extern struct mod_ops mod_driverops;
 230 
 231 static struct modldrv modldrv = {
 232         &mod_driverops,             /* type of module - driver */
 233         "USB keyspan usb2serial driver",
 234         &usbser_keyspan_ops,
 235 };
 236 
 237 static struct modlinkage modlinkage = {
 238         MODREV_1, { &modldrv, NULL }
 239 };
 240 
 241 /* debug support */
 242 static uint_t   keyspan_pre_errlevel = USB_LOG_L4;
 243 static uint_t   keyspan_pre_errmask = DPRINT_MASK_ALL;
 244 static uint_t   keyspan_pre_instance_debug = (uint_t)-1;
 245 
 246 /* firmware support for usa49wlc model */
 247 extern usbser_keyspan_fw_record_t *keyspan_usa49wlc_fw(void);
 248 #pragma weak keyspan_usa49wlc_fw
 249 
 250 /*
 251  * configuration entry points
 252  * --------------------------
 253  */
 254 int
 255 _init(void)
 256 {
 257         int    error;
 258 
 259         if ((error = mod_install(&modlinkage)) == 0) {
 260                 error = ddi_soft_state_init(&usbser_keyspan_statep,
 261                     max(usbser_soft_state_size(),
 262                     sizeof (keyspan_pre_state_t)), 1);
 263         }
 264 
 265         return (error);
 266 }
 267 
 268 
 269 int
 270 _fini(void)
 271 {
 272         int    error;
 273 
 274         if ((error = mod_remove(&modlinkage)) == 0) {
 275                 ddi_soft_state_fini(&usbser_keyspan_statep);
 276         }
 277 
 278         return (error);
 279 }
 280 
 281 
 282 int
 283 _info(struct modinfo *modinfop)
 284 {
 285         return (mod_info(&modlinkage, modinfop));
 286 }
 287 
 288 
 289 /*ARGSUSED*/
 290 int
 291 usbser_keyspan_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
 292                 void **result)
 293 {
 294         return (usbser_getinfo(dip, infocmd, arg, result,
 295             usbser_keyspan_statep));
 296 }
 297 
 298 
 299 static int
 300 usbser_keyspan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 301 {
 302         int     rval;
 303 
 304         /*
 305          * Once the device is plugged, we need set its cfg. And need download
 306          * firmware for some of them.
 307          */
 308         rval = keyspan_pre_attach(dip, cmd, usbser_keyspan_statep);
 309 
 310         /*
 311          * After the cfg is set, and the firmware is downloaded,
 312          * do the real attach.
 313          */
 314         if (rval == DDI_ECONTEXT) {
 315 
 316                 return (usbser_attach(dip, cmd, usbser_keyspan_statep,
 317                     &keyspan_ds_ops));
 318         } else {
 319 
 320                 return (rval);
 321         }
 322 }
 323 
 324 
 325 static int
 326 usbser_keyspan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 327 {
 328 
 329         if (ddi_get_driver_private(dip) == NULL) {
 330 
 331                 return (keyspan_pre_detach(dip, cmd, usbser_keyspan_statep));
 332         } else {
 333 
 334 
 335                 return (usbser_detach(dip, cmd, usbser_keyspan_statep));
 336 
 337 
 338         }
 339 
 340 }
 341 
 342 
 343 static int
 344 usbser_keyspan_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
 345 {
 346         return (usbser_open(rq, dev, flag, sflag, cr, usbser_keyspan_statep));
 347 }
 348 
 349 /*
 350  * Switch config or download firmware
 351  */
 352 /*ARGSUSED*/
 353 static int
 354 keyspan_pre_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, void *statep)
 355 {
 356 
 357         int                     instance = ddi_get_instance(dip);
 358         keyspan_pre_state_t     *kbp = NULL;
 359         usb_client_dev_data_t   *dev_data = NULL;
 360         int                     rval = DDI_FAILURE;
 361 
 362         switch (cmd) {
 363         case DDI_ATTACH:
 364 
 365                 break;
 366         case DDI_RESUME:
 367 
 368                 return (DDI_SUCCESS);
 369         default:
 370 
 371                 return (DDI_FAILURE);
 372         }
 373 
 374         /* attach driver to USBA */
 375         if (usb_client_attach(dip, USBDRV_VERSION, 0) == USB_SUCCESS) {
 376                 (void) usb_get_dev_data(dip, &dev_data, USB_PARSE_LVL_IF, 0);
 377         }
 378         if (dev_data == NULL) {
 379 
 380                 goto fail;
 381         }
 382 
 383         /*
 384          * If 19HS or 49WG, needn't download firmware, but need check the
 385          * current cfg.
 386          * If 49WLC, need check the current cfg before download fw. And after
 387          * download, the product id will change to KEYSPAN_USA49WLC_PID.
 388          */
 389         if (dev_data->dev_descr->idProduct == KEYSPAN_USA19HS_PID ||
 390             dev_data->dev_descr->idProduct == KEYSPAN_USA49WLC_PID) {
 391                 if (keyspan_set_cfg(dip, 1) == USB_SUCCESS) {
 392                         /* Go to keyspan_attach() by return DDI_ECONTEXT. */
 393                         rval =  DDI_ECONTEXT;
 394                 }
 395 
 396                 goto fail;
 397         } else if (dev_data->dev_descr->idProduct == KEYSPAN_USA49WG_PID) {
 398                 if (keyspan_set_cfg(dip, 2) == USB_SUCCESS) {
 399                         /* Go to keyspan_attach() by return DDI_ECONTEXT. */
 400                         rval =  DDI_ECONTEXT;
 401                 }
 402 
 403                 goto fail;
 404         }
 405 
 406 
 407         /*
 408          * By checking KEYSPAN_FW_FLAG,  we can check whether the firmware
 409          * has been downloaded.
 410          * If firmware is already there, then do normal attach.
 411          */
 412         if (!keyspan_need_fw(dev_data)) {
 413                 /* Go to keyspan_attach() by return DDI_ECONTEXT. */
 414                 rval =  DDI_ECONTEXT;
 415 
 416                 goto fail;
 417         }
 418 
 419         /* Go on to download firmware. */
 420 
 421         if (ddi_soft_state_zalloc(statep, instance) == DDI_SUCCESS) {
 422                 kbp = ddi_get_soft_state(statep, instance);
 423         }
 424         if (kbp) {
 425                 kbp->kb_dip = dip;
 426                 kbp->kb_instance = instance;
 427                 kbp->kb_dev_data = dev_data;
 428                 kbp->kb_def_pipe.pipe_handle = kbp->kb_dev_data->dev_default_ph;
 429                 kbp->kb_lh = usb_alloc_log_hdl(kbp->kb_dip, "keyspan[*].",
 430                     &keyspan_pre_errlevel, &keyspan_pre_errmask,
 431                     &keyspan_pre_instance_debug, 0);
 432 
 433                 kbp->kb_def_pipe.pipe_lh = kbp->kb_lh;
 434 
 435                 if (keyspan_download_firmware(kbp) == USB_SUCCESS) {
 436                         USB_DPRINTF_L4(DPRINT_ATTACH, kbp->kb_lh,
 437                             "keyspan_pre_attach: completed.");
 438 
 439                         /* keyspan download firmware done. */
 440 
 441                         return (DDI_SUCCESS);
 442                 }
 443         }
 444 fail:
 445         if (kbp) {
 446                 usb_free_log_hdl(kbp->kb_lh);
 447                 ddi_soft_state_free(statep, instance);
 448         }
 449         usb_client_detach(dip, dev_data);
 450 
 451         return (rval);
 452 }
 453 
 454 
 455 static int
 456 keyspan_pre_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, void *statep)
 457 {
 458         int             instance = ddi_get_instance(dip);
 459         keyspan_pre_state_t     *kbp;
 460 
 461         kbp = ddi_get_soft_state(statep, instance);
 462 
 463         switch (cmd) {
 464         case DDI_DETACH:
 465 
 466                 break;
 467         case DDI_SUSPEND:
 468 
 469                 return (DDI_SUCCESS);
 470         default:
 471 
 472                 return (DDI_FAILURE);
 473         }
 474 
 475         usb_free_log_hdl(kbp->kb_lh);
 476         usb_client_detach(dip, kbp->kb_dev_data);
 477         ddi_soft_state_free(statep, instance);
 478 
 479         return (DDI_SUCCESS);
 480 }
 481 
 482 
 483 /* Set cfg for the device which has more than one cfg */
 484 static int
 485 keyspan_set_cfg(dev_info_t *dip, uint8_t cfg_num)
 486 {
 487 
 488         if (usb_set_cfg(dip, cfg_num, USB_FLAGS_SLEEP,
 489             NULL, NULL) != USB_SUCCESS) {
 490 
 491                 return (USB_FAILURE);
 492         }
 493 
 494         return (USB_SUCCESS);
 495 }
 496 
 497 
 498 /* Return TRUE if need download firmware to the device. */
 499 static boolean_t
 500 keyspan_need_fw(usb_client_dev_data_t *dev_data)
 501 {
 502         uint16_t        bcd_descr;
 503         uint16_t        bcd_descr_change;
 504 
 505         /* need to convert to Little-Endian */
 506         bcd_descr = dev_data->dev_descr->bcdDevice;
 507 
 508         /*
 509          * According to Keyspan's interface spec, this flag indicates
 510          * if need download fw.
 511          */
 512         bcd_descr_change = bcd_descr & KEYSPAN_FW_FLAG;
 513 
 514         return (bcd_descr_change == KEYSPAN_FW_FLAG);
 515 }
 516 
 517 /* Set the device's register. */
 518 static int
 519 keyspan_set_reg(keyspan_pipe_t *pipe, uchar_t bit)
 520 {
 521         int     rval;
 522 
 523         /*
 524          * (0x7f92) is the reg addr we want to set.
 525          * We set this reg before/after downloading firmware.
 526          */
 527         rval = keyspan_write_memory(pipe, 0x7f92, &bit, 1, KEYSPAN_REQ_SET);
 528 
 529         return (rval);
 530 }
 531 
 532 /*
 533  * Download firmware or set register to the device by default ctrl pipe
 534  */
 535 static int
 536 keyspan_write_memory(keyspan_pipe_t *pipe, uint16_t addr, uchar_t *buf,
 537     uint16_t len, uint8_t bRequest)
 538 {
 539         mblk_t *data;
 540         usb_ctrl_setup_t setup;
 541 
 542         usb_cb_flags_t  cb_flags;
 543         usb_cr_t        cr;
 544         uint8_t         retry = 0;
 545 
 546         /* reuse previous mblk if possible */
 547         if ((data = allocb(len, BPRI_HI)) == NULL) {
 548 
 549                 return (USB_FAILURE);
 550         }
 551 
 552         bcopy(buf, data->b_rptr, len);
 553 
 554         setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR;
 555 
 556         /* This is a req defined by hardware vendor. */
 557         setup.bRequest = bRequest;
 558         setup.wValue = addr;
 559         setup.wIndex = 0;
 560         setup.wLength = len;
 561         setup.attrs = 0;
 562 
 563         while (usb_pipe_ctrl_xfer_wait(pipe->pipe_handle, &setup, &data,
 564             &cr, &cb_flags, 0) != USB_SUCCESS) {
 565 
 566                 /* KEYSPAN_RETRY */
 567                 if (++retry > 3) {
 568                         if (data) {
 569                                 freemsg(data);
 570                         }
 571 
 572                         return (USB_FAILURE);
 573                 }
 574         }
 575 
 576         if (data) {
 577                 freemsg(data);
 578         }
 579 
 580         return (USB_SUCCESS);
 581 }
 582 
 583 /* Download firmware into device */
 584 static int
 585 keyspan_download_firmware(keyspan_pre_state_t *kbp)
 586 {
 587         usbser_keyspan_fw_record_t *record = NULL;
 588 
 589         /* If the firmware module exists, then download it to device. */
 590         if (&keyspan_usa49wlc_fw) {
 591 
 592                 record = keyspan_usa49wlc_fw();
 593         }
 594 
 595         if (!record) {
 596                 USB_DPRINTF_L1(DPRINT_ATTACH, kbp->kb_lh,
 597                     "No firmware available for Keyspan usa49wlc"
 598                     " usb-to-serial adapter. Refer to usbsksp(7D)"
 599                     " for details.");
 600 
 601                 return (USB_FAILURE);
 602         }
 603 
 604         /* Set bit 1 before downloading firmware. */
 605         if (keyspan_set_reg(&kbp->kb_def_pipe, 1) != USB_SUCCESS) {
 606                 USB_DPRINTF_L2(DPRINT_ATTACH, kbp->kb_lh,
 607                     "keyspan_pre_attach: Set register failed.");
 608 
 609                 return (USB_FAILURE);
 610         }
 611 
 612         /* Write until the last record of the firmware */
 613         while (record->address != 0xffff) {
 614                 if (keyspan_write_memory(&kbp->kb_def_pipe,
 615                     record->address, (uchar_t *)record->data,
 616                     record->data_len, KEYSPAN_REQ_SET) != USB_SUCCESS) {
 617                         USB_DPRINTF_L2(DPRINT_ATTACH, kbp->kb_lh,
 618                             "keyspan_pre_attach: download firmware failed.");
 619 
 620                         return (USB_FAILURE);
 621                 }
 622                 record++;
 623         }
 624 
 625         /*
 626          * Set bit 0, device will be enumerated again after a while,
 627          * and then go to keyspan_attach()
 628          */
 629         if (keyspan_set_reg(&kbp->kb_def_pipe, 0) != USB_SUCCESS) {
 630 
 631                 return (USB_FAILURE);
 632         }
 633 
 634         return (USB_SUCCESS);
 635 }