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 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <assert.h>
  30 #include <fcntl.h>
  31 #include <sys/types.h>
  32 #include <signal.h>
  33 #include <sys/stat.h>
  34 #include <unistd.h>
  35 #include <limits.h>
  36 #include <stdio.h>
  37 #include <stdarg.h>
  38 #include <stdlib.h>
  39 #include <stropts.h>
  40 #include <strings.h>
  41 #include <thread.h>
  42 #include <errno.h>
  43 #include <libintl.h>
  44 #include <sys/bitmap.h>
  45 #include <sys/lx_autofs.h>
  46 #include <sys/modctl.h>
  47 #include <sys/filio.h>
  48 #include <sys/termios.h>
  49 #include <sys/termio.h>
  50 #include <sys/sockio.h>
  51 #include <net/if.h>
  52 #include <net/if_arp.h>
  53 #include <sys/ptms.h>
  54 #include <sys/ldlinux.h>
  55 #include <sys/lx_ptm.h>
  56 #include <sys/lx_socket.h>
  57 #include <sys/syscall.h>
  58 #include <sys/brand.h>
  59 #include <sys/lx_audio.h>
  60 #include <sys/lx_ioctl.h>
  61 #include <sys/lx_misc.h>
  62 #include <sys/lx_debug.h>
  63 #include <sys/ptyvar.h>
  64 #include <sys/audio.h>
  65 #include <sys/mixer.h>
  66 
  67 /* Define _KERNEL to get the devt manipulation macros. */
  68 #define _KERNEL
  69 #include <sys/sysmacros.h>
  70 #undef  _KERNEL
  71 
  72 /* Maximum number of modules on a stream that we can handle. */
  73 #define MAX_STRMODS     10
  74 
  75 /* Maximum buffer size for debugging messages. */
  76 #define MSGBUF          1024
  77 
  78 /* Structure used to define an ioctl translator. */
  79 typedef struct ioc_cmd_translator {
  80         int     ict_lx_cmd;
  81         char    *ict_lx_cmd_str;
  82         int     ict_cmd;
  83         char    *ict_cmd_str;
  84         int     (*ict_func)(int fd, struct stat *stat,
  85             int cmd, char *cmd_str, intptr_t arg);
  86 } ioc_cmd_translator_t;
  87 
  88 /*
  89  * Structures used to associate a group of ioctl translators with
  90  * a specific device.
  91  */
  92 typedef struct ioc_dev_translator {
  93         char                    *idt_driver;
  94         major_t                 idt_major;
  95 
  96         /* Array of command translators. */
  97         ioc_cmd_translator_t    *idt_cmds;
  98 } ioc_dev_translator_t;
  99 
 100 /*
 101  * Structures used to associate a group of ioctl translators with
 102  * a specific filesystem.
 103  */
 104 typedef struct ioc_fs_translator {
 105         char                    *ift_filesystem;
 106 
 107         /* Array of command translators. */
 108         ioc_cmd_translator_t    *ift_cmds;
 109 } ioc_fs_translator_t;
 110 
 111 /* Structure used to define a unsupported ioctl error codes. */
 112 typedef struct ioc_errno_translator {
 113         int     iet_lx_cmd;
 114         char    *iet_lx_cmd_str;
 115         int     iet_errno;
 116 } ioc_errno_translator_t;
 117 
 118 /* Structure used to convert oss format flags into Solaris options. */
 119 typedef struct oss_fmt_translator {
 120         int     oft_oss_fmt;
 121         int     oft_encoding;
 122         int     oft_precision;
 123 } oss_fmt_translator_t;
 124 
 125 /* Translator forward declerations. */
 126 static oss_fmt_translator_t oft_table[];
 127 static ioc_cmd_translator_t ioc_translators_file[];
 128 static ioc_cmd_translator_t ioc_translators_fifo[];
 129 static ioc_cmd_translator_t ioc_translators_sock[];
 130 static ioc_dev_translator_t ioc_translator_ptm;
 131 static ioc_dev_translator_t *ioc_translators_dev[];
 132 static ioc_fs_translator_t *ioc_translators_fs[];
 133 static ioc_errno_translator_t ioc_translators_errno[];
 134 
 135 /*
 136  * Interface name table.
 137  */
 138 typedef struct ifname_map {
 139         char    im_linux[IFNAMSIZ];
 140         char    im_solaris[IFNAMSIZ];
 141         struct ifname_map *im_next;
 142 } ifname_map_t;
 143 
 144 static ifname_map_t *ifname_map;
 145 static mutex_t ifname_mtx;
 146 
 147 /*
 148  * Macros and structures to help convert integers to string
 149  * values that they represent (for displaying in debug output).
 150  */
 151 #define I2S_ENTRY(x)    { x, #x },
 152 #define I2S_END         { 0, NULL }
 153 
 154 typedef struct int2str {
 155         int     i2s_int;
 156         char    *i2s_str;
 157 } int2str_t;
 158 
 159 static int2str_t st_mode_strings[] = {
 160         I2S_ENTRY(S_IFIFO)
 161         I2S_ENTRY(S_IFCHR)
 162         I2S_ENTRY(S_IFDIR)
 163         I2S_ENTRY(S_IFBLK)
 164         I2S_ENTRY(S_IFREG)
 165         I2S_ENTRY(S_IFLNK)
 166         I2S_ENTRY(S_IFSOCK)
 167         I2S_ENTRY(S_IFDOOR)
 168         I2S_ENTRY(S_IFPORT)
 169         I2S_END
 170 };
 171 
 172 static int2str_t oss_fmt_str[] = {
 173         I2S_ENTRY(LX_OSS_AFMT_QUERY)
 174         I2S_ENTRY(LX_OSS_AFMT_MU_LAW)
 175         I2S_ENTRY(LX_OSS_AFMT_A_LAW)
 176         I2S_ENTRY(LX_OSS_AFMT_IMA_ADPCM)
 177         I2S_ENTRY(LX_OSS_AFMT_U8)
 178         I2S_ENTRY(LX_OSS_AFMT_S16_LE)
 179         I2S_ENTRY(LX_OSS_AFMT_S16_BE)
 180         I2S_ENTRY(LX_OSS_AFMT_S8)
 181         I2S_ENTRY(LX_OSS_AFMT_U16_LE)
 182         I2S_ENTRY(LX_OSS_AFMT_U16_BE)
 183         I2S_ENTRY(LX_OSS_AFMT_MPEG)
 184         I2S_END
 185 };
 186 
 187 static void
 188 lx_ioctl_msg(int fd, int cmd, char *lx_cmd_str, struct stat *stat, char *msg)
 189 {
 190         int     errno_backup = errno;
 191         char    *path, path_buf[MAXPATHLEN];
 192 
 193         assert(msg != NULL);
 194 
 195         if (lx_debug_enabled == 0)
 196                 return;
 197 
 198         path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
 199         if (path == NULL)
 200                 path = "?";
 201 
 202         if (lx_cmd_str == NULL)
 203                 lx_cmd_str = "?";
 204 
 205         /* Display the initial error message and extended ioctl information. */
 206         lx_debug("\t%s", msg);
 207         lx_debug("\tlx_ioctl(): cmd = 0x%x - %s, fd = %d - %s",
 208             cmd, lx_cmd_str, fd, path);
 209 
 210         /* Display information about the target file, if it's available. */
 211         if (stat != NULL) {
 212                 major_t fd_major = getmajor(stat->st_rdev);
 213                 minor_t fd_minor = getminor(stat->st_rdev);
 214                 int     fd_mode = stat->st_mode & S_IFMT;
 215                 char    *fd_mode_str = "unknown";
 216                 char    buf[LX_MSG_MAXLEN];
 217                 int     i;
 218 
 219                 /* Translate the file type bits into a string. */
 220                 for (i = 0; st_mode_strings[i].i2s_str != NULL; i++) {
 221                         if (fd_mode != st_mode_strings[i].i2s_int)
 222                                 continue;
 223                         fd_mode_str = st_mode_strings[i].i2s_str;
 224                         break;
 225                 }
 226 
 227                 (void) snprintf(buf, sizeof (buf),
 228                     "\tlx_ioctl(): mode = %s", fd_mode_str);
 229 
 230                 if ((fd_mode == S_IFCHR) || (fd_mode == S_IFBLK)) {
 231                         char    *fd_driver[MODMAXNAMELEN + 1];
 232                         int     i;
 233 
 234                         /* This is a device so display the devt. */
 235                         i = strlen(buf);
 236                         (void) snprintf(buf + i, sizeof (buf) - i,
 237                             "; rdev = [%d, %d]", fd_major, fd_minor);
 238 
 239                         /* Try to display the drivers name. */
 240                         if (modctl(MODGETNAME,
 241                             fd_driver, sizeof (fd_driver), &fd_major) == 0)
 242                                 i = strlen(buf);
 243                                 (void) snprintf(buf + i, sizeof (buf) - i,
 244                                     "; driver = %s", fd_driver);
 245                 }
 246                 lx_debug(buf);
 247         }
 248 
 249         /* Restore errno. */
 250         errno = errno_backup;
 251 }
 252 
 253 static int
 254 ldlinux_check(int fd)
 255 {
 256         struct str_mlist        mlist[MAX_STRMODS];
 257         struct str_list         strlist;
 258         int                     i;
 259 
 260         /* Get the number of modules on the stream. */
 261         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 262             fd, I_LIST, "I_LIST");
 263         if ((i = ioctl(fd, I_LIST, (struct str_list *)NULL)) < 0) {
 264                 lx_debug("\tldlinux_check(): unable to count stream modules");
 265                 return (-errno);
 266         }
 267 
 268         /* Sanity check the number of modules on the stream. */
 269         assert(i <= MAX_STRMODS);
 270 
 271         /* Get the list of modules on the stream. */
 272         strlist.sl_nmods = i;
 273         strlist.sl_modlist = mlist;
 274         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 275             fd, I_LIST, "I_LIST");
 276         if (ioctl(fd, I_LIST, &strlist) < 0) {
 277                 lx_debug("\tldlinux_check(): unable to list stream modules");
 278                 return (-errno);
 279         }
 280 
 281         for (i = 0; i < strlist.sl_nmods; i++)
 282                 if (strcmp(strlist.sl_modlist[i].l_name, LDLINUX_MOD) == 0)
 283                         return (1);
 284 
 285         return (0);
 286 }
 287 
 288 static int
 289 ioctl_istr(int fd, int cmd, char *cmd_str, void *arg, int arg_len)
 290 {
 291         struct strioctl istr;
 292 
 293         istr.ic_cmd = cmd;
 294         istr.ic_len = arg_len;
 295         istr.ic_timout = 0;
 296         istr.ic_dp = arg;
 297 
 298         lx_debug("\tioctl_istr(%d, 0x%x - %s, ...)", fd, cmd, cmd_str);
 299         if (ioctl(fd, I_STR, &istr) < 0)
 300                 return (-1);
 301         return (0);
 302 }
 303 
 304 /*
 305  * Add an interface name mapping if it doesn't already exist.
 306  *
 307  * Interfaces with IFF_LOOPBACK flag get renamed to loXXX.
 308  * Interfaces with IFF_BROADCAST flag get renamed to ethXXX.
 309  *
 310  * Caller locks the name table.
 311  */
 312 static int
 313 ifname_add(char *if_name, int if_flags)
 314 {
 315         static int eth_index = 0;
 316         static int lo_index = 0;
 317         ifname_map_t **im_pp;
 318 
 319         for (im_pp = &ifname_map; *im_pp; im_pp = &(*im_pp)->im_next)
 320                 if (strncmp((*im_pp)->im_solaris, if_name, IFNAMSIZ) == 0)
 321                         return (0);
 322 
 323         *im_pp = calloc(1, sizeof (ifname_map_t));
 324         if (*im_pp == NULL)
 325                 return (-1);
 326 
 327         (void) strlcpy((*im_pp)->im_solaris, if_name, IFNAMSIZ);
 328         if (if_flags & IFF_LOOPBACK) {
 329                 /* Loopback */
 330                 if (lo_index == 0)
 331                         (void) strlcpy((*im_pp)->im_linux, "lo", IFNAMSIZ);
 332                 else
 333                         (void) snprintf((*im_pp)->im_linux, IFNAMSIZ,
 334                             "lo:%d", lo_index);
 335                 lo_index++;
 336         } else if (if_flags & IFF_BROADCAST) {
 337                 /* Assume ether if it has a broadcast address */
 338                 (void) snprintf((*im_pp)->im_linux, IFNAMSIZ,
 339                     "eth%d", eth_index);
 340                 eth_index++;
 341         } else {
 342                 /* Do not translate unknown interfaces */
 343                 (void) strlcpy((*im_pp)->im_linux, if_name, IFNAMSIZ);
 344         }
 345 
 346         lx_debug("map interface %s -> %s", if_name, (*im_pp)->im_linux);
 347 
 348         return (0);
 349 }
 350 
 351 static int
 352 ifname_cmp(const void *p1, const void *p2)
 353 {
 354         struct ifreq *rp1 = (struct ifreq *)p1;
 355         struct ifreq *rp2 = (struct ifreq *)p2;
 356 
 357         return (strncmp(rp1->ifr_name, rp2->ifr_name, IFNAMSIZ));
 358 }
 359 
 360 /*
 361  * (Re-)scan all interfaces and add them to the name table.
 362  * Caller locks the name table.
 363  */
 364 static int
 365 ifname_scan(void)
 366 {
 367         struct ifconf conf;
 368         int i, fd, ifcount;
 369 
 370         conf.ifc_buf = NULL;
 371 
 372         if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
 373                 goto fail;
 374         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFNUM, "SIOCGIFNUM");
 375         if (ioctl(fd, SIOCGIFNUM, &ifcount) < 0) {
 376                 lx_debug("\tifname_scan(): unable to get number of interfaces");
 377                 goto fail;
 378         }
 379 
 380         conf.ifc_len = ifcount * sizeof (struct ifreq);
 381         if ((conf.ifc_buf = calloc(ifcount, sizeof (struct ifreq))) == NULL)
 382                 goto fail;
 383         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFCONF, "SIOCGIFCONF");
 384         if (ioctl(fd, SIOCGIFCONF, &conf) < 0) {
 385                 lx_debug("\tifname_scan(): unable to get interfaces");
 386                 goto fail;
 387         }
 388 
 389         /* Get the interface flags */
 390         for (i = 0; i < ifcount; i++) {
 391                 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 392                     fd, SIOCGIFFLAGS, "SIOCGIFFLAGS");
 393                 if (ioctl(fd, SIOCGIFFLAGS, &conf.ifc_req[i]) < 0) {
 394                         conf.ifc_req[i].ifr_flags = 0;
 395                         lx_debug("\tifname_scan(): unable to get flags for %s",
 396                             conf.ifc_req[i].ifr_name);
 397                 }
 398         }
 399 
 400         /*
 401          * Sort the interfaces by name to preserve the order
 402          * across reboots of this zone.  Note that the order of
 403          * interface names won't be consistent across network
 404          * configuration changes.  ie.  If network interfaces
 405          * are added or removed from a zone (either dynamically
 406          * or statically) the network interfaces names to physical
 407          * network interface mappings that linux apps see may
 408          * change.
 409          */
 410         qsort(conf.ifc_req, ifcount, sizeof (struct ifreq), ifname_cmp);
 411 
 412         /* Add to the name table */
 413         for (i = 0; i < ifcount; i++)
 414                 if (ifname_add(conf.ifc_req[i].ifr_name,
 415                     conf.ifc_req[i].ifr_flags) != 0)
 416                         goto fail;
 417 
 418         (void) close(fd);
 419         free(conf.ifc_buf);
 420 
 421         return (0);
 422 
 423 fail:
 424         if (fd >= 0)
 425                 (void) close(fd);
 426         if (conf.ifc_buf != NULL)
 427                 free(conf.ifc_buf);
 428 
 429         return (-1);
 430 }
 431 
 432 static int
 433 ifname_from_linux(char *name)
 434 {
 435         int pass;
 436         ifname_map_t *im_p;
 437 
 438         (void) mutex_lock(&ifname_mtx);
 439 
 440         for (pass = 0; pass < 2; pass++) {
 441                 for (im_p = ifname_map; im_p; im_p = im_p->im_next)
 442                         if (strncmp(im_p->im_linux, name, IFNAMSIZ) == 0)
 443                                 break;
 444                 if (im_p != NULL || (pass == 0 && ifname_scan() != 0))
 445                         break;
 446         }
 447 
 448         (void) mutex_unlock(&ifname_mtx);
 449 
 450         if (im_p) {
 451                 (void) strlcpy(name, im_p->im_solaris, IFNAMSIZ);
 452                 return (0);
 453         }
 454 
 455         return (-1);
 456 }
 457 
 458 static int
 459 ifname_from_solaris(char *name)
 460 {
 461         int pass;
 462         ifname_map_t *im_p;
 463 
 464         (void) mutex_lock(&ifname_mtx);
 465 
 466         for (pass = 0; pass < 2; pass++) {
 467                 for (im_p = ifname_map; im_p; im_p = im_p->im_next)
 468                         if (strncmp(im_p->im_solaris, name, IFNAMSIZ) == 0)
 469                                 break;
 470                 if (im_p != NULL || (pass == 0 && ifname_scan() != 0))
 471                         break;
 472         }
 473 
 474         (void) mutex_unlock(&ifname_mtx);
 475 
 476         if (im_p) {
 477                 (void) strlcpy(name, im_p->im_linux, IFNAMSIZ);
 478                 return (0);
 479         }
 480 
 481         return (-1);
 482 }
 483 
 484 /*
 485  * Called to initialize the ioctl translation subsystem.
 486  */
 487 int
 488 lx_ioctl_init()
 489 {
 490         int i, ret;
 491 
 492         /* Figure out the major numbers for our devices translators. */
 493         for (i = 0; ioc_translators_dev[i] != NULL; i++) {
 494                 ioc_dev_translator_t *idt = ioc_translators_dev[i];
 495 
 496                 ret = modctl(MODGETMAJBIND,
 497                     idt->idt_driver, strlen(idt->idt_driver) + 1,
 498                     &idt->idt_major);
 499 
 500                 if (ret != 0) {
 501                         lx_err(gettext("%s%s) failed: %s\n"),
 502                             "lx_ioctl_init(): modctl(MODGETMAJBIND, ",
 503                             idt->idt_driver, strerror(errno));
 504                         lx_err(gettext("%s: %s translator disabled for: %s\n"),
 505                             "lx_ioctl_init()", "ioctl", idt->idt_driver);
 506                         idt->idt_major = (major_t)-1;
 507                 }
 508         }
 509 
 510         /* Create the interface name table */
 511         if (ifname_scan() != 0)
 512                 lx_err("lx_ioctl_init(): ifname_scan() failed\n");
 513 
 514         return (0);
 515 }
 516 
 517 static ioc_cmd_translator_t *
 518 lx_ioctl_find_ict_cmd(ioc_cmd_translator_t *ict, int cmd)
 519 {
 520         assert(ict != NULL);
 521         while ((ict != NULL) && (ict->ict_func != NULL)) {
 522                 if (cmd == ict->ict_lx_cmd)
 523                         return (ict);
 524                 ict++;
 525         }
 526         return (NULL);
 527 }
 528 
 529 /*
 530  * Main entry point for the ioctl translater.
 531  */
 532 int
 533 lx_ioctl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
 534 {
 535         int                     fd = (int)p1;
 536         int                     cmd = (int)p2;
 537         intptr_t                arg = (uintptr_t)p3;
 538         struct stat             stat;
 539         ioc_cmd_translator_t    *ict = NULL;
 540         ioc_errno_translator_t  *iet = NULL;
 541         major_t                 fd_major;
 542         int                     i, ret;
 543 
 544         if (fstat(fd, &stat) != 0) {
 545                 lx_ioctl_msg(fd, cmd, NULL, NULL,
 546                     "lx_ioctl(): fstat() failed");
 547 
 548                 /*
 549                  * Linux ioctl(2) is only documented to return EBADF, EFAULT,
 550                  * EINVAL or ENOTTY.
 551                  *
 552                  * EINVAL is documented to be "Request or argp is not valid",
 553                  * so it's reasonable to force any errno that's not EBADF,
 554                  * EFAULT or ENOTTY to be EINVAL.
 555                  */
 556                 if ((errno != EBADF) && (errno != EFAULT) && (errno != ENOTTY))
 557                         errno = EINVAL;
 558 
 559                 return (-errno);        /* errno already set. */
 560         }
 561 
 562         switch (stat.st_mode & S_IFMT) {
 563         default:
 564                 break;
 565         case S_IFREG:
 566                 /* Use file translators. */
 567                 ict = ioc_translators_file;
 568                 break;
 569 
 570         case S_IFSOCK:
 571                 /* Use socket translators. */
 572                 ict = ioc_translators_sock;
 573                 break;
 574 
 575         case S_IFIFO:
 576                 /* Use fifo translators. */
 577                 ict = ioc_translators_fifo;
 578                 break;
 579 
 580         case S_IFCHR:
 581                 fd_major = getmajor(stat.st_rdev);
 582 
 583                 /*
 584                  * Look through all the device translators to see if there
 585                  * is one for this device.
 586                  */
 587                 for (i = 0; ioc_translators_dev[i] != NULL; i++) {
 588                         if (fd_major != ioc_translators_dev[i]->idt_major)
 589                                 continue;
 590 
 591                         /* We found a translator for this device. */
 592                         ict = ioc_translators_dev[i]->idt_cmds;
 593                         break;
 594                 }
 595                 break;
 596         }
 597 
 598         /*
 599          * Search the selected translator group to see if we have a
 600          * translator for this specific command.
 601          */
 602         if ((ict != NULL) &&
 603             ((ict = lx_ioctl_find_ict_cmd(ict, cmd)) != NULL)) {
 604                 /* We found a translator for this command, invoke it. */
 605                 lx_ioctl_msg(fd, cmd, ict->ict_lx_cmd_str, &stat,
 606                     "lx_ioctl(): emulating ioctl");
 607 
 608                 ret = ict->ict_func(fd, &stat, ict->ict_cmd, ict->ict_cmd_str,
 609                     arg);
 610 
 611                 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
 612                     (ret != -ENOTTY))
 613                         ret = -EINVAL;
 614 
 615                 return (ret);
 616         }
 617 
 618         /*
 619          * If we didn't find a file or device translator for this
 620          * command then try to find a filesystem translator for
 621          * this command.
 622          */
 623         for (i = 0; ioc_translators_fs[i] != NULL; i++) {
 624                 if (strcmp(stat.st_fstype,
 625                     ioc_translators_fs[i]->ift_filesystem) != 0)
 626                         continue;
 627 
 628                 /* We found a translator for this filesystem. */
 629                 ict = ioc_translators_fs[i]->ift_cmds;
 630                 break;
 631         }
 632 
 633         /*
 634          * Search the selected translator group to see if we have a
 635          * translator for this specific command.
 636          */
 637         if ((ict != NULL) &&
 638             ((ict = lx_ioctl_find_ict_cmd(ict, cmd)) != NULL)) {
 639                 /* We found a translator for this command, invoke it. */
 640                 lx_ioctl_msg(fd, cmd, ict->ict_lx_cmd_str, &stat,
 641                     "lx_ioctl(): emulating ioctl");
 642                 ret = ict->ict_func(fd, &stat, ict->ict_cmd, ict->ict_cmd_str,
 643                     arg);
 644 
 645                 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
 646                     (ret != -ENOTTY))
 647                         ret = -EINVAL;
 648 
 649                 return (ret);
 650         }
 651 
 652         /*
 653          * No translator for this ioctl was found.
 654          * Check if there is an errno translator.
 655          */
 656         for (iet = ioc_translators_errno; iet->iet_lx_cmd_str != NULL; iet++) {
 657                 if (cmd != iet->iet_lx_cmd)
 658                         continue;
 659 
 660                 /* We found a an errno translator for this ioctl. */
 661                 lx_ioctl_msg(fd, cmd, iet->iet_lx_cmd_str, &stat,
 662                     "lx_ioctl(): emulating errno");
 663 
 664                 ret = -iet->iet_errno;
 665 
 666                 if ((ret < 0) && (ret != -EBADF) && (ret != -EFAULT) &&
 667                     (ret != -ENOTTY))
 668                         ret = -EINVAL;
 669 
 670                 return (ret);
 671         }
 672 
 673         lx_ioctl_msg(fd, cmd, NULL, &stat,
 674             "lx_ioctl(): unsupported linux ioctl");
 675         lx_unsupported(gettext("lx_ioctl(): unsupported linux ioctl (%d)"),
 676             cmd);
 677         return (-EINVAL);
 678 }
 679 
 680 
 681 /*
 682  * Ioctl translator functions.
 683  */
 684 /*
 685  * Used by translators that want to explicitly return EINVAL for an
 686  * ioctl(2) instead of having the translation framework do it implicitly.
 687  * This allows us to indicate which unsupported ioctl(2)s should not
 688  * trigger a SIGSYS when running in LX_STRICT mode.
 689  */
 690 /* ARGSUSED */
 691 static int
 692 ict_einval(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 693 {
 694         return (-EINVAL);
 695 }
 696 
 697 static int
 698 /*ARGSUSED*/
 699 ict_pass(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 700 {
 701         int ret;
 702 
 703         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 704             fd, cmd, cmd_str);
 705         ret = ioctl(fd, cmd, arg);
 706         return (ret < 0 ? -errno : ret);
 707 }
 708 
 709 static int
 710 /*ARGSUSED*/
 711 ict_tcsbrkp(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 712 {
 713         int ret, dur = 0;
 714 
 715         assert(cmd == LX_TCSBRKP);
 716         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 717             fd, TCSBRK, "TCSBRK");
 718         ret = ioctl(fd, TCSBRK, (intptr_t)&dur);
 719         return (ret < 0 ? -errno : ret);
 720 }
 721 
 722 static int
 723 /*ARGSUSED*/
 724 ict_sioifoob(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 725 {
 726         int req, *reqp = (int *)arg;
 727         int len, val;
 728 
 729         assert(cmd == SIOCATMARK);
 730 
 731         if (uucopy(reqp, &req, sizeof (req)) != 0)
 732                 return (-errno);
 733 
 734         len = sizeof (val);
 735 
 736         /*
 737          * Linux expects a SIOCATMARK of a UDP socket to return EINVAL, while
 738          * Solaris allows it.
 739          */
 740         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &len) < 0) {
 741                 lx_debug("ict_siofmark: getsockopt failed, errno %d", errno);
 742                 return (-EINVAL);
 743         }
 744 
 745         if ((len != sizeof (val)) || (val != SOCK_STREAM))
 746                 return (-EINVAL);
 747 
 748         if (ioctl(fd, cmd, &req) < 0)
 749                 return (-errno);
 750 
 751         if (uucopy(&req, reqp, sizeof (req)) != 0)
 752                 return (-errno);
 753 
 754         return (0);
 755 }
 756 
 757 static int
 758 /*ARGSUSED*/
 759 ict_sioifreq(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 760 {
 761         struct ifreq req, *reqp = (struct ifreq *)arg;
 762 
 763         assert(cmd == SIOCGIFFLAGS || cmd == SIOCSIFFLAGS ||
 764             cmd == SIOCGIFADDR || cmd == SIOCSIFADDR ||
 765             cmd == SIOCGIFDSTADDR || cmd == SIOCSIFDSTADDR ||
 766             cmd == SIOCGIFBRDADDR || cmd == SIOCSIFBRDADDR ||
 767             cmd == SIOCGIFNETMASK || cmd == SIOCSIFNETMASK ||
 768             cmd == SIOCGIFMETRIC || cmd == SIOCSIFMETRIC ||
 769             cmd == SIOCGIFMTU || cmd == SIOCSIFMTU);
 770 
 771         /* Copy in the data */
 772         if (uucopy(reqp, &req, sizeof (struct ifreq)) != 0)
 773                 return (-errno);
 774 
 775         if (ifname_from_linux(req.ifr_name) < 0)
 776                 return (-EINVAL);
 777 
 778         lx_debug("\tioctl(%d, 0x%x - %s, %.14s",
 779             fd, cmd, cmd_str, req.ifr_name);
 780 
 781         if (ioctl(fd, cmd, &req) < 0)
 782                 return (-errno);
 783 
 784         if (ifname_from_solaris(req.ifr_name) < 0)
 785                 return (-EINVAL);
 786 
 787         /* Copy out the data */
 788         if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
 789                 return (-errno);
 790 
 791         return (0);
 792 }
 793 
 794 static int
 795 /*ARGSUSED*/
 796 ict_siocgifconf(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
 797 {
 798         struct ifconf   conf, *confp = (struct ifconf *)arg;
 799         int             i, ifcount, ret;
 800 
 801         assert(cmd == LX_SIOCGIFCONF);
 802 
 803         /* Copy in the data. */
 804         if (uucopy(confp, &conf, sizeof (conf)) != 0)
 805                 return (-errno);
 806 
 807         if (conf.ifc_len == 0) {
 808                 /* They want to know how many interfaces there are. */
 809                 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
 810                     fd, SIOCGIFNUM, "SIOCGIFNUM");
 811                 if (ioctl(fd, SIOCGIFNUM, (intptr_t)&ifcount) < 0)
 812                         return (-errno);
 813                 conf.ifc_len = ifcount * sizeof (struct ifreq);
 814 
 815                 /* Check if we're done. */
 816                 if (conf.ifc_buf == NULL) {
 817                         /* Copy out the data. */
 818                         if (uucopy(&conf, confp, sizeof (conf)) != 0)
 819                                 return (-errno);
 820                         return (0);
 821                 }
 822         }
 823 
 824         /* Get interface configuration list. */
 825         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGIFCONF, "SIOCGIFCONF");
 826         ret = ioctl(fd, SIOCGIFCONF, &conf);
 827         if (ret < 0)
 828                 return (-errno);
 829 
 830         /* Rename interfaces to linux */
 831         for (i = 0; i < conf.ifc_len / sizeof (struct ifreq); i++)
 832                 if (ifname_from_solaris(conf.ifc_req[i].ifr_name) < 0)
 833                         return (-EINVAL);
 834 
 835         /* Copy out the data */
 836         if (uucopy(&conf, confp, sizeof (conf)) != 0)
 837                 return (-errno);
 838 
 839         return (0);
 840 }
 841 
 842 static int
 843 /*ARGSUSED*/
 844 ict_siocifhwaddr(int fd, struct stat *stat, int cmd, char *cmd_str,
 845     intptr_t arg)
 846 {
 847         struct ifreq req, *reqp = (struct ifreq *)arg;
 848         struct arpreq arpreq;
 849 
 850         assert(cmd == LX_SIOCGIFHWADDR || cmd == LX_SIOCSIFHWADDR);
 851 
 852         /* Copy in the data */
 853         if (uucopy(reqp, &req, sizeof (struct ifreq)) != 0)
 854                 return (-errno);
 855 
 856         lx_debug("\tioctl(%d, 0x%x - %s, lx %.14s)",
 857             fd, cmd,
 858             (cmd == LX_SIOCGIFHWADDR) ? "SIOCGIFHWADDR" : "SIOCSIFHWADDR",
 859             req.ifr_name);
 860 
 861         /*
 862          * We're not going to support SIOCSIFHWADDR, but we need to be
 863          * able to check the result of the uucopy first to see if the command
 864          * should have returned EFAULT.
 865          */
 866         if (cmd == LX_SIOCSIFHWADDR) {
 867                 lx_unsupported(gettext(
 868                     "lx_ioctl(): unsupported linux ioctl: %s"),
 869                     "SIOCSIFHWADDR");
 870                 return (-EINVAL);
 871         }
 872 
 873         if (strcmp(req.ifr_name, "lo") == 0 ||
 874             strncmp(req.ifr_name, "lo:", 3) == 0) {
 875                 /* Abuse ifr_addr for linux ifr_hwaddr */
 876                 bzero(&req.ifr_addr, sizeof (struct sockaddr));
 877                 req.ifr_addr.sa_family = LX_ARPHRD_LOOPBACK;
 878 
 879                 /* Copy out the data */
 880                 if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
 881                         return (-errno);
 882 
 883                 return (0);
 884         }
 885 
 886         if (ifname_from_linux(req.ifr_name) < 0)
 887                 return (-EINVAL);
 888 
 889         lx_debug("\tioctl(%d, 0x%x - %s, %.14s)",
 890             fd, SIOCGIFADDR, "SIOCGIFADDR", req.ifr_name);
 891 
 892         if (ioctl(fd, SIOCGIFADDR, &req) < 0)
 893                 return (-errno);
 894 
 895         bcopy(&req.ifr_addr, &arpreq.arp_pa, sizeof (struct sockaddr));
 896 
 897         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, SIOCGARP, "SIOCGARP");
 898 
 899         if (ioctl(fd, SIOCGARP, &arpreq) < 0)
 900                 return (-errno);
 901 
 902         if (ifname_from_solaris(req.ifr_name) < 0)
 903                 return (-EINVAL);
 904 
 905         /* Abuse ifr_addr for linux ifr_hwaddr */
 906         bcopy(&arpreq.arp_ha, &req.ifr_addr, sizeof (struct sockaddr));
 907         if (strncmp(req.ifr_name, "eth", 3) == 0)
 908                 req.ifr_addr.sa_family = LX_ARPHRD_ETHER;
 909         else
 910                 req.ifr_addr.sa_family = LX_ARPHRD_VOID;
 911 
 912         /* Copy out the data */
 913         if (uucopy(&req, reqp, sizeof (struct ifreq)) != 0)
 914                 return (-errno);
 915 
 916         return (0);
 917 }
 918 
 919 static void
 920 l2s_termios(struct lx_termios *l_tios, struct termios *s_tios)
 921 {
 922         assert((l_tios != NULL) && (s_tios != NULL));
 923 
 924         bzero(s_tios, sizeof (*s_tios));
 925 
 926         s_tios->c_iflag = l_tios->c_iflag;
 927         s_tios->c_oflag = l_tios->c_oflag;
 928         s_tios->c_cflag = l_tios->c_cflag;
 929 
 930         s_tios->c_lflag = l_tios->c_lflag;
 931         if (s_tios->c_lflag & ICANON) {
 932                 s_tios->c_cc[VEOF] = l_tios->c_cc[LX_VEOF];
 933                 s_tios->c_cc[VEOL] = l_tios->c_cc[LX_VEOL];
 934         } else {
 935                 s_tios->c_cc[VMIN] = l_tios->c_cc[LX_VMIN];
 936                 s_tios->c_cc[VTIME] = l_tios->c_cc[LX_VTIME];
 937         }
 938 
 939         s_tios->c_cc[VEOL2] = l_tios->c_cc[LX_VEOL2];
 940         s_tios->c_cc[VERASE] = l_tios->c_cc[LX_VERASE];
 941         s_tios->c_cc[VKILL] = l_tios->c_cc[LX_VKILL];
 942         s_tios->c_cc[VREPRINT] = l_tios->c_cc[LX_VREPRINT];
 943         s_tios->c_cc[VLNEXT] = l_tios->c_cc[LX_VLNEXT];
 944         s_tios->c_cc[VWERASE] = l_tios->c_cc[LX_VWERASE];
 945         s_tios->c_cc[VINTR] = l_tios->c_cc[LX_VINTR];
 946         s_tios->c_cc[VQUIT] = l_tios->c_cc[LX_VQUIT];
 947         s_tios->c_cc[VSWTCH] = l_tios->c_cc[LX_VSWTC];
 948         s_tios->c_cc[VSTART] = l_tios->c_cc[LX_VSTART];
 949         s_tios->c_cc[VSTOP] = l_tios->c_cc[LX_VSTOP];
 950         s_tios->c_cc[VSUSP] = l_tios->c_cc[LX_VSUSP];
 951         s_tios->c_cc[VDISCARD] = l_tios->c_cc[LX_VDISCARD];
 952 }
 953 
 954 static void
 955 l2s_termio(struct lx_termio *l_tio, struct termio *s_tio)
 956 {
 957         assert((l_tio != NULL) && (s_tio != NULL));
 958 
 959         bzero(s_tio, sizeof (*s_tio));
 960 
 961         s_tio->c_iflag = l_tio->c_iflag;
 962         s_tio->c_oflag = l_tio->c_oflag;
 963         s_tio->c_cflag = l_tio->c_cflag;
 964 
 965         s_tio->c_lflag = l_tio->c_lflag;
 966         if (s_tio->c_lflag & ICANON) {
 967                 s_tio->c_cc[VEOF] = l_tio->c_cc[LX_VEOF];
 968         } else {
 969                 s_tio->c_cc[VMIN] = l_tio->c_cc[LX_VMIN];
 970                 s_tio->c_cc[VTIME] = l_tio->c_cc[LX_VTIME];
 971         }
 972 
 973         s_tio->c_cc[VINTR] = l_tio->c_cc[LX_VINTR];
 974         s_tio->c_cc[VQUIT] = l_tio->c_cc[LX_VQUIT];
 975         s_tio->c_cc[VERASE] = l_tio->c_cc[LX_VERASE];
 976         s_tio->c_cc[VKILL] = l_tio->c_cc[LX_VKILL];
 977         s_tio->c_cc[VSWTCH] = l_tio->c_cc[LX_VSWTC];
 978 }
 979 
 980 static void
 981 termios2lx_cc(struct lx_termios *l_tios, struct lx_cc *lio)
 982 {
 983         assert((l_tios != NULL) && (lio != NULL));
 984 
 985         bzero(lio, sizeof (*lio));
 986 
 987         lio->veof = l_tios->c_cc[LX_VEOF];
 988         lio->veol = l_tios->c_cc[LX_VEOL];
 989         lio->vmin = l_tios->c_cc[LX_VMIN];
 990         lio->vtime = l_tios->c_cc[LX_VTIME];
 991 }
 992 
 993 static void
 994 termio2lx_cc(struct lx_termio *l_tio, struct lx_cc *lio)
 995 {
 996         assert((l_tio != NULL) && (lio != NULL));
 997 
 998         bzero(lio, sizeof (*lio));
 999 
1000         lio->veof = l_tio->c_cc[LX_VEOF];
1001         lio->veol = 0;
1002         lio->vmin = l_tio->c_cc[LX_VMIN];
1003         lio->vtime = l_tio->c_cc[LX_VTIME];
1004 }
1005 
1006 static void
1007 s2l_termios(struct termios *s_tios, struct lx_termios *l_tios)
1008 {
1009         assert((s_tios != NULL) && (l_tios != NULL));
1010 
1011         bzero(l_tios, sizeof (*l_tios));
1012 
1013         l_tios->c_iflag = s_tios->c_iflag;
1014         l_tios->c_oflag = s_tios->c_oflag;
1015         l_tios->c_cflag = s_tios->c_cflag;
1016         l_tios->c_lflag = s_tios->c_lflag;
1017 
1018         if (s_tios->c_lflag & ICANON) {
1019                 l_tios->c_cc[LX_VEOF] = s_tios->c_cc[VEOF];
1020                 l_tios->c_cc[LX_VEOL] = s_tios->c_cc[VEOL];
1021         } else {
1022                 l_tios->c_cc[LX_VMIN] = s_tios->c_cc[VMIN];
1023                 l_tios->c_cc[LX_VTIME] = s_tios->c_cc[VTIME];
1024         }
1025 
1026         l_tios->c_cc[LX_VEOL2] = s_tios->c_cc[VEOL2];
1027         l_tios->c_cc[LX_VERASE] = s_tios->c_cc[VERASE];
1028         l_tios->c_cc[LX_VKILL] = s_tios->c_cc[VKILL];
1029         l_tios->c_cc[LX_VREPRINT] = s_tios->c_cc[VREPRINT];
1030         l_tios->c_cc[LX_VLNEXT] = s_tios->c_cc[VLNEXT];
1031         l_tios->c_cc[LX_VWERASE] = s_tios->c_cc[VWERASE];
1032         l_tios->c_cc[LX_VINTR] = s_tios->c_cc[VINTR];
1033         l_tios->c_cc[LX_VQUIT] = s_tios->c_cc[VQUIT];
1034         l_tios->c_cc[LX_VSWTC] = s_tios->c_cc[VSWTCH];
1035         l_tios->c_cc[LX_VSTART] = s_tios->c_cc[VSTART];
1036         l_tios->c_cc[LX_VSTOP] = s_tios->c_cc[VSTOP];
1037         l_tios->c_cc[LX_VSUSP] = s_tios->c_cc[VSUSP];
1038         l_tios->c_cc[LX_VDISCARD] = s_tios->c_cc[VDISCARD];
1039 }
1040 
1041 static void
1042 s2l_termio(struct termio *s_tio, struct lx_termio *l_tio)
1043 {
1044         assert((s_tio != NULL) && (l_tio != NULL));
1045 
1046         bzero(l_tio, sizeof (*l_tio));
1047 
1048         l_tio->c_iflag = s_tio->c_iflag;
1049         l_tio->c_oflag = s_tio->c_oflag;
1050         l_tio->c_cflag = s_tio->c_cflag;
1051         l_tio->c_lflag = s_tio->c_lflag;
1052 
1053         if (s_tio->c_lflag & ICANON) {
1054                 l_tio->c_cc[LX_VEOF] = s_tio->c_cc[VEOF];
1055         } else {
1056                 l_tio->c_cc[LX_VMIN] = s_tio->c_cc[VMIN];
1057                 l_tio->c_cc[LX_VTIME] = s_tio->c_cc[VTIME];
1058         }
1059 
1060         l_tio->c_cc[LX_VINTR] = s_tio->c_cc[VINTR];
1061         l_tio->c_cc[LX_VQUIT] = s_tio->c_cc[VQUIT];
1062         l_tio->c_cc[LX_VERASE] = s_tio->c_cc[VERASE];
1063         l_tio->c_cc[LX_VKILL] = s_tio->c_cc[VKILL];
1064         l_tio->c_cc[LX_VSWTC] = s_tio->c_cc[VSWTCH];
1065 }
1066 
1067 static int
1068 /*ARGSUSED*/
1069 ict_tcsets(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1070 {
1071         struct lx_termios       l_tios, *l_tiosp = (struct lx_termios *)arg;
1072         struct termios          s_tios;
1073         struct lx_cc            lio;
1074         int                     ldlinux, ret;
1075 
1076         assert(cmd == TCSETS || cmd == TCSETSW || cmd == TCSETSF);
1077 
1078         /* Copy in the data. */
1079         if (uucopy(l_tiosp, &l_tios, sizeof (l_tios)) != 0)
1080                 return (-errno);
1081 
1082         /*
1083          * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1084          * ldlinux strmod.  So make sure the module exists on the
1085          * target stream before we invoke the ioctl.
1086          */
1087         if ((ldlinux = ldlinux_check(fd)) < 0)
1088                 return (ldlinux);
1089 
1090         if (ldlinux == 1) {
1091                 termios2lx_cc(&l_tios, &lio);
1092                 if (ioctl_istr(fd, TIOCSETLD, "TIOCSETLD",
1093                     &lio, sizeof (lio)) < 0)
1094                         return (-errno);
1095         }
1096 
1097         l2s_termios(&l_tios, &s_tios);
1098         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1099             fd, cmd, cmd_str);
1100         ret = ioctl(fd, cmd, (intptr_t)&s_tios);
1101         return ((ret < 0) ? -errno : ret);
1102 }
1103 
1104 static int
1105 /*ARGSUSED*/
1106 ict_tcseta(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1107 {
1108         struct lx_termio        l_tio, *l_tiop = (struct lx_termio *)arg;
1109         struct termio           s_tio;
1110         struct lx_cc            lio;
1111         int                     ldlinux, ret;
1112 
1113         assert(cmd == TCSETA || cmd == TCSETAW || cmd == TCSETAF);
1114 
1115         /* Copy in the data. */
1116         if (uucopy(l_tiop, &l_tio, sizeof (l_tio)) != 0)
1117                 return (-errno);
1118 
1119         /*
1120          * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1121          * ldlinux strmod.  So make sure the module exists on the
1122          * target stream before we invoke the ioctl.
1123          */
1124         if ((ldlinux = ldlinux_check(fd)) < 0)
1125                 return (ldlinux);
1126 
1127         if (ldlinux == 1) {
1128                 termio2lx_cc(&l_tio, &lio);
1129                 if (ioctl_istr(fd, TIOCSETLD, "TIOCSETLD",
1130                     &lio, sizeof (lio)) < 0)
1131                         return (-errno);
1132         }
1133 
1134         l2s_termio(&l_tio, &s_tio);
1135         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1136             fd, cmd, cmd_str);
1137         ret = ioctl(fd, cmd, (intptr_t)&s_tio);
1138         return ((ret < 0) ? -errno : ret);
1139 }
1140 
1141 /*
1142  * The Solaris TIOCGPGRP ioctl does not have exactly the same semantics as
1143  * the Linux one. To mimic Linux semantics we have to do some extra work
1144  * normally done by the Solaris version of tcgetpgrp().
1145  */
1146 static int
1147 /*ARGSUSED*/
1148 ict_tiocgpgrp(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1149 {
1150         pid_t   ttysid, mysid;
1151         int     ret;
1152 
1153         assert(cmd == LX_TIOCGPGRP);
1154 
1155         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1156             fd, TIOCGSID, "TIOCGSID");
1157         if (ioctl(fd, TIOCGSID, (intptr_t)&ttysid) < 0)
1158                 return (-errno);
1159         if ((mysid = getsid(0)) < 0)
1160                 return (-errno);
1161         if (mysid != ttysid)
1162                 return (-ENOTTY);
1163 
1164         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1165             fd, TIOCGPGRP, "TIOCGPGRP");
1166         ret = ioctl(fd, TIOCGPGRP, arg);
1167         return ((ret < 0) ? -errno : ret);
1168 }
1169 
1170 static int
1171 /*ARGSUSED*/
1172 ict_sptlock(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1173 {
1174         assert(cmd == LX_TIOCSPTLCK);
1175 
1176         /*
1177          * The success/fail return values are different between Linux
1178          * and Solaris.   Linux expects 0 or -1.  Solaris can return
1179          * positive number on success.
1180          */
1181         if (ioctl_istr(fd, UNLKPT, "UNLKPT", NULL, 0) < 0)
1182                 return (-errno);
1183         return (0);
1184 }
1185 
1186 static int
1187 /*ARGSUSED*/
1188 ict_gptn(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1189 {
1190         int             ptyno, *ptynop = (int *)arg;
1191         pt_own_t        pto;
1192 
1193         assert(cmd == LX_TIOCGPTN);
1194         assert(getmajor(stat->st_rdev) == ioc_translator_ptm.idt_major);
1195 
1196         /* This operation is only valid for the lx_ptm device. */
1197         ptyno = LX_PTM_DEV_TO_PTS(stat->st_rdev);
1198 
1199         /*
1200          * We'd like to just use grantpt() directly, but we can't since
1201          * it assumes the fd node that's passed to it is a ptm node,
1202          * and in our case it's an lx_ptm node.  It also relies on
1203          * naming services to get the current process group name.
1204          * Hence we have to invoke the OWNERPT ioctl directly here.
1205          */
1206         pto.pto_ruid = getuid();
1207         pto.pto_rgid = getgid();
1208         if (ioctl_istr(fd, OWNERPT, "OWNERPT", &pto, sizeof (pto)) != 0)
1209                 return (-EACCES);
1210 
1211         /* Copy out the data. */
1212         if (uucopy(&ptyno, ptynop, sizeof (ptyno)) != 0)
1213                 return (-errno);
1214 
1215         return (0);
1216 }
1217 
1218 static int
1219 /*ARGSUSED*/
1220 ict_tiocgwinsz(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1221 {
1222         struct winsize  winsize, *winsizep = (struct winsize *)arg;
1223 
1224         assert(cmd == LX_TIOCGWINSZ);
1225 
1226         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, TIOCGWINSZ, "TIOCGWINSZ");
1227         if (ioctl(fd, TIOCGWINSZ, arg) >= 0)
1228                 return (0);
1229         if (errno != EINVAL)
1230                 return (-errno);
1231 
1232         bzero(&winsize, sizeof (winsize));
1233         if (uucopy(&winsize, winsizep, sizeof (winsize)) != 0)
1234                 return (-errno);
1235 
1236         return (0);
1237 }
1238 
1239 static int
1240 /*ARGSUSED*/
1241 ict_tcgets_emulate(int fd, struct stat *stat,
1242     int cmd, char *cmd_str, intptr_t arg)
1243 {
1244         struct lx_termios       l_tios, *l_tiosp = (struct lx_termios *)arg;
1245         struct termios          s_tios;
1246 
1247         assert(cmd == LX_TCGETS);
1248 
1249         if (syscall(SYS_brand, B_TTYMODES, &s_tios) < 0)
1250                 return (-errno);
1251 
1252         /* Now munge the data to how Linux wants it. */
1253         s2l_termios(&s_tios, &l_tios);
1254         if (uucopy(&l_tios, l_tiosp, sizeof (l_tios)) != 0)
1255                 return (-errno);
1256 
1257         return (0);
1258 }
1259 
1260 static int
1261 /*ARGSUSED*/
1262 ict_tcgets_native(int fd, struct stat *stat,
1263     int cmd, char *cmd_str, intptr_t arg)
1264 {
1265         struct lx_termios       l_tios, *l_tiosp = (struct lx_termios *)arg;
1266         struct termios          s_tios;
1267         struct lx_cc            lio;
1268         int                     ldlinux;
1269 
1270         assert(cmd == LX_TCGETS);
1271 
1272         if ((ldlinux = ldlinux_check(fd)) < 0)
1273                 return (ldlinux);
1274 
1275         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1276             fd, TCGETS, "TCGETS");
1277         if (ioctl(fd, TCGETS, (intptr_t)&s_tios) < 0)
1278                 return (-errno);
1279 
1280         /* Now munge the data to how Linux wants it. */
1281         s2l_termios(&s_tios, &l_tios);
1282 
1283         /*
1284          * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1285          * ldlinux strmod.  So make sure the module exists on the
1286          * target stream before we invoke the ioctl.
1287          */
1288         if (ldlinux != 0) {
1289                 if (ioctl_istr(fd, TIOCGETLD, "TIOCGETLD",
1290                     &lio, sizeof (lio)) < 0)
1291                         return (-errno);
1292 
1293                 l_tios.c_cc[LX_VEOF] = lio.veof;
1294                 l_tios.c_cc[LX_VEOL] = lio.veol;
1295                 l_tios.c_cc[LX_VMIN] = lio.vmin;
1296                 l_tios.c_cc[LX_VTIME] = lio.vtime;
1297         }
1298 
1299         /* Copy out the data. */
1300         if (uucopy(&l_tios, l_tiosp, sizeof (l_tios)) != 0)
1301                 return (-errno);
1302 
1303         return (0);
1304 }
1305 
1306 static int
1307 /*ARGSUSED*/
1308 ict_tcgeta(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1309 {
1310         struct lx_termio        l_tio, *l_tiop = (struct lx_termio *)arg;
1311         struct termio           s_tio;
1312         struct lx_cc            lio;
1313         int                     ldlinux;
1314 
1315         assert(cmd == LX_TCGETA);
1316 
1317         if ((ldlinux = ldlinux_check(fd)) < 0)
1318                 return (ldlinux);
1319 
1320         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1321             fd, TCGETA, "TCGETA");
1322         if (ioctl(fd, TCGETA, (intptr_t)&s_tio) < 0)
1323                 return (-errno);
1324 
1325         /* Now munge the data to how Linux wants it. */
1326         s2l_termio(&s_tio, &l_tio);
1327 
1328         /*
1329          * The TIOCSETLD/TIOCGETLD ioctls are only supported by the
1330          * ldlinux strmod.  So make sure the module exists on the
1331          * target stream before we invoke the ioctl.
1332          */
1333         if (ldlinux != 0) {
1334                 if (ioctl_istr(fd, TIOCGETLD, "TIOCGETLD",
1335                     &lio, sizeof (lio)) < 0)
1336                         return (-errno);
1337 
1338                 l_tio.c_cc[LX_VEOF] = lio.veof;
1339                 l_tio.c_cc[LX_VMIN] = lio.vmin;
1340                 l_tio.c_cc[LX_VTIME] = lio.vtime;
1341         }
1342 
1343         /* Copy out the data. */
1344         if (uucopy(&l_tio, l_tiop, sizeof (l_tio)) != 0)
1345                 return (-errno);
1346 
1347         return (0);
1348 }
1349 
1350 static int
1351 /*ARGSUSED*/
1352 ict_tiocsctty(int fd, struct stat *stat, int cmd, char *cmd_str, intptr_t arg)
1353 {
1354         pid_t   mysid, ttysid;
1355 
1356         if ((mysid = getsid(0)) < 0)
1357                 return (-errno);
1358 
1359         /* Check if this fd is already our ctty. */
1360         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1361             fd, TIOCGSID, "TIOCGSID");
1362         if (ioctl(fd, TIOCGSID, (intptr_t)&ttysid) >= 0)
1363                 if (mysid == ttysid)
1364                         return (0);
1365 
1366         /*
1367          * Need to make sure we're a session leader, otherwise the
1368          * TIOCSCTTY ioctl will fail.
1369          */
1370         if (mysid != getpid())
1371                 (void) setpgrp();
1372 
1373         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1374             fd, TIOCSCTTY, "TIOCSCTTY");
1375         if (ioctl(fd, TIOCSCTTY, 0) < 0)
1376                 return (-errno);
1377         return (0);
1378 }
1379 
1380 /*
1381  * /dev/dsp ioctl translators and support
1382  */
1383 static int
1384 i_is_dsp_dev(int fd)
1385 {
1386         int minor;
1387 
1388         /*
1389          * This is a cloning device so we have to ask the driver
1390          * what kind of minor node this is.
1391          */
1392         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1393             fd, LXA_IOC_GETMINORNUM, "LXA_IOC_GETMINORNUM");
1394         if (ioctl(fd, LXA_IOC_GETMINORNUM, &minor) < 0)
1395                 return (-EINVAL);
1396         if (minor != LXA_MINORNUM_DSP)
1397                 return (-EINVAL);
1398         return (0);
1399 }
1400 
1401 static int
1402 /*ARGSUSED*/
1403 ict_oss_sndctl_dsp_reset(int fd, struct stat *stat,
1404     int cmd, char *cmd_str, intptr_t arg)
1405 {
1406         int err;
1407 
1408         /* Ioctl is only supported on dsp audio devices. */
1409         if ((err = i_is_dsp_dev(fd)) != 0)
1410                 return (err);
1411 
1412         /* Nothing to really do on Solaris. */
1413         return (0);
1414 }
1415 
1416 static void
1417 i_oss_fmt_str(char *buf, int buf_size, uint_t mask)
1418 {
1419         int i, first = 1;
1420 
1421         assert(buf != NULL);
1422 
1423         buf[0] = '\0';
1424         for (i = 0; oss_fmt_str[i].i2s_str != NULL; i++) {
1425                 if ((oss_fmt_str[i].i2s_int != mask) &&
1426                     ((oss_fmt_str[i].i2s_int & mask) == 0))
1427                         continue;
1428                 if (first)
1429                         first = 0;
1430                 else
1431                         (void) strlcat(buf, " | ", buf_size);
1432                 (void) strlcat(buf, oss_fmt_str[i].i2s_str, buf_size);
1433         }
1434 }
1435 
1436 static int
1437 /*ARGSUSED*/
1438 ict_oss_sndctl_dsp_getfmts(int fd, struct stat *stat,
1439     int cmd, char *cmd_str, intptr_t arg)
1440 {
1441         audio_info_t    sa_info;
1442         char            buf[MSGBUF];
1443         uint_t          *maskp = (uint_t *)arg;
1444         uint_t          mask = 0;
1445         int             i, amode, err;
1446 
1447         assert(cmd == LX_OSS_SNDCTL_DSP_GETFMTS);
1448 
1449         /* Ioctl is only supported on dsp audio devices. */
1450         if ((err = i_is_dsp_dev(fd)) != 0)
1451                 return (err);
1452 
1453         /* We need to know the access mode for the file. */
1454         if ((amode = fcntl(fd, F_GETFL)) < 0)
1455                 return (-EINVAL);
1456         amode &= O_ACCMODE;
1457         assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1458 
1459         /* Test to see what Linux oss formats the target device supports. */
1460         for (i = 0; oft_table[i].oft_oss_fmt != 0; i++) {
1461 
1462                 /* Initialize the mode request. */
1463                 AUDIO_INITINFO(&sa_info);
1464 
1465                 /* Translate a Linux oss format into Solaris settings. */
1466                 if ((amode == O_RDONLY) || (amode == O_RDWR)) {
1467                         sa_info.record.encoding = oft_table[i].oft_encoding;
1468                         sa_info.record.precision = oft_table[i].oft_precision;
1469                 }
1470                 if ((amode == O_WRONLY) || (amode == O_RDWR)) {
1471                         sa_info.play.encoding = oft_table[i].oft_encoding;
1472                         sa_info.play.precision = oft_table[i].oft_precision;
1473                 }
1474 
1475                 /* Send the request. */
1476                 lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1477                     fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1478                 if (ioctl(fd, AUDIO_SETINFO, &sa_info) < 0)
1479                         continue;
1480 
1481                 /* This Linux oss format is supported. */
1482                 mask |= oft_table[i].oft_oss_fmt;
1483         }
1484 
1485         if (lx_debug_enabled != 0) {
1486                 i_oss_fmt_str(buf, sizeof (buf), mask);
1487                 lx_debug("\toss formats supported = 0x%x (%s)", mask, buf);
1488         }
1489         if (uucopy(&mask, maskp, sizeof (mask)) != 0)
1490                 return (-errno);
1491         return (0);
1492 }
1493 
1494 static int
1495 /*ARGSUSED*/
1496 ict_oss_sndctl_dsp_setfmts(int fd, struct stat *stat,
1497     int cmd, char *cmd_str, intptr_t arg)
1498 {
1499         audio_info_t    sa_info;
1500         char            buf[MSGBUF];
1501         uint_t          *maskp = (uint_t *)arg;
1502         uint_t          mask;
1503         int             i, amode, err;
1504 
1505         assert(cmd == LX_OSS_SNDCTL_DSP_SETFMTS);
1506 
1507         /* Ioctl is only supported on dsp audio devices. */
1508         if ((err = i_is_dsp_dev(fd)) != 0)
1509                 return (err);
1510 
1511         if (uucopy(maskp, &mask, sizeof (mask)) != 0)
1512                 return (-errno);
1513 
1514         if (lx_debug_enabled != 0) {
1515                 i_oss_fmt_str(buf, sizeof (buf), mask);
1516                 lx_debug("\toss formats request = 0x%x (%s)", mask, buf);
1517         }
1518 
1519         if ((mask == (uint_t)-1) || (mask == 0)) {
1520                 lx_debug("\tXXX: possible oss formats query?");
1521                 return (-EINVAL);
1522         }
1523 
1524         /* Check if multiple format bits were specified. */
1525         if (!BIT_ONLYONESET(mask))
1526                 return (-EINVAL);
1527 
1528         /* Decode the oss format request into a native format. */
1529         for (i = 0; oft_table[i].oft_oss_fmt != 0; i++) {
1530                 if (oft_table[i].oft_oss_fmt == mask)
1531                         break;
1532         }
1533         if (oft_table[i].oft_oss_fmt == 0)
1534                 return (-EINVAL);
1535 
1536         /* We need to know the access mode for the file. */
1537         if ((amode = fcntl(fd, F_GETFL)) < 0)
1538                 return (-EINVAL);
1539         amode &= O_ACCMODE;
1540         assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1541 
1542         /* Initialize the mode request. */
1543         AUDIO_INITINFO(&sa_info);
1544 
1545         /* Translate the Linux oss request into a Solaris request. */
1546         if ((amode == O_RDONLY) || (amode == O_RDWR)) {
1547                 sa_info.record.encoding = oft_table[i].oft_encoding;
1548                 sa_info.record.precision = oft_table[i].oft_precision;
1549         }
1550         if ((amode == O_WRONLY) || (amode == O_RDWR)) {
1551                 sa_info.play.encoding = oft_table[i].oft_encoding;
1552                 sa_info.play.precision = oft_table[i].oft_precision;
1553         }
1554 
1555         /* Send the request. */
1556         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1557             fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1558         return ((ioctl(fd, AUDIO_SETINFO, &sa_info) < 0) ? -errno : 0);
1559 }
1560 
1561 static int
1562 /*ARGSUSED*/
1563 ict_oss_sndctl_dsp_channels(int fd, struct stat *stat,
1564     int cmd, char *cmd_str, intptr_t arg)
1565 {
1566         audio_info_t    sa_info;
1567         uint_t          *channelsp = (uint_t *)arg;
1568         uint_t          channels;
1569         int             amode, err;
1570 
1571         assert((cmd == LX_OSS_SNDCTL_DSP_CHANNELS) ||
1572             (cmd == LX_OSS_SNDCTL_DSP_STEREO));
1573 
1574         /* Ioctl is only supported on dsp audio devices. */
1575         if ((err = i_is_dsp_dev(fd)) != 0)
1576                 return (err);
1577 
1578         if (uucopy(channelsp, &channels, sizeof (channels)) != 0)
1579                 return (-errno);
1580 
1581         lx_debug("\toss %s request = 0x%x (%u)",
1582             (cmd == LX_OSS_SNDCTL_DSP_CHANNELS) ? "channel" : "stereo",
1583             channels, channels);
1584 
1585         if (channels == (uint_t)-1) {
1586                 lx_debug("\tXXX: possible channel/stereo query?");
1587                 return (-EINVAL);
1588         }
1589 
1590         if (cmd == LX_OSS_SNDCTL_DSP_STEREO) {
1591                 /*
1592                  * There doesn't seem to be any documentation for
1593                  * SNDCTL_DSP_STEREO.  Looking at source that uses or
1594                  * used this ioctl seems to indicate that the
1595                  * functionality provided by this ioctl has been
1596                  * subsumed by the SNDCTL_DSP_CHANNELS ioctl.  It
1597                  * seems that the only arguments ever passed to
1598                  * the SNDCTL_DSP_STEREO.  Ioctl are boolean values
1599                  * of '0' or '1'.  Hence we'll start out strict and
1600                  * only support those values.
1601                  *
1602                  * Some online forum discussions about this ioctl
1603                  * seemed to indicate that in case of success it
1604                  * returns the "stereo" setting (ie, either
1605                  * '0' for mono or '1' for stereo).
1606                  */
1607                 if ((channels != 0) && (channels != 1)) {
1608                         lx_debug("\tinvalid stereo request");
1609                         return (-EINVAL);
1610                 }
1611                 channels += 1;
1612         } else {
1613                 /* Limit the system to one or two channels. */
1614                 if ((channels != 1) && (channels != 2)) {
1615                         lx_debug("\tinvalid channel request");
1616                         return (-EINVAL);
1617                 }
1618         }
1619 
1620         /* We need to know the access mode for the file. */
1621         if ((amode = fcntl(fd, F_GETFL)) < 0)
1622                 return (-EINVAL);
1623         amode &= O_ACCMODE;
1624         assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1625 
1626         /* Initialize the channel request. */
1627         AUDIO_INITINFO(&sa_info);
1628 
1629         /* Translate the Linux oss request into a Solaris request. */
1630         if ((amode == O_RDONLY) || (amode == O_RDWR))
1631                 sa_info.record.channels = channels;
1632         if ((amode == O_WRONLY) || (amode == O_RDWR))
1633                 sa_info.play.channels = channels;
1634 
1635         /* Send the request. */
1636         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1637             fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1638         if (ioctl(fd, AUDIO_SETINFO, &sa_info) < 0)
1639                 return (-errno);
1640 
1641         if (cmd == LX_OSS_SNDCTL_DSP_STEREO)
1642                 return (channels - 1);
1643         return (0);
1644 }
1645 
1646 static int
1647 /*ARGSUSED*/
1648 ict_oss_sndctl_dsp_speed(int fd, struct stat *stat,
1649     int cmd, char *cmd_str, intptr_t arg)
1650 {
1651         audio_info_t    sa_info;
1652         uint_t          *speedp = (uint_t *)arg;
1653         uint_t          speed;
1654         int             amode, err;
1655 
1656         assert(cmd == LX_OSS_SNDCTL_DSP_SPEED);
1657 
1658         /* Ioctl is only supported on dsp audio devices. */
1659         if ((err = i_is_dsp_dev(fd)) != 0)
1660                 return (err);
1661 
1662         if (uucopy(speedp, &speed, sizeof (speed)) != 0)
1663                 return (-errno);
1664 
1665         lx_debug("\toss speed request = 0x%x (%u)", speed, speed);
1666 
1667         if (speed == (uint_t)-1) {
1668                 lx_debug("\tXXX: possible oss speed query?");
1669                 return (-EINVAL);
1670         }
1671 
1672         /* We need to know the access mode for the file. */
1673         if ((amode = fcntl(fd, F_GETFL)) < 0)
1674                 return (-EINVAL);
1675         amode &= O_ACCMODE;
1676         assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1677 
1678         /* Initialize the speed request. */
1679         AUDIO_INITINFO(&sa_info);
1680 
1681         /* Translate the Linux oss request into a Solaris request. */
1682         if ((amode == O_RDONLY) || (amode == O_RDWR))
1683                 sa_info.record.sample_rate = speed;
1684         if ((amode == O_WRONLY) || (amode == O_RDWR))
1685                 sa_info.play.sample_rate = speed;
1686 
1687         /* Send the request. */
1688         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1689             fd, AUDIO_SETINFO, "AUDIO_SETINFO");
1690         return ((ioctl(fd, AUDIO_SETINFO, &sa_info) < 0) ? -errno : 0);
1691 }
1692 
1693 static int
1694 /*ARGSUSED*/
1695 ict_oss_sndctl_dsp_getblksize(int fd, struct stat *stat,
1696     int cmd, char *cmd_str, intptr_t arg)
1697 {
1698         lxa_frag_info_t fi;
1699         uint_t          *blksizep = (uint_t *)arg;
1700         uint_t          blksize;
1701         int             err;
1702 
1703         assert(cmd == LX_OSS_SNDCTL_DSP_GETBLKSIZE);
1704 
1705         /* Ioctl is only supported on dsp audio devices. */
1706         if ((err = i_is_dsp_dev(fd)) != 0)
1707                 return (err);
1708 
1709         /* Query the current fragment count and size. */
1710         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1711             fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1712         if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1713                 return (-errno);
1714 
1715         blksize = fi.lxa_fi_size;
1716 
1717         if (uucopy(&blksize, blksizep, sizeof (blksize)) != 0)
1718                 return (-errno);
1719         return (0);
1720 }
1721 
1722 static int
1723 /*ARGSUSED*/
1724 ict_oss_sndctl_dsp_getspace(int fd, struct stat *stat,
1725     int cmd, char *cmd_str, intptr_t arg)
1726 {
1727         lx_oss_audio_buf_info_t *spacep = (lx_oss_audio_buf_info_t *)arg;
1728         lx_oss_audio_buf_info_t space;
1729         lxa_frag_info_t         fi;
1730         int                     err;
1731 
1732         assert((cmd == LX_OSS_SNDCTL_DSP_GETOSPACE) ||
1733             (cmd == LX_OSS_SNDCTL_DSP_GETISPACE));
1734 
1735         /* Ioctl is only supported on dsp audio devices. */
1736         if ((err = i_is_dsp_dev(fd)) != 0)
1737                 return (err);
1738 
1739         /* Query the current fragment count and size. */
1740         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1741             fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1742         if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1743                 return (-errno);
1744 
1745         /* Return the current fragment count and size. */
1746         space.fragstotal = fi.lxa_fi_cnt;
1747         space.fragsize = fi.lxa_fi_size;
1748 
1749         /*
1750          * We'll lie and tell applications that they can always write
1751          * out at least one fragment without blocking.
1752          */
1753         space.fragments = 1;
1754         space.bytes = space.fragsize;
1755 
1756         if (cmd == LX_OSS_SNDCTL_DSP_GETOSPACE)
1757                 lx_debug("\toss get output space result = ");
1758         if (cmd == LX_OSS_SNDCTL_DSP_GETISPACE)
1759                 lx_debug("\toss get input space result = ");
1760 
1761         lx_debug("\t\tbytes = 0x%x (%u), fragments = 0x%x (%u)",
1762             space.bytes, space.bytes, space.fragments, space.fragments);
1763         lx_debug("\t\tfragtotal = 0x%x (%u), fragsize = 0x%x (%u)",
1764             space.fragstotal, space.fragstotal,
1765             space.fragsize, space.fragsize);
1766 
1767         if (uucopy(&space, spacep, sizeof (space)) != 0)
1768                 return (-errno);
1769         return (0);
1770 }
1771 
1772 static int
1773 /*ARGSUSED*/
1774 ict_oss_sndctl_dsp_setfragment(int fd, struct stat *stat,
1775     int cmd, char *cmd_str, intptr_t arg)
1776 {
1777         lxa_frag_info_t fi;
1778         uint_t          *fraginfop = (uint_t *)arg;
1779         uint_t          fraginfo, frag_size, frag_cnt;
1780         int             err;
1781 
1782         assert(cmd == LX_OSS_SNDCTL_DSP_SETFRAGMENT);
1783 
1784         /* Ioctl is only supported on dsp audio devices. */
1785         if ((err = i_is_dsp_dev(fd)) != 0)
1786                 return (err);
1787 
1788         if (uucopy(fraginfop, &fraginfo, sizeof (fraginfo)) != 0)
1789                 return (-errno);
1790 
1791         /*
1792          * The argument to this ioctl is a 32-bit integer of the
1793          * format 0x MMMM SSSS where:
1794          *      SSSS - requests a fragment size of 2^SSSS
1795          *      MMMM - requests a maximum fragment count of 2^MMMM
1796          * if MMMM is 0x7fff then the application is requesting
1797          * no limits on the number of fragments.
1798          */
1799 
1800         frag_size = fraginfo & 0xffff;
1801         frag_cnt = fraginfo >> 16;
1802 
1803         lx_debug("\toss fragment request: "
1804             "power size = 0x%x (%u), power cnt = 0x%x (%u)",
1805             frag_size, frag_size, frag_cnt, frag_cnt);
1806 
1807         /* Limit the supported fragment size from 2^4 to 2^31. */
1808         if ((frag_size < 4) || (frag_size > 31))
1809                 return (-EINVAL);
1810 
1811         /* Limit the number of fragments from 2^1 to 2^32. */
1812         if (((frag_cnt < 1) || (frag_cnt > 32)) && (frag_cnt != 0x7fff))
1813                 return (-EINVAL);
1814 
1815         /* Expand the fragment values. */
1816         frag_size = 1 << frag_size;
1817         if ((frag_cnt == 32) || (frag_cnt == 0x7fff)) {
1818                 frag_cnt = UINT_MAX;
1819         } else {
1820                 frag_cnt = 1 << frag_cnt;
1821         }
1822 
1823         lx_debug("\toss fragment request: "
1824             "translated size = 0x%x (%u), translated cnt = 0x%x (%u)",
1825             frag_size, frag_size, frag_cnt, frag_cnt);
1826 
1827         fi.lxa_fi_size = frag_size;
1828         fi.lxa_fi_cnt = frag_cnt;
1829 
1830         /* Set the current fragment count and size. */
1831         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1832             fd, LXA_IOC_SET_FRAG_INFO, "LXA_IOC_SET_FRAG_INFO");
1833         return ((ioctl(fd, LXA_IOC_SET_FRAG_INFO, &fi) < 0) ? -errno : 0);
1834 }
1835 
1836 static int
1837 /*ARGSUSED*/
1838 ict_oss_sndctl_dsp_getcaps(int fd, struct stat *stat,
1839     int cmd, char *cmd_str, intptr_t arg)
1840 {
1841         uint_t  *capsp = (uint_t *)arg;
1842         uint_t  caps;
1843         int     err;
1844 
1845         assert(cmd == LX_OSS_SNDCTL_DSP_GETCAPS);
1846 
1847         /* Ioctl is only supported on dsp audio devices. */
1848         if ((err = i_is_dsp_dev(fd)) != 0)
1849                 return (err);
1850 
1851         /*
1852          * Report that we support mmap access
1853          * this is where things start to get fun.
1854          */
1855         caps = LX_OSS_DSP_CAP_MMAP | LX_OSS_DSP_CAP_TRIGGER;
1856 
1857         if (uucopy(&caps, capsp, sizeof (caps)) != 0)
1858                 return (-errno);
1859         return (0);
1860 }
1861 
1862 static int
1863 /*ARGSUSED*/
1864 ict_oss_sndctl_dsp_settrigger(int fd, struct stat *stat,
1865     int cmd, char *cmd_str, intptr_t arg)
1866 {
1867         uint_t          *triggerp = (uint_t *)arg;
1868         uint_t          trigger;
1869         int             err;
1870 
1871         assert(cmd == LX_OSS_SNDCTL_DSP_SETTRIGGER);
1872 
1873         /* Ioctl is only supported on dsp audio devices. */
1874         if ((err = i_is_dsp_dev(fd)) != 0)
1875                 return (err);
1876 
1877         if (uucopy(triggerp, &trigger, sizeof (trigger)) != 0)
1878                 return (-errno);
1879 
1880         lx_debug("\toss set trigger request = 0x%x (%u)",
1881             trigger, trigger);
1882 
1883         /* We only support two types of trigger requests. */
1884         if ((trigger != LX_OSS_PCM_DISABLE_OUTPUT) &&
1885             (trigger != LX_OSS_PCM_ENABLE_OUTPUT))
1886                 return (-EINVAL);
1887 
1888         /*
1889          * We only support triggers on devices open for write access,
1890          * but we don't need to check for that here since the driver will
1891          * verify this for us.
1892          */
1893 
1894         /* Send the trigger command to the audio device. */
1895         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1896             fd, LXA_IOC_MMAP_OUTPUT, "LXA_IOC_MMAP_OUTPUT");
1897         return ((ioctl(fd, LXA_IOC_MMAP_OUTPUT, &trigger) < 0) ? -errno : 0);
1898 }
1899 
1900 static int
1901 /*ARGSUSED*/
1902 ict_oss_sndctl_dsp_getoptr(int fd, struct stat *stat,
1903     int cmd, char *cmd_str, intptr_t arg)
1904 {
1905         static uint_t           bytes = 0;
1906         lx_oss_count_info_t     ci;
1907         lxa_frag_info_t         fi;
1908         audio_info_t            ai;
1909         int                     ptr, err;
1910 
1911         assert(cmd == LX_OSS_SNDCTL_DSP_GETOPTR);
1912 
1913         /* Ioctl is only supported on dsp audio devices. */
1914         if ((err = i_is_dsp_dev(fd)) != 0)
1915                 return (err);
1916 
1917         /* Query the current fragment size. */
1918         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1919             fd, LXA_IOC_GET_FRAG_INFO, "LXA_IOC_GET_FRAG_INFO");
1920         if (ioctl(fd, LXA_IOC_GET_FRAG_INFO, &fi) < 0)
1921                 return (-errno);
1922 
1923         /* Figure out how many samples have been played. */
1924         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1925             fd, AUDIO_GETINFO, "AUDIO_GETINFO");
1926         if (ioctl(fd, AUDIO_GETINFO, &ai) < 0)
1927                 return (-errno);
1928         ci.bytes = ai.play.samples + ai.record.samples;
1929 
1930         /*
1931          * Figure out how many fragments of audio have gone out since
1932          * the last call to this ioctl.
1933          */
1934         ci.blocks = (ci.bytes - bytes) / fi.lxa_fi_size;
1935         bytes = ci.bytes;
1936 
1937         /* Figure out the current fragment offset for mmap audio output. */
1938         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1939             fd, LXA_IOC_MMAP_PTR, "LXA_IOC_MMAP_PTR");
1940         if (ioctl(fd, LXA_IOC_MMAP_PTR, &ptr) < 0) {
1941                 /*
1942                  * We really should return an error here, but some
1943                  * application (*cough* *cough* flash) expect this
1944                  * ioctl to work even if they haven't mmaped the
1945                  * device.
1946                  */
1947                 ci.ptr = 0;
1948         } else {
1949                 ci.ptr = ptr;
1950         }
1951 
1952         lx_debug("\toss get output ptr result = ");
1953         lx_debug("\t\t"
1954             "bytes = 0x%x (%u), blocks = 0x%x (%u), ptr = 0x%x (%u)",
1955             ci.bytes, ci.bytes, ci.blocks, ci.blocks, ci.ptr, ci.ptr);
1956 
1957         if (uucopy(&ci, (void *)arg, sizeof (ci)) != 0)
1958                 return (-errno);
1959         return (0);
1960 }
1961 
1962 static int
1963 /*ARGSUSED*/
1964 ict_oss_sndctl_dsp_sync(int fd, struct stat *stat,
1965     int cmd, char *cmd_str, intptr_t arg)
1966 {
1967         int             amode, err;
1968 
1969         assert(cmd == LX_OSS_SNDCTL_DSP_SYNC);
1970 
1971         /* Ioctl is only supported on dsp audio devices. */
1972         if ((err = i_is_dsp_dev(fd)) != 0)
1973                 return (err);
1974 
1975         /* We need to know the access mode for the file. */
1976         if ((amode = fcntl(fd, F_GETFL)) < 0)
1977                 return (-EINVAL);
1978         amode &= O_ACCMODE;
1979         assert((amode == O_RDONLY) || (amode == O_WRONLY) || (amode == O_RDWR));
1980 
1981         /*
1982          * A sync is basically a noop for record only device.
1983          * We check for this here because on Linux a sync on a record
1984          * only device returns success immediately.  But the Solaris
1985          * equivalent to a drain operation is a AUDIO_DRAIN, and if
1986          * it's issued to a record only device it will fail and return
1987          * EINVAL.
1988          */
1989         if (amode == O_RDONLY)
1990                 return (0);
1991 
1992         /* Drain any pending output. */
1993         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
1994             fd, AUDIO_DRAIN, "AUDIO_DRAIN");
1995         return ((ioctl(fd, AUDIO_DRAIN, NULL) < 0) ? -errno : 0);
1996 }
1997 
1998 /*
1999  * /dev/mixer ioctl translators and support
2000  *
2001  * There are some interesting things to take note of for supporting
2002  * /dev/mixer ioctls.
2003  *
2004  * 1) We report support for the following mixer resources:
2005  *      VOLUME, PCM, MIC
2006  *
2007  * 2) We assume the following number of channels for each mixer resource:
2008  *      VOLUME: 2 channels
2009  *      PCM:    2 channels
2010  *      MIC:    1 channel
2011  *
2012  * 3) OSS sets the gain on each channel independently but on Solaris
2013  *    there is only one gain value and a balance value.  So we need
2014  *    to do some translation back and forth.
2015  *
2016  * 4) OSS assumes direct access to hardware but Solaris provides
2017  *    virtualized audio device access (where everyone who opens /dev/audio
2018  *    get a virtualized audio channel stream, all of which are merged
2019  *    together by a software mixer before reaching the hardware).  Hence
2020  *    mapping OSS mixer resources to Solaris mixer resources takes some
2021  *    work.  VOLUME and Mic resources are mapped to the actual underlying
2022  *    audio hardware resources.  PCM resource are mapped to the virtual
2023  *    audio channel output level.  This mapping becomes more complicated
2024  *    if there are no open audio output channels.  In this case the
2025  *    lx_audio device caches the PCM channels setting for us and applies
2026  *    them to any new audio output channels that get opened.  (This
2027  *    is the reason that we don't use AUDIO_SETINFO ioctls directly
2028  *    but instead the lx_audio driver custom LXA_IOC_MIXER_SET_*
2029  *    and LXA_IOC_MIXER_GET_* ioctls.)  For more information see
2030  *    the comments in lx_audio.c.
2031  */
2032 static int
2033 i_is_mixer_dev(int fd)
2034 {
2035         int minor;
2036 
2037         /*
2038          * This is a cloning device so we have to ask the driver
2039          * what kind of minor node this is.
2040          */
2041         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2042             fd, LXA_IOC_GETMINORNUM, "LXA_IOC_GETMINORNUM");
2043         if (ioctl(fd, LXA_IOC_GETMINORNUM, &minor) < 0)
2044                 return (-EINVAL);
2045         if (minor != LXA_MINORNUM_MIXER)
2046                 return (-EINVAL);
2047         return (0);
2048 }
2049 
2050 static int
2051 i_oss_mixer_ml_to_val(lxa_mixer_levels_t *ml, uint_t *val)
2052 {
2053         int range, val1, val2;
2054 
2055         /* Deal with the other easy case, both channels have the same level. */
2056         if (ml->lxa_ml_balance == AUDIO_MID_BALANCE) {
2057                 *val = LX_OSS_MIXER_ENC2(
2058                     LX_OSS_S2L_GAIN(ml->lxa_ml_gain),
2059                     LX_OSS_S2L_GAIN(ml->lxa_ml_gain));
2060                 assert(LX_OSS_MIXER_2CH_OK(*val));
2061                 return (0);
2062         }
2063 
2064         /* Decode the balance/gain into two separate levels. */
2065         if (ml->lxa_ml_balance > AUDIO_MID_BALANCE) {
2066                 val2 = ml->lxa_ml_gain;
2067 
2068                 range = AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE;
2069                 val1 = AUDIO_RIGHT_BALANCE - ml->lxa_ml_balance;
2070                 val1 = (val2 * val1) / range;
2071         } else {
2072                 assert(ml->lxa_ml_balance < AUDIO_MID_BALANCE);
2073                 val1 = ml->lxa_ml_gain;
2074 
2075                 range = AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE;
2076                 val2 = ml->lxa_ml_balance;
2077                 val2 = (val1 * val2) / range;
2078         }
2079 
2080         *val = LX_OSS_MIXER_ENC2(LX_OSS_S2L_GAIN(val1),
2081             LX_OSS_S2L_GAIN(val2));
2082         return (0);
2083 }
2084 
2085 static int
2086 i_oss_mixer_val_to_ml(uint_t val, lxa_mixer_levels_t *ml_old,
2087     lxa_mixer_levels_t *ml)
2088 {
2089         int range, val1, val2;
2090 
2091         if (!LX_OSS_MIXER_2CH_OK(val))
2092                 return (-EINVAL);
2093 
2094         val1 = LX_OSS_MIXER_DEC1(val);
2095         val2 = LX_OSS_MIXER_DEC2(val);
2096 
2097         /*
2098          * Deal with the easy case.
2099          * Both channels have the same non-zero level.
2100          */
2101         if ((val1 != 0) && (val1 == val2)) {
2102                 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val1);
2103                 ml->lxa_ml_balance = AUDIO_MID_BALANCE;
2104                 return (0);
2105         }
2106 
2107         /* If both levels are zero, preserve the current balance setting. */
2108         if ((val1 == 0) && (val2 == 0)) {
2109                 ml->lxa_ml_gain = 0;
2110                 ml->lxa_ml_balance = ml_old->lxa_ml_balance;
2111                 return (0);
2112         }
2113 
2114         /*
2115          * First set the gain to match the highest channel value volume.
2116          * Then use the balance to simulate lower volume on the second
2117          * channel.
2118          */
2119         if (val1 > val2) {
2120                 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val1);
2121 
2122                 range = AUDIO_MID_BALANCE - AUDIO_LEFT_BALANCE;
2123                 ml->lxa_ml_balance = 0;
2124                 ml->lxa_ml_balance += ((val2 * range) / val1);
2125         } else {
2126                 assert(val1 < val2);
2127 
2128                 ml->lxa_ml_gain = LX_OSS_L2S_GAIN(val2);
2129 
2130                 range = AUDIO_RIGHT_BALANCE - AUDIO_MID_BALANCE;
2131                 ml->lxa_ml_balance = AUDIO_RIGHT_BALANCE;
2132                 ml->lxa_ml_balance -= ((val1 * range) / val2);
2133         }
2134 
2135         return (0);
2136 }
2137 
2138 static int
2139 /*ARGSUSED*/
2140 ict_oss_mixer_read_volume(int fd, struct stat *stat,
2141     int cmd, char *cmd_str, intptr_t arg)
2142 {
2143         lxa_mixer_levels_t      ml;
2144         uint_t                  *valp = (uint_t *)arg;
2145         uint_t                  val;
2146         char                    *cmd_txt;
2147         int                     err, cmd_new;
2148 
2149         assert((cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) ||
2150             (cmd == LX_OSS_SOUND_MIXER_READ_PCM));
2151 
2152         /* Ioctl is only supported on mixer audio devices. */
2153         if ((err = i_is_mixer_dev(fd)) != 0)
2154                 return (err);
2155 
2156         if (cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) {
2157                 cmd_new = LXA_IOC_MIXER_GET_VOL;
2158                 cmd_txt = "LXA_IOC_MIXER_GET_VOL";
2159         }
2160         if (cmd == LX_OSS_SOUND_MIXER_READ_PCM) {
2161                 cmd_new = LXA_IOC_MIXER_GET_PCM;
2162                 cmd_txt = "LXA_IOC_MIXER_GET_PCM";
2163         }
2164 
2165         /* Attempt to set the device output gain. */
2166         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, cmd_new, cmd_txt);
2167         if (ioctl(fd, cmd_new, &ml) < 0)
2168                 return (-errno);
2169 
2170         lx_debug("\tlx_audio mixer results, "
2171             "gain = 0x%x (%u), balance = 0x%x (%u)",
2172             ml.lxa_ml_gain, ml.lxa_ml_gain,
2173             ml.lxa_ml_balance, ml.lxa_ml_balance);
2174 
2175         assert(LXA_MIXER_LEVELS_OK(&ml));
2176 
2177         /* Translate the mixer levels struct to an OSS mixer value. */
2178         if ((err = i_oss_mixer_ml_to_val(&ml, &val)) != 0)
2179                 return (err);
2180         assert(LX_OSS_MIXER_2CH_OK(val));
2181 
2182         lx_debug("\toss get mixer %s result = 0x%x (%u)",
2183             (cmd == LX_OSS_SOUND_MIXER_READ_VOLUME) ? "volume" : "pcm",
2184             val, val);
2185 
2186         if (uucopy(&val, valp, sizeof (val)) != 0)
2187                 return (-errno);
2188         return (0);
2189 }
2190 
2191 static int
2192 /*ARGSUSED*/
2193 ict_oss_mixer_write_volume(int fd, struct stat *stat,
2194     int cmd, char *cmd_str, intptr_t arg)
2195 {
2196         lxa_mixer_levels_t      ml, ml_old;
2197         uint_t                  *valp = (uint_t *)arg;
2198         uint_t                  val;
2199         char                    *cmd_txt;
2200         int                     err, cmd_new;
2201 
2202         assert((cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) ||
2203             (cmd == LX_OSS_SOUND_MIXER_WRITE_PCM));
2204 
2205         /* Ioctl is only supported on mixer audio devices. */
2206         if ((err = i_is_mixer_dev(fd)) != 0)
2207                 return (err);
2208 
2209         if (uucopy(valp, &val, sizeof (val)) != 0)
2210                 return (-errno);
2211 
2212         if (cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) {
2213                 cmd_new = LXA_IOC_MIXER_SET_VOL;
2214                 cmd_txt = "LXA_IOC_MIXER_SET_VOL";
2215 
2216                 /* Attempt to get the device output gain. */
2217                 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd,
2218                     LXA_IOC_MIXER_GET_VOL, "LXA_IOC_MIXER_GET_VOL");
2219                 if (ioctl(fd, LXA_IOC_MIXER_GET_VOL, &ml_old) < 0)
2220                         return (-errno);
2221         }
2222 
2223         if (cmd == LX_OSS_SOUND_MIXER_WRITE_PCM) {
2224                 cmd_new = LXA_IOC_MIXER_SET_PCM;
2225                 cmd_txt = "LXA_IOC_MIXER_SET_PCM";
2226 
2227                 /* Attempt to get the device output gain. */
2228                 lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd,
2229                     LXA_IOC_MIXER_GET_PCM, "LXA_IOC_MIXER_GET_PCM");
2230                 if (ioctl(fd, LXA_IOC_MIXER_GET_PCM, &ml_old) < 0)
2231                         return (-errno);
2232         }
2233 
2234         lx_debug("\toss set mixer %s request = 0x%x (%u)",
2235             (cmd == LX_OSS_SOUND_MIXER_WRITE_VOLUME) ? "volume" : "pcm",
2236             val, val);
2237 
2238         /* Translate an OSS mixer value to mixer levels. */
2239         if ((err = i_oss_mixer_val_to_ml(val, &ml_old, &ml)) != 0)
2240                 return (err);
2241         assert(LXA_MIXER_LEVELS_OK(&ml));
2242 
2243         lx_debug("\tlx_audio mixer request, "
2244             "gain = 0x%x (%u), balance = 0x%x (%u)",
2245             ml.lxa_ml_gain, ml.lxa_ml_gain,
2246             ml.lxa_ml_balance, ml.lxa_ml_balance);
2247 
2248         /* Attempt to set the device output gain. */
2249         lx_debug("\tioctl(%d, 0x%x - %s, ...)", fd, cmd_new, cmd_txt);
2250         if (ioctl(fd, cmd_new, &ml) < 0)
2251                 return (-errno);
2252 
2253         return (0);
2254 }
2255 
2256 static int
2257 /*ARGSUSED*/
2258 ict_oss_mixer_read_mic(int fd, struct stat *stat,
2259     int cmd, char *cmd_str, intptr_t arg)
2260 {
2261         lxa_mixer_levels_t      ml;
2262         uint_t                  *valp = (uint_t *)arg;
2263         uint_t                  val;
2264         int                     err;
2265 
2266         assert((cmd == LX_OSS_SOUND_MIXER_READ_MIC) ||
2267             (cmd == LX_OSS_SOUND_MIXER_READ_IGAIN));
2268 
2269         /* Ioctl is only supported on mixer audio devices. */
2270         if ((err = i_is_mixer_dev(fd)) != 0)
2271                 return (err);
2272 
2273         /* Attempt to get the device input gain. */
2274         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2275             fd, LXA_IOC_MIXER_GET_MIC, "LXA_IOC_MIXER_GET_MIC");
2276         if (ioctl(fd, LXA_IOC_MIXER_GET_MIC, &ml) < 0)
2277                 return (-errno);
2278 
2279         /* Report the mixer as having two channels. */
2280         val = LX_OSS_MIXER_ENC2(
2281             LX_OSS_S2L_GAIN(ml.lxa_ml_gain),
2282             LX_OSS_S2L_GAIN(ml.lxa_ml_gain));
2283 
2284         if (cmd == LX_OSS_SOUND_MIXER_READ_MIC)
2285                 lx_debug("\toss get mixer mic result = 0x%x (%u)", val, val);
2286         if (cmd == LX_OSS_SOUND_MIXER_READ_IGAIN)
2287                 lx_debug("\toss get mixer igain result = 0x%x (%u)", val, val);
2288 
2289         if (uucopy(&val, valp, sizeof (val)) != 0)
2290                 return (-errno);
2291         return (0);
2292 }
2293 
2294 static int
2295 /*ARGSUSED*/
2296 ict_oss_mixer_write_mic(int fd, struct stat *stat,
2297     int cmd, char *cmd_str, intptr_t arg)
2298 {
2299         lxa_mixer_levels_t      ml;
2300         uint_t                  *valp = (uint_t *)arg;
2301         uint_t                  val;
2302         int                     err;
2303 
2304         assert((cmd == LX_OSS_SOUND_MIXER_WRITE_MIC) ||
2305             (cmd == LX_OSS_SOUND_MIXER_WRITE_IGAIN));
2306 
2307         /* Ioctl is only supported on mixer audio devices. */
2308         if ((err = i_is_mixer_dev(fd)) != 0)
2309                 return (err);
2310 
2311         if (uucopy(valp, &val, sizeof (val)) != 0)
2312                 return (-errno);
2313 
2314         if (cmd == LX_OSS_SOUND_MIXER_WRITE_MIC)
2315                 lx_debug("\toss set mixer mic request = 0x%x (%u)", val, val);
2316         if (cmd == LX_OSS_SOUND_MIXER_WRITE_IGAIN)
2317                 lx_debug("\toss set mixer igain request = 0x%x (%u)", val, val);
2318 
2319         /* The mic only supports one channel. */
2320         val = LX_OSS_MIXER_DEC1(val);
2321 
2322         ml.lxa_ml_balance = AUDIO_MID_BALANCE;
2323         ml.lxa_ml_gain = LX_OSS_L2S_GAIN(val);
2324 
2325         /* Attempt to set the device input gain. */
2326         lx_debug("\tioctl(%d, 0x%x - %s, ...)",
2327             fd, LXA_IOC_MIXER_SET_MIC, "LXA_IOC_MIXER_SET_MIC");
2328         if (ioctl(fd, LXA_IOC_MIXER_SET_MIC, &ml) < 0)
2329                 return (-errno);
2330 
2331         return (0);
2332 }
2333 
2334 static int
2335 /*ARGSUSED*/
2336 ict_oss_mixer_read_devs(int fd, struct stat *stat,
2337     int cmd, char *cmd_str, intptr_t arg)
2338 {
2339         uint_t          *resultp = (uint_t *)arg;
2340         uint_t          result = 0;
2341         int             err;
2342 
2343         if (cmd == LX_OSS_SOUND_MIXER_READ_DEVMASK) {
2344                 /* Bitmap of all the mixer channels we supposedly support. */
2345                 result = ((1 << LX_OSS_SM_PCM) |
2346                     (1 << LX_OSS_SM_MIC) |
2347                     (1 << LX_OSS_SM_VOLUME));
2348         }
2349         if (cmd == LX_OSS_SOUND_MIXER_READ_STEREODEVS) {
2350                 /* Bitmap of the stereo mixer channels we supposedly support. */
2351                 result = ((1 << LX_OSS_SM_PCM) |
2352                     (1 << LX_OSS_SM_VOLUME));
2353         }
2354         if ((cmd == LX_OSS_SOUND_MIXER_READ_RECMASK) ||
2355             (cmd == LX_OSS_SOUND_MIXER_READ_RECSRC)) {
2356                 /* Bitmap of the mixer input channels we supposedly support. */
2357                 result = (1 << LX_OSS_SM_MIC);
2358         }
2359         assert(result != 0);
2360 
2361         /* Ioctl is only supported on mixer audio devices. */
2362         if ((err = i_is_mixer_dev(fd)) != 0)
2363                 return (err);
2364 
2365         if (uucopy(&result, resultp, sizeof (result)) != 0)
2366                 return (-errno);
2367 
2368         return (0);
2369 }
2370 
2371 /*
2372  * Audio ioctl conversion support structures.
2373  */
2374 static oss_fmt_translator_t oft_table[] = {
2375         { LX_OSS_AFMT_MU_LAW,           AUDIO_ENCODING_ULAW,    8 },
2376         { LX_OSS_AFMT_A_LAW,            AUDIO_ENCODING_ALAW,    8 },
2377         { LX_OSS_AFMT_S8,               AUDIO_ENCODING_LINEAR,  8 },
2378         { LX_OSS_AFMT_U8,               AUDIO_ENCODING_LINEAR8, 8 },
2379         { LX_OSS_AFMT_S16_NE,           AUDIO_ENCODING_LINEAR,  16 },
2380         { 0,                            0,                      0 }
2381 };
2382 
2383 /*
2384  * Ioctl translator definitions.
2385  */
2386 
2387 /*
2388  * Defines to help with creating ioctl translators.
2389  *
2390  * IOC_CMD_TRANSLATOR_NONE - Ioctl has the same semantics and argument
2391  * values on Solaris and Linux but may have different command values.
2392  * (Macro assumes the symbolic Linux name assigned to the ioctl command
2393  * value is the same as the Solaris symbol but pre-pended with an "LX_")
2394  *
2395  * IOC_CMD_TRANSLATOR_PASS - Ioctl is a Linux specific ioctl and should
2396  * be passed through unmodified.
2397  *
2398  * IOC_CMD_TRANSLATOR_FILTER - Ioctl has the same command name on
2399  * Solaris and Linux and needs a translation function that is common to
2400  * more than one ioctl. (Macro assumes the symbolic Linux name assigned
2401  * to the ioctl command value is the same as the Solaris symbol but
2402  * pre-pended with an "LX_")
2403  *
2404  * IOC_CMD_TRANSLATOR_CUSTOM - Ioctl needs special handling via a
2405  * translation function.
2406  */
2407 #define IOC_CMD_TRANSLATOR_NONE(ioc_cmd_sym)                            \
2408         { (int)LX_##ioc_cmd_sym, "LX_" #ioc_cmd_sym,                    \
2409                 ioc_cmd_sym, #ioc_cmd_sym, ict_pass },
2410 
2411 #define IOC_CMD_TRANSLATOR_PASS(ioc_cmd_sym)                            \
2412         { (int)ioc_cmd_sym, #ioc_cmd_sym,                               \
2413                 ioc_cmd_sym, #ioc_cmd_sym, ict_pass },
2414 
2415 #define IOC_CMD_TRANSLATOR_FILTER(ioc_cmd_sym, ioct_handler)            \
2416         { (int)LX_##ioc_cmd_sym, "LX_" #ioc_cmd_sym,                    \
2417                 ioc_cmd_sym, #ioc_cmd_sym, ioct_handler },
2418 
2419 #define IOC_CMD_TRANSLATOR_CUSTOM(ioc_cmd_sym, ioct_handler)            \
2420         { (int)ioc_cmd_sym, #ioc_cmd_sym,                               \
2421                 (int)ioc_cmd_sym, #ioc_cmd_sym, ioct_handler },
2422 
2423 #define IOC_CMD_TRANSLATOR_END                                          \
2424         { 0, NULL, 0, NULL, NULL }
2425 
2426 /* All files will need to support these ioctls. */
2427 #define IOC_CMD_TRANSLATORS_ALL                                         \
2428         IOC_CMD_TRANSLATOR_NONE(FIONREAD)                               \
2429         IOC_CMD_TRANSLATOR_NONE(FIONBIO)
2430 
2431 /* Any files supporting streams semantics will need these ioctls. */
2432 #define IOC_CMD_TRANSLATORS_STREAMS                                     \
2433         IOC_CMD_TRANSLATOR_NONE(TCXONC)                                 \
2434         IOC_CMD_TRANSLATOR_NONE(TCFLSH)                                 \
2435         IOC_CMD_TRANSLATOR_NONE(TIOCEXCL)                               \
2436         IOC_CMD_TRANSLATOR_NONE(TIOCNXCL)                               \
2437         IOC_CMD_TRANSLATOR_NONE(TIOCSPGRP)                              \
2438         IOC_CMD_TRANSLATOR_NONE(TIOCSTI)                                \
2439         IOC_CMD_TRANSLATOR_NONE(TIOCSWINSZ)                             \
2440         IOC_CMD_TRANSLATOR_NONE(TIOCMBIS)                               \
2441         IOC_CMD_TRANSLATOR_NONE(TIOCMBIC)                               \
2442         IOC_CMD_TRANSLATOR_NONE(TIOCMSET)                               \
2443         IOC_CMD_TRANSLATOR_NONE(TIOCSETD)                               \
2444         IOC_CMD_TRANSLATOR_NONE(FIOASYNC)                               \
2445         IOC_CMD_TRANSLATOR_NONE(FIOSETOWN)                              \
2446         IOC_CMD_TRANSLATOR_NONE(TCSBRK)                                 \
2447                                                                         \
2448         IOC_CMD_TRANSLATOR_FILTER(TCSETS,               ict_tcsets)     \
2449         IOC_CMD_TRANSLATOR_FILTER(TCSETSW,              ict_tcsets)     \
2450         IOC_CMD_TRANSLATOR_FILTER(TCSETSF,              ict_tcsets)     \
2451         IOC_CMD_TRANSLATOR_FILTER(TCSETA,               ict_tcseta)     \
2452         IOC_CMD_TRANSLATOR_FILTER(TCSETAW,              ict_tcseta)     \
2453         IOC_CMD_TRANSLATOR_FILTER(TCSETAF,              ict_tcseta)     \
2454                                                                         \
2455         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCSBRKP,           ict_tcsbrkp)
2456 
2457 
2458 /*
2459  * Translators for non-device files.
2460  */
2461 static ioc_cmd_translator_t ioc_translators_file[] = {
2462         IOC_CMD_TRANSLATORS_ALL
2463         IOC_CMD_TRANSLATOR_END
2464 };
2465 
2466 static ioc_cmd_translator_t ioc_translators_fifo[] = {
2467         IOC_CMD_TRANSLATORS_ALL
2468         IOC_CMD_TRANSLATORS_STREAMS
2469         IOC_CMD_TRANSLATOR_END
2470 };
2471 
2472 static ioc_cmd_translator_t ioc_translators_sock[] = {
2473         IOC_CMD_TRANSLATORS_ALL
2474 
2475         IOC_CMD_TRANSLATOR_NONE(FIOASYNC)
2476         IOC_CMD_TRANSLATOR_NONE(FIOGETOWN)
2477         IOC_CMD_TRANSLATOR_NONE(FIOSETOWN)
2478         IOC_CMD_TRANSLATOR_NONE(SIOCSPGRP)
2479         IOC_CMD_TRANSLATOR_NONE(SIOCGPGRP)
2480 
2481         IOC_CMD_TRANSLATOR_FILTER(SIOCATMARK,           ict_sioifoob)
2482 
2483         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFFLAGS,         ict_sioifreq)
2484         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFFLAGS,         ict_sioifreq)
2485         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFADDR,          ict_sioifreq)
2486         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFADDR,          ict_sioifreq)
2487         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFDSTADDR,       ict_sioifreq)
2488         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFDSTADDR,       ict_sioifreq)
2489         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFBRDADDR,       ict_sioifreq)
2490         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFBRDADDR,       ict_sioifreq)
2491         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFNETMASK,       ict_sioifreq)
2492         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFNETMASK,       ict_sioifreq)
2493         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMETRIC,        ict_sioifreq)
2494         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMETRIC,        ict_sioifreq)
2495         IOC_CMD_TRANSLATOR_FILTER(SIOCGIFMTU,           ict_sioifreq)
2496         IOC_CMD_TRANSLATOR_FILTER(SIOCSIFMTU,           ict_sioifreq)
2497 
2498         IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFCONF,       ict_siocgifconf)
2499         IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCGIFHWADDR,     ict_siocifhwaddr)
2500         IOC_CMD_TRANSLATOR_CUSTOM(LX_SIOCSIFHWADDR,     ict_siocifhwaddr)
2501 
2502         IOC_CMD_TRANSLATOR_END
2503 };
2504 
2505 /*
2506  * Translators for devices.
2507  */
2508 static ioc_cmd_translator_t ioc_cmd_translators_ptm[] = {
2509         IOC_CMD_TRANSLATORS_ALL
2510         IOC_CMD_TRANSLATORS_STREAMS
2511 
2512         IOC_CMD_TRANSLATOR_NONE(TIOCPKT)
2513 
2514         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPGRP,         ict_tiocgpgrp)
2515         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSPTLCK,        ict_sptlock)
2516         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPTN,          ict_gptn)
2517         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ,        ict_tiocgwinsz)
2518         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS,            ict_tcgets_emulate)
2519 
2520         IOC_CMD_TRANSLATOR_END
2521 };
2522 static ioc_dev_translator_t ioc_translator_ptm = {
2523         LX_PTM_DRV,     /* idt_driver */
2524         0,              /* idt_major */
2525         ioc_cmd_translators_ptm
2526 };
2527 
2528 static ioc_cmd_translator_t ioc_cmd_translators_pts[] = {
2529         IOC_CMD_TRANSLATORS_ALL
2530         IOC_CMD_TRANSLATORS_STREAMS
2531 
2532         IOC_CMD_TRANSLATOR_NONE(TIOCGETD)
2533         IOC_CMD_TRANSLATOR_NONE(TIOCGSID)
2534         IOC_CMD_TRANSLATOR_NONE(TIOCNOTTY)
2535 
2536         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGPGRP,         ict_tiocgpgrp)
2537         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS,            ict_tcgets_native)
2538         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETA,            ict_tcgeta)
2539         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ,        ict_tiocgwinsz)
2540         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSCTTY,         ict_tiocsctty)
2541 
2542         IOC_CMD_TRANSLATOR_END
2543 };
2544 static ioc_dev_translator_t ioc_translator_pts = {
2545         "pts",          /* idt_driver */
2546         0,              /* idt_major */
2547         ioc_cmd_translators_pts
2548 };
2549 
2550 static ioc_dev_translator_t ioc_translator_sy = {
2551         "sy",           /* idt_driver */
2552         0,              /* idt_major */
2553 
2554         /*
2555          * /dev/tty (which is implemented via the "sy" driver) is basically
2556          * a layered driver that passes on requests to the ctty for the
2557          * current process.  Since ctty's are currently always implemented
2558          * via the pts driver, we should make sure to support all the
2559          * same ioctls on the sy driver as we do on the pts driver.
2560          */
2561         ioc_cmd_translators_pts
2562 };
2563 
2564 static ioc_cmd_translator_t ioc_cmd_translators_zcons[] = {
2565         IOC_CMD_TRANSLATORS_ALL
2566         IOC_CMD_TRANSLATORS_STREAMS
2567 
2568         IOC_CMD_TRANSLATOR_NONE(TIOCNOTTY)
2569 
2570         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETS,            ict_tcgets_native)
2571         IOC_CMD_TRANSLATOR_CUSTOM(LX_TCGETA,            ict_tcgeta)
2572         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCGWINSZ,        ict_tiocgwinsz)
2573         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCSCTTY,         ict_tiocsctty)
2574 
2575         IOC_CMD_TRANSLATOR_CUSTOM(LX_TIOCLINUX,         ict_einval)
2576 
2577         IOC_CMD_TRANSLATOR_END
2578 };
2579 static ioc_dev_translator_t ioc_translator_zcons = {
2580         "zcons",        /* idt_driver */
2581         0,              /* idt_major */
2582         ioc_cmd_translators_zcons
2583 };
2584 
2585 static ioc_cmd_translator_t ioc_cmd_translators_lx_audio[] = {
2586         IOC_CMD_TRANSLATORS_ALL
2587 
2588         /* /dev/dsp ioctls */
2589         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_RESET,
2590             ict_oss_sndctl_dsp_reset)
2591         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETFMTS,
2592             ict_oss_sndctl_dsp_getfmts)
2593         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETFMTS,
2594             ict_oss_sndctl_dsp_setfmts)
2595         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_CHANNELS,
2596             ict_oss_sndctl_dsp_channels)
2597         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_STEREO,
2598             ict_oss_sndctl_dsp_channels)
2599         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SPEED,
2600             ict_oss_sndctl_dsp_speed)
2601         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETBLKSIZE,
2602             ict_oss_sndctl_dsp_getblksize)
2603         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SYNC,
2604             ict_oss_sndctl_dsp_sync)
2605         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETFRAGMENT,
2606             ict_oss_sndctl_dsp_setfragment)
2607         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETOSPACE,
2608             ict_oss_sndctl_dsp_getspace)
2609         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETCAPS,
2610             ict_oss_sndctl_dsp_getcaps)
2611         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_SETTRIGGER,
2612             ict_oss_sndctl_dsp_settrigger)
2613         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETOPTR,
2614             ict_oss_sndctl_dsp_getoptr)
2615         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SNDCTL_DSP_GETISPACE,
2616             ict_oss_sndctl_dsp_getspace)
2617 
2618         /* /dev/mixer level ioctls */
2619         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_VOLUME,
2620             ict_oss_mixer_read_volume)
2621         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_PCM,
2622             ict_oss_mixer_read_volume)
2623         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_MIC,
2624             ict_oss_mixer_read_mic)
2625         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_IGAIN,
2626             ict_oss_mixer_read_mic)
2627         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_VOLUME,
2628             ict_oss_mixer_write_volume)
2629         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_PCM,
2630             ict_oss_mixer_write_volume)
2631         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_MIC,
2632             ict_oss_mixer_write_mic)
2633         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_WRITE_IGAIN,
2634             ict_oss_mixer_write_mic)
2635 
2636         /* /dev/mixer capability ioctls */
2637         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_STEREODEVS,
2638             ict_oss_mixer_read_devs)
2639         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_DEVMASK,
2640             ict_oss_mixer_read_devs)
2641         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_RECMASK,
2642             ict_oss_mixer_read_devs)
2643         IOC_CMD_TRANSLATOR_CUSTOM(LX_OSS_SOUND_MIXER_READ_RECSRC,
2644             ict_oss_mixer_read_devs)
2645 
2646         IOC_CMD_TRANSLATOR_END
2647 };
2648 static ioc_dev_translator_t ioc_translator_lx_audio = {
2649         "lx_audio",     /* idt_driver */
2650         0,              /* idt_major */
2651         ioc_cmd_translators_lx_audio
2652 };
2653 
2654 /*
2655  * An array of all the device translators.
2656  */
2657 static ioc_dev_translator_t *ioc_translators_dev[] = {
2658         &ioc_translator_lx_audio,
2659         &ioc_translator_ptm,
2660         &ioc_translator_pts,
2661         &ioc_translator_sy,
2662         &ioc_translator_zcons,
2663         NULL
2664 };
2665 
2666 /*
2667  * Translators for filesystems.
2668  */
2669 static ioc_cmd_translator_t ioc_cmd_translators_autofs[] = {
2670         IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_READY)
2671         IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_FAIL)
2672         IOC_CMD_TRANSLATOR_PASS(LX_AUTOFS_IOC_CATATONIC)
2673         IOC_CMD_TRANSLATOR_END
2674 };
2675 
2676 static ioc_fs_translator_t ioc_translator_autofs = {
2677         LX_AUTOFS_NAME, /* ift_filesystem */
2678         ioc_cmd_translators_autofs
2679 };
2680 
2681 /*
2682  * An array of all the filesystem translators.
2683  */
2684 static ioc_fs_translator_t *ioc_translators_fs[] = {
2685         &ioc_translator_autofs,
2686         NULL
2687 };
2688 
2689 /*
2690  * Ioctl error translator definitions.
2691  */
2692 #define IOC_ERRNO_TRANSLATOR(iet_cmd_sym, iet_errno)                    \
2693         { (int)LX_##iet_cmd_sym, "LX_" #iet_cmd_sym, iet_errno },
2694 
2695 #define IOC_ERRNO_TRANSLATOR_END                                        \
2696         { 0, NULL, 0 }
2697 
2698 static ioc_errno_translator_t ioc_translators_errno[] = {
2699         IOC_ERRNO_TRANSLATOR(TCGETS, ENOTTY)
2700         IOC_ERRNO_TRANSLATOR(TCSETS, ENOTTY)
2701         IOC_ERRNO_TRANSLATOR(TCSBRK, ENOTTY)
2702         IOC_ERRNO_TRANSLATOR(TCXONC, ENOTTY)
2703         IOC_ERRNO_TRANSLATOR(TCFLSH, ENOTTY)
2704         IOC_ERRNO_TRANSLATOR(TIOCGPGRP, ENOTTY)
2705         IOC_ERRNO_TRANSLATOR(TIOCSPGRP, ENOTTY)
2706         IOC_ERRNO_TRANSLATOR(TIOCGWINSZ, ENOTTY)
2707         IOC_ERRNO_TRANSLATOR_END
2708 };
2709 
2710 int
2711 lx_vhangup(void)
2712 {
2713         if (geteuid() != 0)
2714                 return (-EPERM);
2715 
2716         vhangup();
2717 
2718         return (0);
2719 }