File Index
Files and directories
Sign in
FILE

ews.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/ice1712/ews.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *   ALSA driver for ICEnsemble ICE1712 (Envy24)
   4 *
   5 *   Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire
   6 *
   7 *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz>
   8 *                    2002 Takashi Iwai <tiwai@suse.de>
   9 */      
  10
  11#include <linux/delay.h>
  12#include <linux/interrupt.h>
  13#include <linux/init.h>
  14#include <linux/slab.h>
  15#include <sound/core.h>
  16#include <sound/cs8427.h>
  17#include <sound/asoundef.h>
  18
  19#include "ice1712.h"
  20#include "ews.h"
  21
  22#define SND_CS8404
  23#include <sound/cs8403.h>
  24
  25enum {
  26	EWS_I2C_CS8404 = 0, EWS_I2C_PCF1, EWS_I2C_PCF2,
  27	EWS_I2C_88D = 0,
  28	EWS_I2C_6FIRE = 0
  29};
  30	
  31
  32/* additional i2c devices for EWS boards */
  33struct ews_spec {
  34	struct snd_i2c_device *i2cdevs[3];
  35};
  36
  37/*
  38 * access via i2c mode (for EWX 24/96, EWS 88MT&D)
  39 */
  40
  41/* send SDA and SCL */
  42static void ewx_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
  43{
  44	struct snd_ice1712 *ice = bus->private_data;
  45	unsigned char tmp = 0;
  46	if (clk)
  47		tmp |= ICE1712_EWX2496_SERIAL_CLOCK;
  48	if (data)
  49		tmp |= ICE1712_EWX2496_SERIAL_DATA;
  50	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
  51	udelay(5);
  52}
  53
  54static int ewx_i2c_getclock(struct snd_i2c_bus *bus)
  55{
  56	struct snd_ice1712 *ice = bus->private_data;
  57	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_CLOCK ? 1 : 0;
  58}
  59
  60static int ewx_i2c_getdata(struct snd_i2c_bus *bus, int ack)
  61{
  62	struct snd_ice1712 *ice = bus->private_data;
  63	int bit;
  64	/* set RW pin to low */
  65	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_RW);
  66	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, 0);
  67	if (ack)
  68		udelay(5);
  69	bit = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_DATA ? 1 : 0;
  70	/* set RW pin to high */
  71	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ICE1712_EWX2496_RW);
  72	/* reset write mask */
  73	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_SERIAL_CLOCK);
  74	return bit;
  75}
  76
  77static void ewx_i2c_start(struct snd_i2c_bus *bus)
  78{
  79	struct snd_ice1712 *ice = bus->private_data;
  80	unsigned char mask;
  81
  82	snd_ice1712_save_gpio_status(ice);
  83	/* set RW high */
  84	mask = ICE1712_EWX2496_RW;
  85	switch (ice->eeprom.subvendor) {
  86	case ICE1712_SUBDEVICE_EWX2496:
  87		mask |= ICE1712_EWX2496_AK4524_CS; /* CS high also */
  88		break;
  89	case ICE1712_SUBDEVICE_DMX6FIRE:
  90		mask |= ICE1712_6FIRE_AK4524_CS_MASK; /* CS high also */
  91		break;
  92	}
  93	snd_ice1712_gpio_write_bits(ice, mask, mask);
  94}
  95
  96static void ewx_i2c_stop(struct snd_i2c_bus *bus)
  97{
  98	struct snd_ice1712 *ice = bus->private_data;
  99	snd_ice1712_restore_gpio_status(ice);
 100}
 101
 102static void ewx_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
 103{
 104	struct snd_ice1712 *ice = bus->private_data;
 105	unsigned char mask = 0;
 106
 107	if (clock)
 108		mask |= ICE1712_EWX2496_SERIAL_CLOCK; /* write SCL */
 109	if (data)
 110		mask |= ICE1712_EWX2496_SERIAL_DATA; /* write SDA */
 111	ice->gpio.direction &= ~(ICE1712_EWX2496_SERIAL_CLOCK|ICE1712_EWX2496_SERIAL_DATA);
 112	ice->gpio.direction |= mask;
 113	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction);
 114	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);
 115}
 116
 117static struct snd_i2c_bit_ops snd_ice1712_ewx_cs8427_bit_ops = {
 118	.start = ewx_i2c_start,
 119	.stop = ewx_i2c_stop,
 120	.direction = ewx_i2c_direction,
 121	.setlines = ewx_i2c_setlines,
 122	.getclock = ewx_i2c_getclock,
 123	.getdata = ewx_i2c_getdata,
 124};
 125
 126
 127/*
 128 * AK4524 access
 129 */
 130
 131/* AK4524 chip select; address 0x48 bit 0-3 */
 132static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask)
 133{
 134	struct ews_spec *spec = ice->spec;
 135	unsigned char data, ndata;
 136
 137	if (snd_BUG_ON(chip_mask < 0 || chip_mask > 0x0f))
 138		return -EINVAL;
 139	snd_i2c_lock(ice->i2c);
 140	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)
 141		goto __error;
 142	ndata = (data & 0xf0) | chip_mask;
 143	if (ndata != data)
 144		if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], &ndata, 1)
 145		    != 1)
 146			goto __error;
 147	snd_i2c_unlock(ice->i2c);
 148	return 0;
 149
 150     __error:
 151	snd_i2c_unlock(ice->i2c);
 152	dev_err(ice->card->dev,
 153		"AK4524 chip select failed, check cable to the front module\n");
 154	return -EIO;
 155}
 156
 157/* start callback for EWS88MT, needs to select a certain chip mask */
 158static void ews88mt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
 159{
 160	struct snd_ice1712 *ice = ak->private_data[0];
 161	unsigned char tmp;
 162	/* assert AK4524 CS */
 163	if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
 164		dev_err(ice->card->dev, "fatal error (ews88mt chip select)\n");
 165	snd_ice1712_save_gpio_status(ice);
 166	tmp = ICE1712_EWS88_SERIAL_DATA |
 167		ICE1712_EWS88_SERIAL_CLOCK |
 168		ICE1712_EWS88_RW;
 169	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
 170			  ice->gpio.direction | tmp);
 171	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 172}
 173
 174/* stop callback for EWS88MT, needs to deselect chip mask */
 175static void ews88mt_ak4524_unlock(struct snd_akm4xxx *ak, int chip)
 176{
 177	struct snd_ice1712 *ice = ak->private_data[0];
 178	snd_ice1712_restore_gpio_status(ice);
 179	udelay(1);
 180	snd_ice1712_ews88mt_chip_select(ice, 0x0f);
 181}
 182
 183/* start callback for EWX24/96 */
 184static void ewx2496_ak4524_lock(struct snd_akm4xxx *ak, int chip)
 185{
 186	struct snd_ice1712 *ice = ak->private_data[0];
 187	unsigned char tmp;
 188	snd_ice1712_save_gpio_status(ice);
 189	tmp =  ICE1712_EWX2496_SERIAL_DATA |
 190		ICE1712_EWX2496_SERIAL_CLOCK |
 191		ICE1712_EWX2496_AK4524_CS |
 192		ICE1712_EWX2496_RW;
 193	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
 194			  ice->gpio.direction | tmp);
 195	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 196}
 197
 198/* start callback for DMX 6fire */
 199static void dmx6fire_ak4524_lock(struct snd_akm4xxx *ak, int chip)
 200{
 201	struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
 202	struct snd_ice1712 *ice = ak->private_data[0];
 203	unsigned char tmp;
 204	snd_ice1712_save_gpio_status(ice);
 205	tmp = priv->cs_mask = priv->cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK;
 206	tmp |= ICE1712_6FIRE_SERIAL_DATA |
 207		ICE1712_6FIRE_SERIAL_CLOCK |
 208		ICE1712_6FIRE_RW;
 209	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
 210			  ice->gpio.direction | tmp);
 211	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
 212}
 213
 214/*
 215 * CS8404 interface on EWS88MT/D
 216 */
 217
 218static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits)
 219{
 220	struct ews_spec *spec = ice->spec;
 221	unsigned char bytes[2];
 222
 223	snd_i2c_lock(ice->i2c);
 224	switch (ice->eeprom.subvendor) {
 225	case ICE1712_SUBDEVICE_EWS88MT:
 226	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 227	case ICE1712_SUBDEVICE_PHASE88:
 228	case ICE1712_SUBDEVICE_TS88:
 229		if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_CS8404], &bits, 1)
 230		    != 1)
 231			goto _error;
 232		break;
 233	case ICE1712_SUBDEVICE_EWS88D:
 234		if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], bytes, 2)
 235		    != 2)
 236			goto _error;
 237		if (bits != bytes[1]) {
 238			bytes[1] = bits;
 239			if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D],
 240					      bytes, 2) != 2)
 241				goto _error;
 242		}
 243		break;
 244	}
 245 _error:
 246	snd_i2c_unlock(ice->i2c);
 247}
 248
 249/*
 250 */
 251
 252static void ews88_spdif_default_get(struct snd_ice1712 *ice, struct snd_ctl_elem_value *ucontrol)
 253{
 254	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_bits);
 255}
 256
 257static int ews88_spdif_default_put(struct snd_ice1712 *ice, struct snd_ctl_elem_value *ucontrol)
 258{
 259	unsigned int val;
 260	int change;
 261
 262	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
 263	scoped_guard(spinlock_irq, &ice->reg_lock) {
 264		change = ice->spdif.cs8403_bits != val;
 265		ice->spdif.cs8403_bits = val;
 266		if (!change || ice->playback_pro_substream)
 267			return change;
 268	}
 269	snd_ice1712_ews_cs8404_spdif_write(ice, val);
 270	return change;
 271}
 272
 273static void ews88_spdif_stream_get(struct snd_ice1712 *ice, struct snd_ctl_elem_value *ucontrol)
 274{
 275	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_stream_bits);
 276}
 277
 278static int ews88_spdif_stream_put(struct snd_ice1712 *ice, struct snd_ctl_elem_value *ucontrol)
 279{
 280	unsigned int val;
 281	int change;
 282
 283	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
 284	scoped_guard(spinlock_irq, &ice->reg_lock) {
 285		change = ice->spdif.cs8403_stream_bits != val;
 286		ice->spdif.cs8403_stream_bits = val;
 287		if (!change || ice->playback_pro_substream)
 288			return change;
 289	}
 290	snd_ice1712_ews_cs8404_spdif_write(ice, val);
 291	return change;
 292}
 293
 294
 295/* open callback */
 296static void ews88_open_spdif(struct snd_ice1712 *ice, struct snd_pcm_substream *substream)
 297{
 298	ice->spdif.cs8403_stream_bits = ice->spdif.cs8403_bits;
 299}
 300
 301/* set up SPDIF for EWS88MT / EWS88D */
 302static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate)
 303{
 304	unsigned char tmp;
 305	int change;
 306
 307	scoped_guard(spinlock_irqsave, &ice->reg_lock) {
 308		tmp = ice->spdif.cs8403_stream_bits;
 309		if (tmp & 0x10)		/* consumer */
 310			tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;
 311		switch (rate) {
 312		case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;
 313		case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
 314		case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;
 315		default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
 316		}
 317		change = ice->spdif.cs8403_stream_bits != tmp;
 318		ice->spdif.cs8403_stream_bits = tmp;
 319	}
 320	if (change)
 321		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);
 322	snd_ice1712_ews_cs8404_spdif_write(ice, tmp);
 323}
 324
 325
 326/*
 327 */
 328static const struct snd_akm4xxx akm_ews88mt = {
 329	.num_adcs = 8,
 330	.num_dacs = 8,
 331	.type = SND_AK4524,
 332	.ops = {
 333		.lock = ews88mt_ak4524_lock,
 334		.unlock = ews88mt_ak4524_unlock
 335	}
 336};
 337
 338static const struct snd_ak4xxx_private akm_ews88mt_priv = {
 339	.caddr = 2,
 340	.cif = 1, /* CIF high */
 341	.data_mask = ICE1712_EWS88_SERIAL_DATA,
 342	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,
 343	.cs_mask = 0,
 344	.cs_addr = 0,
 345	.cs_none = 0, /* no chip select on gpio */
 346	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */
 347	.mask_flags = 0,
 348};
 349
 350static const struct snd_akm4xxx akm_ewx2496 = {
 351	.num_adcs = 2,
 352	.num_dacs = 2,
 353	.type = SND_AK4524,
 354	.ops = {
 355		.lock = ewx2496_ak4524_lock
 356	}
 357};
 358
 359static const struct snd_ak4xxx_private akm_ewx2496_priv = {
 360	.caddr = 2,
 361	.cif = 1, /* CIF high */
 362	.data_mask = ICE1712_EWS88_SERIAL_DATA,
 363	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,
 364	.cs_mask = ICE1712_EWX2496_AK4524_CS,
 365	.cs_addr = ICE1712_EWX2496_AK4524_CS,
 366	.cs_none = 0,
 367	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */
 368	.mask_flags = 0,
 369};
 370
 371static const struct snd_akm4xxx akm_6fire = {
 372	.num_adcs = 6,
 373	.num_dacs = 6,
 374	.type = SND_AK4524,
 375	.ops = {
 376		.lock = dmx6fire_ak4524_lock
 377	}
 378};
 379
 380static const struct snd_ak4xxx_private akm_6fire_priv = {
 381	.caddr = 2,
 382	.cif = 1, /* CIF high */
 383	.data_mask = ICE1712_6FIRE_SERIAL_DATA,
 384	.clk_mask = ICE1712_6FIRE_SERIAL_CLOCK,
 385	.cs_mask = 0,
 386	.cs_addr = 0, /* set later */
 387	.cs_none = 0,
 388	.add_flags = ICE1712_6FIRE_RW, /* set rw bit high */
 389	.mask_flags = 0,
 390};
 391
 392/*
 393 * initialize the chip
 394 */
 395
 396/* 6fire specific */
 397#define PCF9554_REG_INPUT      0
 398#define PCF9554_REG_OUTPUT     1
 399#define PCF9554_REG_POLARITY   2
 400#define PCF9554_REG_CONFIG     3
 401
 402static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data);
 403
 404static int snd_ice1712_ews_init(struct snd_ice1712 *ice)
 405{
 406	int err;
 407	struct snd_akm4xxx *ak;
 408	struct ews_spec *spec;
 409
 410	/* set the analog DACs */
 411	switch (ice->eeprom.subvendor) {
 412	case ICE1712_SUBDEVICE_EWX2496:
 413		ice->num_total_dacs = 2;
 414		ice->num_total_adcs = 2;
 415		break;	
 416	case ICE1712_SUBDEVICE_EWS88MT:
 417	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 418	case ICE1712_SUBDEVICE_PHASE88:
 419	case ICE1712_SUBDEVICE_TS88:
 420		ice->num_total_dacs = 8;
 421		ice->num_total_adcs = 8;
 422		break;
 423	case ICE1712_SUBDEVICE_EWS88D:
 424		/* Note: not analog but ADAT I/O */
 425		ice->num_total_dacs = 8;
 426		ice->num_total_adcs = 8;
 427		break;
 428	case ICE1712_SUBDEVICE_DMX6FIRE:
 429		ice->num_total_dacs = 6;
 430		ice->num_total_adcs = 6;
 431		break;
 432	}
 433
 434	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 435	if (!spec)
 436		return -ENOMEM;
 437	ice->spec = spec;
 438
 439	/* create i2c */
 440	err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c);
 441	if (err < 0) {
 442		dev_err(ice->card->dev, "unable to create I2C bus\n");
 443		return err;
 444	}
 445	ice->i2c->private_data = ice;
 446	ice->i2c->hw_ops.bit = &snd_ice1712_ewx_cs8427_bit_ops;
 447
 448	/* create i2c devices */
 449	switch (ice->eeprom.subvendor) {
 450	case ICE1712_SUBDEVICE_DMX6FIRE:
 451		err = snd_i2c_device_create(ice->i2c, "PCF9554",
 452					    ICE1712_6FIRE_PCF9554_ADDR,
 453					    &spec->i2cdevs[EWS_I2C_6FIRE]);
 454		if (err < 0) {
 455			dev_err(ice->card->dev,
 456				"PCF9554 initialization failed\n");
 457			return err;
 458		}
 459		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80);
 460		break;
 461	case ICE1712_SUBDEVICE_EWS88MT:
 462	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 463	case ICE1712_SUBDEVICE_PHASE88:
 464	case ICE1712_SUBDEVICE_TS88:
 465
 466		err = snd_i2c_device_create(ice->i2c, "CS8404",
 467					    ICE1712_EWS88MT_CS8404_ADDR,
 468					    &spec->i2cdevs[EWS_I2C_CS8404]);
 469		if (err < 0)
 470			return err;
 471		err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)",
 472					    ICE1712_EWS88MT_INPUT_ADDR,
 473					    &spec->i2cdevs[EWS_I2C_PCF1]);
 474		if (err < 0)
 475			return err;
 476		err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)",
 477					    ICE1712_EWS88MT_OUTPUT_ADDR,
 478					    &spec->i2cdevs[EWS_I2C_PCF2]);
 479		if (err < 0)
 480			return err;
 481		/* Check if the front module is connected */
 482		err = snd_ice1712_ews88mt_chip_select(ice, 0x0f);
 483		if (err < 0)
 484			return err;
 485		break;
 486	case ICE1712_SUBDEVICE_EWS88D:
 487		err = snd_i2c_device_create(ice->i2c, "PCF8575",
 488					    ICE1712_EWS88D_PCF_ADDR,
 489					    &spec->i2cdevs[EWS_I2C_88D]);
 490		if (err < 0)
 491			return err;
 492		break;
 493	}
 494
 495	/* set up SPDIF interface */
 496	switch (ice->eeprom.subvendor) {
 497	case ICE1712_SUBDEVICE_EWX2496:
 498		err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR);
 499		if (err < 0)
 500			return err;
 501		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);
 502		break;
 503	case ICE1712_SUBDEVICE_DMX6FIRE:
 504		err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR);
 505		if (err < 0)
 506			return err;
 507		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);
 508		break;
 509	case ICE1712_SUBDEVICE_EWS88MT:
 510	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 511	case ICE1712_SUBDEVICE_PHASE88:
 512	case ICE1712_SUBDEVICE_TS88:
 513	case ICE1712_SUBDEVICE_EWS88D:
 514		/* set up CS8404 */
 515		ice->spdif.ops.open = ews88_open_spdif;
 516		ice->spdif.ops.setup_rate = ews88_setup_spdif;
 517		ice->spdif.ops.default_get = ews88_spdif_default_get;
 518		ice->spdif.ops.default_put = ews88_spdif_default_put;
 519		ice->spdif.ops.stream_get = ews88_spdif_stream_get;
 520		ice->spdif.ops.stream_put = ews88_spdif_stream_put;
 521		/* Set spdif defaults */
 522		snd_ice1712_ews_cs8404_spdif_write(ice, ice->spdif.cs8403_bits);
 523		break;
 524	}
 525
 526	/* no analog? */
 527	switch (ice->eeprom.subvendor) {
 528	case ICE1712_SUBDEVICE_EWS88D:
 529		return 0;
 530	}
 531
 532	/* analog section */
 533	ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
 534	if (! ak)
 535		return -ENOMEM;
 536	ice->akm_codecs = 1;
 537
 538	switch (ice->eeprom.subvendor) {
 539	case ICE1712_SUBDEVICE_EWS88MT:
 540	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 541	case ICE1712_SUBDEVICE_PHASE88:
 542	case ICE1712_SUBDEVICE_TS88:
 543		err = snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, &akm_ews88mt_priv, ice);
 544		break;
 545	case ICE1712_SUBDEVICE_EWX2496:
 546		err = snd_ice1712_akm4xxx_init(ak, &akm_ewx2496, &akm_ewx2496_priv, ice);
 547		break;
 548	case ICE1712_SUBDEVICE_DMX6FIRE:
 549		err = snd_ice1712_akm4xxx_init(ak, &akm_6fire, &akm_6fire_priv, ice);
 550		break;
 551	default:
 552		err = 0;
 553	}
 554
 555	return err;
 556}
 557
 558/*
 559 * EWX 24/96 specific controls
 560 */
 561
 562/* i/o sensitivity - this callback is shared among other devices, too */
 563static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){
 564
 565	static const char * const texts[2] = {
 566		"+4dBu", "-10dBV",
 567	};
 568	return snd_ctl_enum_info(uinfo, 1, 2, texts);
 569}
 570
 571static int snd_ice1712_ewx_io_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 572{
 573	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 574	unsigned char mask = kcontrol->private_value & 0xff;
 575	
 576	snd_ice1712_save_gpio_status(ice);
 577	ucontrol->value.enumerated.item[0] = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & mask ? 1 : 0;
 578	snd_ice1712_restore_gpio_status(ice);
 579	return 0;
 580}
 581
 582static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 583{
 584	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 585	unsigned char mask = kcontrol->private_value & 0xff;
 586	int val, nval;
 587
 588	if (kcontrol->private_value & (1 << 31))
 589		return -EPERM;
 590	nval = ucontrol->value.enumerated.item[0] ? mask : 0;
 591	snd_ice1712_save_gpio_status(ice);
 592	val = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 593	nval |= val & ~mask;
 594	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, nval);
 595	snd_ice1712_restore_gpio_status(ice);
 596	return val != nval;
 597}
 598
 599static const struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] = {
 600	{
 601		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 602		.name = "Input Sensitivity Switch",
 603		.info = snd_ice1712_ewx_io_sense_info,
 604		.get = snd_ice1712_ewx_io_sense_get,
 605		.put = snd_ice1712_ewx_io_sense_put,
 606		.private_value = ICE1712_EWX2496_AIN_SEL,
 607	},
 608	{
 609		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 610		.name = "Output Sensitivity Switch",
 611		.info = snd_ice1712_ewx_io_sense_info,
 612		.get = snd_ice1712_ewx_io_sense_get,
 613		.put = snd_ice1712_ewx_io_sense_put,
 614		.private_value = ICE1712_EWX2496_AOUT_SEL,
 615	},
 616};
 617
 618
 619/*
 620 * EWS88MT specific controls
 621 */
 622/* analog output sensitivity;; address 0x48 bit 6 */
 623static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 624{
 625	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 626	struct ews_spec *spec = ice->spec;
 627	unsigned char data;
 628
 629	snd_i2c_lock(ice->i2c);
 630	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
 631		snd_i2c_unlock(ice->i2c);
 632		return -EIO;
 633	}
 634	snd_i2c_unlock(ice->i2c);
 635	ucontrol->value.enumerated.item[0] = data & ICE1712_EWS88MT_OUTPUT_SENSE ? 1 : 0; /* high = -10dBV, low = +4dBu */
 636	return 0;
 637}
 638
 639/* analog output sensitivity;; address 0x48 bit 6 */
 640static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 641{
 642	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 643	struct ews_spec *spec = ice->spec;
 644	unsigned char data, ndata;
 645
 646	snd_i2c_lock(ice->i2c);
 647	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
 648		snd_i2c_unlock(ice->i2c);
 649		return -EIO;
 650	}
 651	ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0);
 652	if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2],
 653					       &ndata, 1) != 1) {
 654		snd_i2c_unlock(ice->i2c);
 655		return -EIO;
 656	}
 657	snd_i2c_unlock(ice->i2c);
 658	return ndata != data;
 659}
 660
 661/* analog input sensitivity; address 0x46 */
 662static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 663{
 664	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 665	struct ews_spec *spec = ice->spec;
 666	int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 667	unsigned char data;
 668
 669	if (snd_BUG_ON(channel < 0 || channel > 7))
 670		return 0;
 671	snd_i2c_lock(ice->i2c);
 672	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
 673		snd_i2c_unlock(ice->i2c);
 674		return -EIO;
 675	}
 676	/* reversed; high = +4dBu, low = -10dBV */
 677	ucontrol->value.enumerated.item[0] = data & (1 << channel) ? 0 : 1;
 678	snd_i2c_unlock(ice->i2c);
 679	return 0;
 680}
 681
 682/* analog output sensitivity; address 0x46 */
 683static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 684{
 685	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 686	struct ews_spec *spec = ice->spec;
 687	int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 688	unsigned char data, ndata;
 689
 690	if (snd_BUG_ON(channel < 0 || channel > 7))
 691		return 0;
 692	snd_i2c_lock(ice->i2c);
 693	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
 694		snd_i2c_unlock(ice->i2c);
 695		return -EIO;
 696	}
 697	ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel));
 698	if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF1],
 699					       &ndata, 1) != 1) {
 700		snd_i2c_unlock(ice->i2c);
 701		return -EIO;
 702	}
 703	snd_i2c_unlock(ice->i2c);
 704	return ndata != data;
 705}
 706
 707static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = {
 708	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 709	.name = "Input Sensitivity Switch",
 710	.info = snd_ice1712_ewx_io_sense_info,
 711	.get = snd_ice1712_ews88mt_input_sense_get,
 712	.put = snd_ice1712_ews88mt_input_sense_put,
 713	.count = 8,
 714};
 715
 716static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = {
 717	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 718	.name = "Output Sensitivity Switch",
 719	.info = snd_ice1712_ewx_io_sense_info,
 720	.get = snd_ice1712_ews88mt_output_sense_get,
 721	.put = snd_ice1712_ews88mt_output_sense_put,
 722};
 723
 724
 725/*
 726 * EWS88D specific controls
 727 */
 728
 729#define snd_ice1712_ews88d_control_info		snd_ctl_boolean_mono_info
 730
 731static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 732{
 733	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 734	struct ews_spec *spec = ice->spec;
 735	int shift = kcontrol->private_value & 0xff;
 736	int invert = (kcontrol->private_value >> 8) & 1;
 737	unsigned char data[2];
 738	
 739	snd_i2c_lock(ice->i2c);
 740	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
 741		snd_i2c_unlock(ice->i2c);
 742		return -EIO;
 743	}
 744	snd_i2c_unlock(ice->i2c);
 745	data[0] = (data[shift >> 3] >> (shift & 7)) & 0x01;
 746	if (invert)
 747		data[0] ^= 0x01;
 748	ucontrol->value.integer.value[0] = data[0];
 749	return 0;
 750}
 751
 752static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 753{
 754	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 755	struct ews_spec *spec = ice->spec;
 756	int shift = kcontrol->private_value & 0xff;
 757	int invert = (kcontrol->private_value >> 8) & 1;
 758	unsigned char data[2], ndata[2];
 759	int change;
 760
 761	snd_i2c_lock(ice->i2c);
 762	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
 763		snd_i2c_unlock(ice->i2c);
 764		return -EIO;
 765	}
 766	ndata[shift >> 3] = data[shift >> 3] & ~(1 << (shift & 7));
 767	if (invert) {
 768		if (! ucontrol->value.integer.value[0])
 769			ndata[shift >> 3] |= (1 << (shift & 7));
 770	} else {
 771		if (ucontrol->value.integer.value[0])
 772			ndata[shift >> 3] |= (1 << (shift & 7));
 773	}
 774	change = (data[shift >> 3] != ndata[shift >> 3]);
 775	if (change &&
 776	    snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
 777		snd_i2c_unlock(ice->i2c);
 778		return -EIO;
 779	}
 780	snd_i2c_unlock(ice->i2c);
 781	return change;
 782}
 783
 784#define EWS88D_CONTROL(xiface, xname, xshift, xinvert, xaccess) \
 785{ .iface = xiface,\
 786  .name = xname,\
 787  .access = xaccess,\
 788  .info = snd_ice1712_ews88d_control_info,\
 789  .get = snd_ice1712_ews88d_control_get,\
 790  .put = snd_ice1712_ews88d_control_put,\
 791  .private_value = xshift | (xinvert << 8),\
 792}
 793
 794static const struct snd_kcontrol_new snd_ice1712_ews88d_controls[] = {
 795	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */
 796	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0),
 797	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0),
 798	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "Enable ADAT", 3, 0, 0),
 799	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Through", 4, 1, 0),
 800};
 801
 802
 803/*
 804 * DMX 6Fire specific controls
 805 */
 806
 807static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg)
 808{
 809	unsigned char byte;
 810	struct ews_spec *spec = ice->spec;
 811
 812	snd_i2c_lock(ice->i2c);
 813	byte = reg;
 814	if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
 815		snd_i2c_unlock(ice->i2c);
 816		dev_err(ice->card->dev, "cannot send pca\n");
 817		return -EIO;
 818	}
 819
 820	byte = 0;
 821	if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
 822		snd_i2c_unlock(ice->i2c);
 823		dev_err(ice->card->dev, "cannot read pca\n");
 824		return -EIO;
 825	}
 826	snd_i2c_unlock(ice->i2c);
 827	return byte;
 828}
 829
 830static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data)
 831{
 832	unsigned char bytes[2];
 833	struct ews_spec *spec = ice->spec;
 834
 835	snd_i2c_lock(ice->i2c);
 836	bytes[0] = reg;
 837	bytes[1] = data;
 838	if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) {
 839		snd_i2c_unlock(ice->i2c);
 840		return -EIO;
 841	}
 842	snd_i2c_unlock(ice->i2c);
 843	return 0;
 844}
 845
 846#define snd_ice1712_6fire_control_info		snd_ctl_boolean_mono_info
 847
 848static int snd_ice1712_6fire_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 849{
 850	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 851	int shift = kcontrol->private_value & 0xff;
 852	int invert = (kcontrol->private_value >> 8) & 1;
 853	int data;
 854	
 855	data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT);
 856	if (data < 0)
 857		return data;
 858	data = (data >> shift) & 1;
 859	if (invert)
 860		data ^= 1;
 861	ucontrol->value.integer.value[0] = data;
 862	return 0;
 863}
 864
 865static int snd_ice1712_6fire_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 866{
 867	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 868	int shift = kcontrol->private_value & 0xff;
 869	int invert = (kcontrol->private_value >> 8) & 1;
 870	int data, ndata;
 871	
 872	data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT);
 873	if (data < 0)
 874		return data;
 875	ndata = data & ~(1 << shift);
 876	if (ucontrol->value.integer.value[0])
 877		ndata |= (1 << shift);
 878	if (invert)
 879		ndata ^= (1 << shift);
 880	if (data != ndata) {
 881		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
 882		return 1;
 883	}
 884	return 0;
 885}
 886
 887static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 888{
 889	static const char * const texts[4] = {
 890		"Internal", "Front Input", "Rear Input", "Wave Table"
 891	};
 892	return snd_ctl_enum_info(uinfo, 1, 4, texts);
 893}
 894     
 895static int snd_ice1712_6fire_select_input_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 896{
 897	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 898	int data;
 899	
 900	data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT);
 901	if (data < 0)
 902		return data;
 903	ucontrol->value.integer.value[0] = data & 3;
 904	return 0;
 905}
 906
 907static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 908{
 909	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 910	int data, ndata;
 911	
 912	data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT);
 913	if (data < 0)
 914		return data;
 915	ndata = data & ~3;
 916	ndata |= (ucontrol->value.integer.value[0] & 3);
 917	if (data != ndata) {
 918		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
 919		return 1;
 920	}
 921	return 0;
 922}
 923
 924
 925#define DMX6FIRE_CONTROL(xname, xshift, xinvert) \
 926{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
 927  .name = xname,\
 928  .info = snd_ice1712_6fire_control_info,\
 929  .get = snd_ice1712_6fire_control_get,\
 930  .put = snd_ice1712_6fire_control_put,\
 931  .private_value = xshift | (xinvert << 8),\
 932}
 933
 934static const struct snd_kcontrol_new snd_ice1712_6fire_controls[] = {
 935	{
 936		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 937		.name = "Analog Input Select",
 938		.info = snd_ice1712_6fire_select_input_info,
 939		.get = snd_ice1712_6fire_select_input_get,
 940		.put = snd_ice1712_6fire_select_input_put,
 941	},
 942	DMX6FIRE_CONTROL("Front Digital Input Switch", 2, 1),
 943	// DMX6FIRE_CONTROL("Master Clock Select", 3, 0),
 944	DMX6FIRE_CONTROL("Optical Digital Input Switch", 4, 0),
 945	DMX6FIRE_CONTROL("Phono Analog Input Switch", 5, 0),
 946	DMX6FIRE_CONTROL("Breakbox LED", 6, 0),
 947};
 948
 949
 950static int snd_ice1712_ews_add_controls(struct snd_ice1712 *ice)
 951{
 952	unsigned int idx;
 953	int err;
 954	
 955	/* all terratec cards have spdif, but cs8427 module builds it's own controls */
 956	if (ice->cs8427 == NULL) {
 957		err = snd_ice1712_spdif_build_controls(ice);
 958		if (err < 0)
 959			return err;
 960	}
 961
 962	/* ak4524 controls */
 963	switch (ice->eeprom.subvendor) {
 964	case ICE1712_SUBDEVICE_EWX2496:
 965	case ICE1712_SUBDEVICE_EWS88MT:
 966	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 967	case ICE1712_SUBDEVICE_PHASE88:
 968	case ICE1712_SUBDEVICE_TS88:
 969	case ICE1712_SUBDEVICE_DMX6FIRE:
 970		err = snd_ice1712_akm4xxx_build_controls(ice);
 971		if (err < 0)
 972			return err;
 973		break;
 974	}
 975
 976	/* card specific controls */
 977	switch (ice->eeprom.subvendor) {
 978	case ICE1712_SUBDEVICE_EWX2496:
 979		for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_ewx2496_controls); idx++) {
 980			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ewx2496_controls[idx], ice));
 981			if (err < 0)
 982				return err;
 983		}
 984		break;
 985	case ICE1712_SUBDEVICE_EWS88MT:
 986	case ICE1712_SUBDEVICE_EWS88MT_NEW:
 987	case ICE1712_SUBDEVICE_PHASE88:
 988	case ICE1712_SUBDEVICE_TS88:
 989		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice));
 990		if (err < 0)
 991			return err;
 992		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_output_sense, ice));
 993		if (err < 0)
 994			return err;
 995		break;
 996	case ICE1712_SUBDEVICE_EWS88D:
 997		for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_ews88d_controls); idx++) {
 998			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88d_controls[idx], ice));
 999			if (err < 0)
