// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140
* Copyright (c) 2006 by Matthias König <mk@phasorlab.de>
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/parport.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include <sound/control.h>
#define CARD_NAME "Miditerminal 4140"
#define DRIVER_NAME "MTS64"
#define PLATFORM_DRIVER "snd_mts64"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static struct platform_device *platform_devices[SNDRV_CARDS];
static int device_count;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>");
MODULE_DESCRIPTION("ESI Miditerminal 4140");
MODULE_LICENSE("GPL");
/*********************************************************************
* Chip specific
*********************************************************************/
#define MTS64_NUM_INPUT_PORTS 5
#define MTS64_NUM_OUTPUT_PORTS 4
#define MTS64_SMPTE_SUBSTREAM 4
struct mts64 {
spinlock_t lock;
struct snd_card *card;
struct snd_rawmidi *rmidi;
struct pardevice *pardev;
int open_count;
int current_midi_output_port;
int current_midi_input_port;
u8 mode[MTS64_NUM_INPUT_PORTS];
struct snd_rawmidi_substream *midi_input_substream[MTS64_NUM_INPUT_PORTS];
int smpte_switch;
u8 time[4]; /* [0]=hh, [1]=mm, [2]=ss, [3]=ff */
u8 fps;
};
static int snd_mts64_free(struct mts64 *mts)
{
kfree(mts);
return 0;
}
static int snd_mts64_create(struct snd_card *card,
struct pardevice *pardev,
struct mts64 **rchip)
{
struct mts64 *mts;
*rchip = NULL;
mts = kzalloc(sizeof(struct mts64), GFP_KERNEL);
if (mts == NULL)
return -ENOMEM;
/* Init chip specific data */
spin_lock_init(&mts->lock);
mts->card = card;
mts->pardev = pardev;
mts->current_midi_output_port = -1;
mts->current_midi_input_port = -1;
*rchip = mts;
return 0;
}
/*********************************************************************
* HW register related constants
*********************************************************************/
/* Status Bits */
#define MTS64_STAT_BSY 0x80
#define MTS64_STAT_BIT_SET 0x20 /* readout process, bit is set */
#define MTS64_STAT_PORT 0x10 /* read byte is a port number */
/* Control Bits */
#define MTS64_CTL_READOUT 0x08 /* enable readout */
#define MTS64_CTL_WRITE_CMD 0x06
#define MTS64_CTL_WRITE_DATA 0x02
#define MTS64_CTL_STROBE 0x01
/* Command */
#define MTS64_CMD_RESET 0xfe
#define MTS64_CMD_PROBE 0x8f /* Used in probing procedure */
#define MTS64_CMD_SMPTE_SET_TIME 0xe8
#define MTS64_CMD_SMPTE_SET_FPS 0xee
#define MTS64_CMD_SMPTE_STOP 0xef
#define MTS64_CMD_SMPTE_FPS_24 0xe3
#define MTS64_CMD_SMPTE_FPS_25 0xe2
#define MTS64_CMD_SMPTE_FPS_2997 0xe4
#define MTS64_CMD_SMPTE_FPS_30D 0xe1
#define MTS64_CMD_SMPTE_FPS_30 0xe0
#define MTS64_CMD_COM_OPEN 0xf8 /* setting the communication mode */
#define MTS64_CMD_COM_CLOSE1 0xff /* clearing communication mode */
#define MTS64_CMD_COM_CLOSE2 0xf5
/*********************************************************************
* Hardware specific functions
*********************************************************************/
static void mts64_enable_readout(struct parport *p);
static void mts64_disable_readout(struct parport *p);
static int mts64_device_ready(struct parport *p);
static int mts64_device_init(struct parport *p);
static int mts64_device_open(struct mts64 *mts);
static int mts64_device_close(struct mts64 *mts);
static u8 mts64_map_midi_input(u8 c);
static int mts64_probe(struct parport *p);
static u16 mts64_read(struct parport *p);
static u8 mts64_read_char(struct parport *p);
static void mts64_smpte_start(struct parport *p,
u8 hours, u8 minutes,
u8 seconds, u8 frames,
u8 idx);
static void mts64_smpte_stop(struct parport *p);
static void mts64_write_command(struct parport *p, u8 c);
static void mts64_write_data(struct parport *p, u8 c);
static void mts64_write_midi(struct mts64 *mts, u8 c, int midiport);
/* Enables the readout procedure
*
* Before we can read a midi byte from the device, we have to set
* bit 3 of control port.
*/
static void mts64_enable_readout(struct parport *p)
{
u8 c;
c = parport_read_control(p);
c |= MTS64_CTL_READOUT;
parport_write_control(p, c);
}
/* Disables readout
*
* Readout is disabled by clearing bit 3 of control
*/
static void mts64_disable_readout(struct parport *p)
{
u8 c;
c = parport_read_control(p);
c &= ~MTS64_CTL_READOUT;
parport_write_control(p, c);
}
/* waits for device ready
*
* Checks if BUSY (Bit 7 of status) is clear
* 1 device ready
* 0 failure
*/
static int mts64_device_ready(struct parport *p)
{
int i;
u8 c;
for (i = 0; i < 0xffff; ++i) {
c = parport_read_status(p