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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 
  28 #include <sys/stat.h>             /* ddi_create_minor_node S_IFCHR */
  29 #include <sys/modctl.h>           /* for modldrv */
  30 #include <sys/open.h>             /* for open params.      */
  31 #include <sys/types.h>
  32 #include <sys/kmem.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/conf.h>             /* req. by dev_ops flags MTSAFE etc. */
  35 #include <sys/ddi.h>
  36 #include <sys/file.h>
  37 #include <sys/note.h>
  38 
  39 #include <sys/i2c/clients/pcf8574_impl.h>
  40 
  41 static void *pcf8574soft_statep;
  42 
  43 static int pcf8574_do_attach(dev_info_t *);
  44 static int pcf8574_do_detach(dev_info_t *);
  45 static int pcf8574_do_resume(void);
  46 static int pcf8574_do_suspend(void);
  47 static int pcf8574_get(struct pcf8574_unit *, uchar_t *);
  48 static int pcf8574_set(struct pcf8574_unit *, uchar_t);
  49 
  50 static void littleneck_abort_seq_handler(char *msg);
  51 extern void (*abort_seq_handler)();
  52 
  53 static void littleneck_ks_poll(void *);
  54 
  55 /*
  56  * cb ops (only need ioctl)
  57  */
  58 static int pcf8574_open(dev_t *, int, int, cred_t *);
  59 static int pcf8574_close(dev_t, int, int, cred_t *);
  60 static int pcf8574_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  61 
  62 static struct cb_ops pcf8574_cbops = {
  63         pcf8574_open,                   /* open  */
  64         pcf8574_close,                  /* close */
  65         nodev,                          /* strategy */
  66         nodev,                          /* print */
  67         nodev,                          /* dump */
  68         nodev,                          /* read */
  69         nodev,                          /* write */
  70         pcf8574_ioctl,                  /* ioctl */
  71         nodev,                          /* devmap */
  72         nodev,                          /* mmap */
  73         nodev,                          /* segmap */
  74         nochpoll,                       /* poll */
  75         ddi_prop_op,                    /* cb_prop_op */
  76         NULL,                           /* streamtab */
  77         D_NEW | D_MP | D_HOTPLUG,       /* Driver compatibility flag */
  78         CB_REV,                         /* rev */
  79         nodev,                          /* int (*cb_aread)() */
  80         nodev                           /* int (*cb_awrite)() */
  81 };
  82 
  83 /*
  84  * dev ops
  85  */
  86 static int pcf8574_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
  87 static int pcf8574_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  88 
  89 static struct dev_ops pcf8574_ops = {
  90         DEVO_REV,
  91         0,
  92         ddi_getinfo_1to1,
  93         nulldev,
  94         nulldev,
  95         pcf8574_attach,
  96         pcf8574_detach,
  97         nodev,
  98         &pcf8574_cbops,
  99         NULL,                   /* bus_ops */
 100         NULL,                   /* power */
 101         ddi_quiesce_not_needed,         /* quiesce */
 102 };
 103 
 104 extern struct mod_ops mod_driverops;
 105 
 106 static struct modldrv pcf8574_modldrv = {
 107         &mod_driverops,                     /* type of module - driver */
 108         "PCF8574 i2c device driver: v1.9",
 109         &pcf8574_ops
 110 };
 111 
 112 static struct modlinkage pcf8574_modlinkage = {
 113         MODREV_1,
 114         &pcf8574_modldrv,
 115         0
 116 };
 117 
 118 #define LNECK_KEY_POLL_BIT 5
 119 #define LNECK_KEY_POLL_INTVL 10         /* 10 seconds poll interval */
 120 static timeout_id_t keypoll_timeout_id;
 121 static clock_t keypoll_timeout_hz;
 122 static boolean_t key_locked_bit;
 123 
 124 
 125 int
 126 _init(void)
 127 {
 128         int error;
 129 
 130         error = mod_install(&pcf8574_modlinkage);
 131 
 132         if (!error)
 133                 (void) ddi_soft_state_init(&pcf8574soft_statep,
 134                     sizeof (struct pcf8574_unit), 1);
 135         return (error);
 136 }
 137 
 138 int
 139 _fini(void)
 140 {
 141         int error;
 142 
 143         error = mod_remove(&pcf8574_modlinkage);
 144         if (!error)
 145                 ddi_soft_state_fini(&pcf8574soft_statep);
 146 
 147         return (error);
 148 }
 149 
 150 int
 151 _info(struct modinfo *modinfop)
 152 {
 153         return (mod_info(&pcf8574_modlinkage, modinfop));
 154 }
 155 
 156 static int
 157 pcf8574_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 158 {
 159         _NOTE(ARGUNUSED(credp))
 160         struct pcf8574_unit *unitp;
 161         int instance;
 162         int error = 0;
 163 
 164         D1CMN_ERR((CE_WARN, "Opening the PCF8574 device\n"));
 165 
 166         instance = getminor(*devp);
 167 
 168         if (instance < 0) {
 169                 return (ENXIO);
 170         }
 171 
 172         unitp = (struct pcf8574_unit *)
 173             ddi_get_soft_state(pcf8574soft_statep, instance);
 174 
 175         if (unitp == NULL) {
 176                 return (ENXIO);
 177         }
 178 
 179         if (otyp != OTYP_CHR) {
 180                 return (EINVAL);
 181         }
 182 
 183         mutex_enter(&unitp->pcf8574_mutex);
 184 
 185         if (flags & FEXCL) {
 186                 if (unitp->pcf8574_oflag != 0) {
 187                         error = EBUSY;
 188                 } else {
 189                         unitp->pcf8574_oflag = FEXCL;
 190                 }
 191         } else {
 192                 if (unitp->pcf8574_oflag == FEXCL) {
 193                         error = EBUSY;
 194                 } else {
 195                         unitp->pcf8574_oflag = FOPEN;
 196                 }
 197         }
 198 
 199         mutex_exit(&unitp->pcf8574_mutex);
 200 
 201         return (error);
 202 }
 203 
 204 static int
 205 pcf8574_close(dev_t dev, int flags, int otyp, cred_t *credp)
 206 {
 207         _NOTE(ARGUNUSED(flags, otyp, credp))
 208         struct pcf8574_unit *unitp;
 209         int instance;
 210 
 211         instance = getminor(dev);
 212 
 213         if (instance < 0) {
 214                 return (ENXIO);
 215         }
 216         unitp = (struct pcf8574_unit *)
 217             ddi_get_soft_state(pcf8574soft_statep, instance);
 218 
 219         if (unitp == NULL) {
 220                 return (ENXIO);
 221         }
 222 
 223         mutex_enter(&unitp->pcf8574_mutex);
 224 
 225         unitp->pcf8574_oflag = 0;
 226 
 227         mutex_exit(&unitp->pcf8574_mutex);
 228         return (DDI_SUCCESS);
 229 }
 230 
 231 static int
 232 pcf8574_get(struct pcf8574_unit *unitp, uchar_t *byte) {
 233         i2c_transfer_t          *i2c_tran_pointer;
 234         int                     err = I2C_SUCCESS;
 235 
 236         D1CMN_ERR((CE_WARN, "Entered the pcf8574_get routine\n"));
 237 
 238         (void) i2c_transfer_alloc(unitp->pcf8574_hdl, &i2c_tran_pointer,
 239                                         0, 1, I2C_SLEEP);
 240         if (i2c_tran_pointer == NULL) {
 241                 D2CMN_ERR((CE_WARN, "%s: Failed in pcf8574_get "
 242                                 "i2c_tran_pointer not allocated\n",
 243                                 unitp->pcf8574_name));
 244                 return (ENOMEM);
 245         }
 246 
 247         i2c_tran_pointer->i2c_flags = I2C_RD;
 248 
 249         err = i2c_transfer(unitp->pcf8574_hdl, i2c_tran_pointer);
 250         if (err) {
 251                 D2CMN_ERR((CE_WARN, "%s: Failed in the i2c_transfer routine\n",
 252                                 unitp->pcf8574_name));
 253                 i2c_transfer_free(unitp->pcf8574_hdl, i2c_tran_pointer);
 254                 return (err);
 255         }
 256 
 257         D1CMN_ERR((CE_WARN, "Back from a transfer value is %x\n",
 258                 i2c_tran_pointer->i2c_rbuf[0]));
 259         *byte = i2c_tran_pointer->i2c_rbuf[0];
 260 
 261         i2c_transfer_free(unitp->pcf8574_hdl, i2c_tran_pointer);
 262         return (err);
 263 }
 264 
 265 static int
 266 pcf8574_set(struct pcf8574_unit *unitp, uchar_t byte) {
 267         i2c_transfer_t          *i2c_tran_pointer;
 268         int                     err = I2C_SUCCESS;
 269 
 270         (void) i2c_transfer_alloc(unitp->pcf8574_hdl, &i2c_tran_pointer,
 271                                 1, 0, I2C_SLEEP);
 272         if (i2c_tran_pointer == NULL) {
 273                 D2CMN_ERR((CE_WARN, "%s: Failed in pcf8574_set "
 274                                 "i2c_tran_pointer not allocated\n",
 275                                 unitp->pcf8574_name));
 276                 return (ENOMEM);
 277         }
 278 
 279         i2c_tran_pointer->i2c_flags = I2C_WR;
 280         i2c_tran_pointer->i2c_wbuf[0] = byte;
 281 
 282         D1CMN_ERR((CE_NOTE, "%s: contains %x\n", unitp->pcf8574_name,
 283                         i2c_tran_pointer->i2c_wbuf[0]));
 284 
 285         err = i2c_transfer(unitp->pcf8574_hdl, i2c_tran_pointer);
 286         if (err) {
 287                 D2CMN_ERR((CE_WARN, "%s: Failed in the pcf8574_set"
 288                                 " i2c_transfer routine\n",
 289                                 unitp->pcf8574_name));
 290                 i2c_transfer_free(unitp->pcf8574_hdl, i2c_tran_pointer);
 291                 return (err);
 292         }
 293         i2c_transfer_free(unitp->pcf8574_hdl, i2c_tran_pointer);
 294         return (err);
 295 }
 296 
 297 static int
 298 pcf8574_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 299                 cred_t *credp, int *rvalp)
 300 {
 301         _NOTE(ARGUNUSED(credp, rvalp))
 302         struct pcf8574_unit     *unitp;
 303         int             instance;
 304         int                     err = 0;
 305         i2c_bit_t               ioctl_bit;
 306         i2c_port_t              ioctl_port;
 307         uchar_t                 byte;
 308 
 309         if (arg == NULL) {
 310                 D2CMN_ERR((CE_WARN, "PCF8574: ioctl: arg passed in to ioctl "
 311                     "= NULL\n"));
 312                 err = EINVAL;
 313                 return (err);
 314         }
 315 
 316         instance = getminor(dev);
 317         unitp = (struct pcf8574_unit *)
 318             ddi_get_soft_state(pcf8574soft_statep, instance);
 319         if (unitp == NULL) {
 320                 cmn_err(CE_WARN, "PCF8574: ioctl: unitp not filled\n");
 321                 return (ENOMEM);
 322         }
 323 
 324         mutex_enter(&unitp->pcf8574_mutex);
 325 
 326         switch (cmd) {
 327         case I2C_GET_PORT:
 328                 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_port,
 329                     sizeof (i2c_port_t), mode) != DDI_SUCCESS) {
 330                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_PORT"
 331                             " ddi_copyin routine\n",
 332                             unitp->pcf8574_name));
 333                         err = EFAULT;
 334                         break;
 335                 }
 336 
 337                 err = pcf8574_get(unitp, &byte);
 338                 if (err != I2C_SUCCESS) {
 339                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_PORT"
 340                             " pcf8574_get routine\n",
 341                             unitp->pcf8574_name));
 342                         break;
 343                 }
 344 
 345                 ioctl_port.value = byte;
 346                 if (ddi_copyout((caddr_t)&ioctl_port, (caddr_t)arg,
 347                     sizeof (i2c_port_t), mode) != DDI_SUCCESS) {
 348                         D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_PORT "
 349                             "ddi_copyout routine\n",
 350                             unitp->pcf8574_name));
 351                         err = EFAULT;
 352                 }
 353 
 354                 D1CMN_ERR((CE_NOTE, "%s: contains %x\n", unitp->pcf8574_name,
 355                     byte));
 356                 break;
 357 
 358         case I2C_SET_PORT:
 359                 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_port,
 360                     sizeof (uint8_t), mode) != DDI_SUCCESS) {
 361                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_PORT"
 362                             "ddi_cpoyin routine\n",
 363                             unitp->pcf8574_name));
 364                         err = EFAULT;
 365                         break;
 366                 }
 367 
 368                 err = pcf8574_set(unitp, ioctl_port.value);
 369                 if (err != I2C_SUCCESS) {
 370                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_PORT"
 371                             " pcf8574_set routine\n",
 372                             unitp->pcf8574_name));
 373                         break;
 374                 }
 375                 break;
 376 
 377         case I2C_GET_BIT:
 378                 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_bit,
 379                     sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
 380                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_BIT"
 381                             " ddi_copyin routine\n",
 382                             unitp->pcf8574_name));
 383                         err = EFAULT;
 384                         break;
 385                 }
 386 
 387                 if (ioctl_bit.bit_num > 7) {
 388                         D2CMN_ERR((CE_WARN, "%s: In I2C_GET_BIT bit num"
 389                             " was not between 0 and 7\n",
 390                             unitp->pcf8574_name));
 391                         err = EIO;
 392                         break;
 393                 }
 394 
 395                 err = pcf8574_get(unitp, &byte);
 396                 if (err != I2C_SUCCESS) {
 397                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_GET_BIT"
 398                             " pcf8574_get routine\n",
 399                             unitp->pcf8574_name));
 400                         break;
 401                 }
 402 
 403                 D1CMN_ERR((CE_NOTE, "%s: byte returned from device is %x\n",
 404                     unitp->pcf8574_name, byte));
 405                 ioctl_bit.bit_value = (boolean_t)PCF8574_BIT_READ_MASK(byte,
 406                     ioctl_bit.bit_num);
 407                 D1CMN_ERR((CE_NOTE, "%s: byte now contains %x\n",
 408                     unitp->pcf8574_name, byte));
 409 
 410                 if (ddi_copyout((caddr_t)&ioctl_bit, (caddr_t)arg,
 411                     sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
 412                         D2CMN_ERR((CE_WARN, "%s: Failed in I2C_GET_BIT"
 413                             " ddi_copyout routine\n",
 414                             unitp->pcf8574_name));
 415                         err = EFAULT;
 416                 }
 417                 break;
 418 
 419         case I2C_SET_BIT:
 420                 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_bit,
 421                     sizeof (i2c_bit_t), mode) != DDI_SUCCESS) {
 422                         D2CMN_ERR((CE_WARN, "%s: Failed in I2C_SET_BIT"
 423                             " ddi_copyin routine\n",
 424                             unitp->pcf8574_name));
 425                         err = EFAULT;
 426                         break;
 427                 }
 428 
 429                 if (ioctl_bit.bit_num > 7) {
 430                         D2CMN_ERR((CE_WARN, "%s: I2C_SET_BIT: bit_num sent"
 431                             " in was not between 0 and 7",
 432                             unitp->pcf8574_name));
 433                         err = EIO;
 434                         break;
 435                 }
 436 
 437                 err = pcf8574_get(unitp, &byte);
 438                 if (err != I2C_SUCCESS) {
 439                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_BIT"
 440                             " pcf8574_get routine\n",
 441                             unitp->pcf8574_name));
 442                         break;
 443                 }
 444 
 445                 D1CMN_ERR((CE_NOTE, "%s: byte returned from device is %x\n",
 446                     unitp->pcf8574_name, byte));
 447                 byte = PCF8574_BIT_WRITE_MASK(byte, ioctl_bit.bit_num,
 448                     ioctl_bit.bit_value);
 449                 D1CMN_ERR((CE_NOTE, "%s: byte after shifting is %x\n",
 450                     unitp->pcf8574_name, byte));
 451 
 452                 err = pcf8574_set(unitp, byte);
 453                 if (err != I2C_SUCCESS) {
 454                         D2CMN_ERR((CE_WARN, "%s: Failed in the I2C_SET_BIT"
 455                             " pcf8574_set routine\n",
 456                             unitp->pcf8574_name));
 457                         break;
 458                 }
 459                 break;
 460 
 461         default:
 462                 D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n",
 463                     unitp->pcf8574_name, cmd));
 464                 err = EINVAL;
 465         }
 466 
 467         mutex_exit(&unitp->pcf8574_mutex);
 468         return (err);
 469 }
 470 
 471 static int
 472 pcf8574_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 473 {
 474         switch (cmd) {
 475         case DDI_ATTACH:
 476                 return (pcf8574_do_attach(dip));
 477         case DDI_RESUME:
 478                 return (pcf8574_do_resume());
 479         default:
 480                 return (DDI_FAILURE);
 481         }
 482 }
 483 
 484 static int
 485 pcf8574_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 486 {
 487         switch (cmd) {
 488         case DDI_DETACH:
 489                 return (pcf8574_do_detach(dip));
 490         case DDI_SUSPEND:
 491                 return (pcf8574_do_suspend());
 492         default:
 493                 return (DDI_FAILURE);
 494         }
 495 }
 496 
 497 static int
 498 pcf8574_do_attach(dev_info_t *dip)
 499 {
 500         struct pcf8574_unit *unitp;
 501         int instance, err;
 502         uint_t len;
 503         int *regs;
 504 
 505         instance = ddi_get_instance(dip);
 506 
 507         if (ddi_soft_state_zalloc(pcf8574soft_statep, instance) != 0) {
 508                 cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
 509                     ddi_get_name(dip), instance);
 510                 return (DDI_FAILURE);
 511         }
 512 
 513         unitp = ddi_get_soft_state(pcf8574soft_statep, instance);
 514 
 515         if (unitp == NULL) {
 516                 cmn_err(CE_WARN, "%s%d: unitp not filled\n",
 517                     ddi_get_name(dip), instance);
 518                 return (ENOMEM);
 519         }
 520 
 521         (void) snprintf(unitp->pcf8574_name, sizeof (unitp->pcf8574_name),
 522             "%s%d", ddi_node_name(dip), instance);
 523 
 524 
 525         if (ddi_create_minor_node(dip, "pcf8574", S_IFCHR, instance,
 526             "ddi_i2c:ioexp", NULL) == DDI_FAILURE) {
 527                 cmn_err(CE_WARN, "%s ddi_create_minor_node failed for "
 528                     "%s\n", unitp->pcf8574_name, "pcf8574");
 529                 ddi_soft_state_free(pcf8574soft_statep, instance);
 530 
 531                 return (DDI_FAILURE);
 532         }
 533 
 534         if (i2c_client_register(dip, &unitp->pcf8574_hdl) != I2C_SUCCESS) {
 535                 ddi_remove_minor_node(dip, NULL);
 536                 ddi_soft_state_free(pcf8574soft_statep, instance);
 537 
 538                 return (DDI_FAILURE);
 539         }
 540 
 541         err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
 542             DDI_PROP_DONTPASS,
 543             "reg", (int **)&regs, &len);
 544         if (err != DDI_PROP_SUCCESS) {
 545                 return (DDI_FAILURE);
 546         }
 547 
 548         /*
 549          * regs[0] contains the bus number and regs[1] contains the device
 550          * address of the i2c device. 0x7c is the device address of the
 551          * i2c device from which the key switch position is read.
 552          */
 553         if (regs[0] == 0 && regs[1] == 0x7c) {
 554                 abort_seq_handler = littleneck_abort_seq_handler;
 555                 keypoll_timeout_hz =
 556                     drv_sectohz(LNECK_KEY_POLL_INTVL);
 557                 littleneck_ks_poll(unitp);
 558         }
 559 
 560         ddi_prop_free(regs);
 561 
 562         mutex_init(&unitp->pcf8574_mutex, NULL, MUTEX_DRIVER, NULL);
 563 
 564         return (DDI_SUCCESS);
 565 }
 566 
 567 static int
 568 pcf8574_do_resume()
 569 {
 570         int ret = DDI_SUCCESS;
 571 
 572         return (ret);
 573 }
 574 
 575 static int
 576 pcf8574_do_suspend()
 577 {
 578         int ret = DDI_SUCCESS;
 579 
 580         return (ret);
 581 }
 582 
 583 static int
 584 pcf8574_do_detach(dev_info_t *dip)
 585 {
 586         struct pcf8574_unit *unitp;
 587         int instance;
 588 
 589         instance = ddi_get_instance(dip);
 590 
 591         unitp = ddi_get_soft_state(pcf8574soft_statep, instance);
 592 
 593         if (unitp == NULL) {
 594                 cmn_err(CE_WARN, "%s%d: unitp not filled\n",
 595                     ddi_get_name(dip), instance);
 596                 return (ENOMEM);
 597         }
 598 
 599         (void) untimeout(keypoll_timeout_id);
 600 
 601         i2c_client_unregister(unitp->pcf8574_hdl);
 602 
 603         ddi_remove_minor_node(dip, NULL);
 604 
 605         mutex_destroy(&unitp->pcf8574_mutex);
 606 
 607         ddi_soft_state_free(pcf8574soft_statep, instance);
 608 
 609         return (DDI_SUCCESS);
 610 
 611 }
 612 
 613 static void
 614 littleneck_ks_poll(void *arg)
 615 {
 616         struct pcf8574_unit *unitp = (struct pcf8574_unit *)arg;
 617         uint8_t byte;
 618 
 619         mutex_enter(&unitp->pcf8574_mutex);
 620 
 621         if (pcf8574_get(unitp, &byte) != I2C_SUCCESS) {
 622                 D2CMN_ERR((CE_WARN, "%s: Failed in littleneck_ks_poll"
 623                     " pcf8574_get routine\n", unitp->pcf8574_name));
 624                 mutex_exit(&unitp->pcf8574_mutex);
 625                 return;
 626         }
 627 
 628         /*
 629          * 5th bit in the byte is the key LOCKED position
 630          */
 631         key_locked_bit = (boolean_t)PCF8574_BIT_READ_MASK(byte,
 632             LNECK_KEY_POLL_BIT);
 633 
 634         keypoll_timeout_id = (timeout(littleneck_ks_poll,
 635             (caddr_t)unitp, keypoll_timeout_hz));
 636 
 637         mutex_exit(&unitp->pcf8574_mutex);
 638 }
 639 
 640 static void
 641 littleneck_abort_seq_handler(char *msg)
 642 {
 643 
 644         if (key_locked_bit == 0)
 645                 cmn_err(CE_CONT, "KEY in LOCKED position, "
 646                     "ignoring debug enter sequence\n");
 647         else  {
 648                 D1CMN_ERR((CE_CONT, "debug enter sequence \n"));
 649                 debug_enter(msg);
 650         }
 651 }