1000				return err;
1001		}
1002		break;
1003	case ICE1712_SUBDEVICE_DMX6FIRE:
1004		for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_6fire_controls); idx++) {
1005			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_controls[idx], ice));
1006			if (err < 0)
1007				return err;
1008		}
1009		break;
1010	}
1011	return 0;
1012}
1013
1014
1015/* entry point */
1016struct snd_ice1712_card_info snd_ice1712_ews_cards[] = {
1017	{
1018		.subvendor = ICE1712_SUBDEVICE_EWX2496,
1019		.name = "TerraTec EWX24/96",
1020		.model = "ewx2496",
1021		.chip_init = snd_ice1712_ews_init,
1022		.build_controls = snd_ice1712_ews_add_controls,
1023	},
1024	{
1025		.subvendor = ICE1712_SUBDEVICE_EWS88MT,
1026		.name = "TerraTec EWS88MT",
1027		.model = "ews88mt",
1028		.chip_init = snd_ice1712_ews_init,
1029		.build_controls = snd_ice1712_ews_add_controls,
1030	},
1031	{
1032		.subvendor = ICE1712_SUBDEVICE_EWS88MT_NEW,
1033		.name = "TerraTec EWS88MT",
1034		.model = "ews88mt_new",
1035		.chip_init = snd_ice1712_ews_init,
1036		.build_controls = snd_ice1712_ews_add_controls,
1037	},
1038	{
1039		.subvendor = ICE1712_SUBDEVICE_PHASE88,
1040		.name = "TerraTec Phase88",
1041		.model = "phase88",
1042		.chip_init = snd_ice1712_ews_init,
1043		.build_controls = snd_ice1712_ews_add_controls,
1044	},
1045	{
1046		.subvendor = ICE1712_SUBDEVICE_TS88,
1047		.name = "terrasoniq TS88",
1048		.model = "phase88",
1049		.chip_init = snd_ice1712_ews_init,
1050		.build_controls = snd_ice1712_ews_add_controls,
1051	},
1052	{
1053		.subvendor = ICE1712_SUBDEVICE_EWS88D,
1054		.name = "TerraTec EWS88D",
1055		.model = "ews88d",
1056		.chip_init = snd_ice1712_ews_init,
1057		.build_controls = snd_ice1712_ews_add_controls,
1058	},
1059	{
1060		.subvendor = ICE1712_SUBDEVICE_DMX6FIRE,
1061		.name = "TerraTec DMX6Fire",
1062		.model = "dmx6fire",
1063		.chip_init = snd_ice1712_ews_init,
1064		.build_controls = snd_ice1712_ews_add_controls,
1065		.mpu401_1_name = "MIDI-Front DMX6fire",
1066		.mpu401_2_name = "Wavetable DMX6fire",
1067		.mpu401_2_info_flags = MPU401_INFO_OUTPUT,
1068	},
1069	{ } /* terminator */
1070};
~/ Read-only file preview.