ioctl.c revision 49e92448e558772c002444c0d92e7a31d529d046
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A#
pragma ident "%Z%%M% %I% %E% SMI" 2N/A/* Define _KERNEL to get the devt manipulation macros. */ 2N/A/* Maximum number of modules on a stream that we can handle. */ 2N/A/* Maximum buffer size for debugging messages. */ 2N/A/* Structure used to define an ioctl translator. */ 2N/A * Structures used to associate a group of ioctl translators with 2N/A * a specific device. 2N/A /* Array of command translators. */ 2N/A * Structures used to associate a group of ioctl translators with 2N/A * a specific filesystem. 2N/A /* Array of command translators. */ /* Structure used to define a unsupported ioctl error codes. */ /* Structure used to convert oss format flags into Solaris options. */ /* Translator forward declerations. */ * Macros and structures to help convert integers to string * values that they represent (for displaying in debug output). /* Display the initial error message and extended ioctl information. */ lx_debug(
"\tlx_ioctl(): cmd = 0x%x - %s, fd = %d - %s",
/* Display information about the target file, if it's available. */ /* Translate the file type bits into a string. */ /* This is a device so display the devt. */ /* Try to display the drivers name. */ /* Get the number of modules on the stream. */ lx_debug(
"\tldlinux_check(): unable to count stream modules");
/* Sanity check the number of modules on the stream. */ /* Get the list of modules on the stream. */ lx_debug(
"\tldlinux_check(): unable to list stream modules");
* Add an interface name mapping if it doesn't already exist. * Interfaces with IFF_LOOPBACK flag get renamed to loXXX. * Interfaces with IFF_BROADCAST flag get renamed to ethXXX. * Caller locks the name table. /* Assume ether if it has a broadcast address */ /* Do not translate unknown interfaces */ * (Re-)scan all interfaces and add them to the name table. * Caller locks the name table. lx_debug(
"\tifname_scan(): unable to get number of interfaces");
lx_debug(
"\tifname_scan(): unable to get interfaces");
/* Get the interface flags */ lx_debug(
"\tifname_scan(): unable to get flags for %s",
* Sort the interfaces by name to preserve the order * across reboots of this zone. Note that the order of * interface names won't be consistent across network * configuration changes. ie. If network interfaces * are added or removed from a zone (either dynamically * or statically) the network interfaces names to physical * network interface mappings that linux apps see may /* Add to the name table */ * Called to initialize the ioctl translation subsystem. /* Figure out the major numbers for our devices translators. */ "lx_ioctl_init(): modctl(MODGETMAJBIND, ",
/* Create the interface name table */ lx_err(
"lx_ioctl_init(): ifname_scan() failed\n");
* Main entry point for the ioctl translater. "lx_ioctl(): fstat() failed");
* Linux ioctl(2) is only documented to return EBADF, EFAULT, * EINVAL is documented to be "Request or argp is not valid", * so it's reasonable to force any errno that's not EBADF, * EFAULT or ENOTTY to be EINVAL. return (-
errno);
/* errno already set. */ /* Use file translators. */ /* Use socket translators. */ /* Use fifo translators. */ * Look through all the device translators to see if there * is one for this device. /* We found a translator for this device. */ * Search the selected translator group to see if we have a * translator for this specific command. /* We found a translator for this command, invoke it. */ "lx_ioctl(): emulating ioctl");
* If we didn't find a file or device translator for this * command then try to find a filesystem translator for /* We found a translator for this filesystem. */ * Search the selected translator group to see if we have a * translator for this specific command. /* We found a translator for this command, invoke it. */ "lx_ioctl(): emulating ioctl");
* No translator for this ioctl was found. * Check if there is an errno translator. /* We found a an errno translator for this ioctl. */ "lx_ioctl(): emulating errno");
"lx_ioctl(): unsupported linux ioctl");
* Ioctl translator functions. * Used by translators that want to explicitly return EINVAL for an * ioctl(2) instead of having the translation framework do it implicitly. * This allows us to indicate which unsupported ioctl(2)s should not * trigger a SIGSYS when running in LX_STRICT mode. * Linux expects a SIOCATMARK of a UDP socket to return EINVAL, while lx_debug(
"\tioctl(%d, 0x%x - %s, %.14s",
/* They want to know how many interfaces there are. */ /* Check if we're done. */ /* Get interface configuration list. */ /* Rename interfaces to linux */ lx_debug(
"\tioctl(%d, 0x%x - %s, lx %.14s)",
* We're not going to support SIOCSIFHWADDR, but we need to be * able to check the result of the uucopy first to see if the command * should have returned EFAULT. "lx_ioctl(): unsupported linux ioctl: %s"),
/* Abuse ifr_addr for linux ifr_hwaddr */ lx_debug(
"\tioctl(%d, 0x%x - %s, %.14s)",
/* Abuse ifr_addr for linux ifr_hwaddr */ * ldlinux strmod. So make sure the module exists on the * target stream before we invoke the ioctl. * ldlinux strmod. So make sure the module exists on the * target stream before we invoke the ioctl. * The Solaris TIOCGPGRP ioctl does not have exactly the same semantics as * the Linux one. To mimic Linux semantics we have to do some extra work * normally done by the Solaris version of tcgetpgrp(). * The success/fail return values are different between Linux * and Solaris. Linux expects 0 or -1. Solaris can return * positive number on success. /* This operation is only valid for the lx_ptm device. */ * We'd like to just use grantpt() directly, but we can't since * it assumes the fd node that's passed to it is a ptm node, * and in our case it's an lx_ptm node. It also relies on * naming services to get the current process group name. * Hence we have to invoke the OWNERPT ioctl directly here. /* Now munge the data to how Linux wants it. */ /* Now munge the data to how Linux wants it. */ * ldlinux strmod. So make sure the module exists on the * target stream before we invoke the ioctl. /* Now munge the data to how Linux wants it. */ * ldlinux strmod. So make sure the module exists on the * target stream before we invoke the ioctl. /* Check if this fd is already our ctty. */ * Need to make sure we're a session leader, otherwise the * TIOCSCTTY ioctl will fail. * /dev/dsp ioctl translators and support * This is a cloning device so we have to ask the driver * what kind of minor node this is. /* Ioctl is only supported on dsp audio devices. */ /* Nothing to really do on Solaris. */ /* Ioctl is only supported on dsp audio devices. */ /* We need to know the access mode for the file. */ /* Test to see what Linux oss formats the target device supports. */ /* Initialize the mode request. */ /* Translate a Linux oss format into Solaris settings. */ /* This Linux oss format is supported. */ /* Ioctl is only supported on dsp audio devices. */ lx_debug(
"\tXXX: possible oss formats query?");
/* Check if multiple format bits were specified. */ /* Decode the oss format request into a native format. */ /* We need to know the access mode for the file. */ /* Initialize the mode request. */ /* Translate the Linux oss request into a Solaris request. */ /* Ioctl is only supported on dsp audio devices. */ lx_debug(
"\toss %s request = 0x%x (%u)",
* There doesn't seem to be any documentation for * SNDCTL_DSP_STEREO. Looking at source that uses or * used this ioctl seems to indicate that the * functionality provided by this ioctl has been * subsumed by the SNDCTL_DSP_CHANNELS ioctl. It * seems that the only arguments ever passed to * the SNDCTL_DSP_STEREO. Ioctl are boolean values * of '0' or '1'. Hence we'll start out strict and * only support those values. * Some online forum discussions about this ioctl * seemed to indicate that in case of success it * returns the "stereo" setting (ie, either * '0' for mono or '1' for stereo). /* Limit the system to one or two channels. */ /* We need to know the access mode for the file. */ /* Initialize the channel request. */ /* Translate the Linux oss request into a Solaris request. */ /* Ioctl is only supported on dsp audio devices. */ lx_debug(
"\tXXX: possible oss speed query?");
/* We need to know the access mode for the file. */ /* Initialize the speed request. */ /* Translate the Linux oss request into a Solaris request. */ /* Ioctl is only supported on dsp audio devices. */ /* Query the current fragment count and size. */ /* Ioctl is only supported on dsp audio devices. */ /* Query the current fragment count and size. */ /* Return the current fragment count and size. */ * We'll lie and tell applications that they can always write * out at least one fragment without blocking. lx_debug(
"\toss get output space result = ");
lx_debug(
"\toss get input space result = ");
lx_debug(
"\t\tbytes = 0x%x (%u), fragments = 0x%x (%u)",
lx_debug(
"\t\tfragtotal = 0x%x (%u), fragsize = 0x%x (%u)",
/* Ioctl is only supported on dsp audio devices. */ * The argument to this ioctl is a 32-bit integer of the * format 0x MMMM SSSS where: * SSSS - requests a fragment size of 2^SSSS * MMMM - requests a maximum fragment count of 2^MMMM * if MMMM is 0x7fff then the application is requesting * no limits on the number of fragments. "power size = 0x%x (%u), power cnt = 0x%x (%u)",
/* Limit the supported fragment size from 2^4 to 2^31. */ /* Limit the number of fragments from 2^1 to 2^32. */ /* Expand the fragment values. */ "translated size = 0x%x (%u), translated cnt = 0x%x (%u)",
/* Set the current fragment count and size. */ /* Ioctl is only supported on dsp audio devices. */ * Report that we support mmap access * this is where things start to get fun. /* Ioctl is only supported on dsp audio devices. */ lx_debug(
"\toss set trigger request = 0x%x (%u)",
/* We only support two types of trigger requests. */ * We only support triggers on devices open for write access, * but we don't need to check for that here since the driver will /* Send the trigger command to the audio device. */ /* Ioctl is only supported on dsp audio devices. */ /* Query the current fragment size. */ /* Figure out how many samples have been played. */ * Figure out how many fragments of audio have gone out since * the last call to this ioctl. /* Figure out the current fragment offset for mmap audio output. */ * We really should return an error here, but some * application (*cough* *cough* flash) expect this * ioctl to work even if they haven't mmaped the lx_debug(
"\toss get output ptr result = ");
"bytes = 0x%x (%u), blocks = 0x%x (%u), ptr = 0x%x (%u)",
/* Ioctl is only supported on dsp audio devices. */ /* We need to know the access mode for the file. */ * A sync is basically a noop for record only device. * We check for this here because on Linux a sync on a record * only device returns success immediately. But the Solaris * equivalent to a drain operation is a AUDIO_DRAIN, and if * it's issued to a record only device it will fail and return /* Drain any pending output. */ * /dev/mixer ioctl translators and support * There are some interesting things to take note of for supporting * 1) We report support for the following mixer resources: * 2) We assume the following number of channels for each mixer resource: * 3) OSS sets the gain on each channel independently but on Solaris * there is only one gain value and a balance value. So we need * to do some translation back and forth. * 4) OSS assumes direct access to hardware but Solaris provides * virtualized audio device access (where everyone who opens /dev/audio * get a virtualized audio channel stream, all of which are merged * together by a software mixer before reaching the hardware). Hence * mapping OSS mixer resources to Solaris mixer resources takes some * work. VOLUME and Mic resources are mapped to the actual underlying * audio hardware resources. PCM resource are mapped to the virtual * audio channel output level. This mapping becomes more complicated * if there are no open audio output channels. In this case the * lx_audio device caches the PCM channels setting for us and applies * them to any new audio output channels that get opened. (This * is the reason that we don't use AUDIO_SETINFO ioctls directly * but instead the lx_audio driver custom LXA_IOC_MIXER_SET_* * and LXA_IOC_MIXER_GET_* ioctls.) For more information see * This is a cloning device so we have to ask the driver * what kind of minor node this is. /* Deal with the other easy case, both channels have the same level. */ /* Decode the balance/gain into two separate levels. */ * Deal with the easy case. * Both channels have the same non-zero level. /* If both levels are zero, preserve the current balance setting. */ * First set the gain to match the highest channel value volume. * Then use the balance to simulate lower volume on the second /* Ioctl is only supported on mixer audio devices. */ /* Attempt to set the device output gain. */ "gain = 0x%x (%u), balance = 0x%x (%u)",
/* Translate the mixer levels struct to an OSS mixer value. */ lx_debug(
"\toss get mixer %s result = 0x%x (%u)",
/* Ioctl is only supported on mixer audio devices. */ /* Attempt to get the device output gain. */ /* Attempt to get the device output gain. */ lx_debug(
"\toss set mixer %s request = 0x%x (%u)",
/* Translate an OSS mixer value to mixer levels. */ "gain = 0x%x (%u), balance = 0x%x (%u)",
/* Attempt to set the device output gain. */ /* Ioctl is only supported on mixer audio devices. */ /* Attempt to get the device input gain. */ /* Report the mixer as having two channels. */ /* Ioctl is only supported on mixer audio devices. */ /* The mic only supports one channel. */ /* Attempt to set the device input gain. */ /* Bitmap of all the mixer channels we supposedly support. */ /* Bitmap of the stereo mixer channels we supposedly support. */ /* Bitmap of the mixer input channels we supposedly support. */ /* Ioctl is only supported on mixer audio devices. */ * Audio ioctl conversion support structures. * Ioctl translator definitions. * Defines to help with creating ioctl translators. * IOC_CMD_TRANSLATOR_NONE - Ioctl has the same semantics and argument * values on Solaris and Linux but may have different command values. * (Macro assumes the symbolic Linux name assigned to the ioctl command * value is the same as the Solaris symbol but pre-pended with an "LX_") * IOC_CMD_TRANSLATOR_PASS - Ioctl is a Linux specific ioctl and should * be passed through unmodified. * IOC_CMD_TRANSLATOR_FILTER - Ioctl has the same command name on * Solaris and Linux and needs a translation function that is common to * more than one ioctl. (Macro assumes the symbolic Linux name assigned * to the ioctl command value is the same as the Solaris symbol but * pre-pended with an "LX_") * IOC_CMD_TRANSLATOR_CUSTOM - Ioctl needs special handling via a /* All files will need to support these ioctls. */ /* Any files supporting streams semantics will need these ioctls. */ * Translators for non-device files. * Translators for devices. * /dev/tty (which is implemented via the "sy" driver) is basically * a layered driver that passes on requests to the ctty for the * current process. Since ctty's are currently always implemented * via the pts driver, we should make sure to support all the * same ioctls on the sy driver as we do on the pts driver. "zcons",
/* idt_driver */ "lx_audio",
/* idt_driver */ * An array of all the device translators. * Translators for filesystems. * An array of all the filesystem translators. * Ioctl error translator definitions.