⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mts64.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*      *   ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140 *   Copyright (c) 2006 by Matthias König <mk@phasorlab.de> * *   This program is free software; you can redistribute it and/or modify  *   it under the terms of the GNU General Public License as published by  *   the Free Software Foundation; either version 2 of the License, or  *   (at your option) any later version.  * *   This program is distributed in the hope that it will be useful,  *   but WITHOUT ANY WARRANTY; without even the implied warranty of  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#include <sound/driver.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/parport.h>#include <linux/spinlock.h>#include <linux/delay.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 int 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, S_IRUGO);MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");module_param_array(id, charp, NULL, S_IRUGO);MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");module_param_array(enable, bool, NULL, S_IRUGO);MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>");MODULE_DESCRIPTION("ESI Miditerminal 4140");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{ESI,Miditerminal 4140}}");/********************************************************************* * Chip specific *********************************************************************/#define MTS64_NUM_INPUT_PORTS 5#define MTS64_NUM_OUTPUT_PORTS 4#define MTS64_SMPTE_SUBSTREAM 4struct mts64 {	spinlock_t lock;	struct snd_card *card;	struct snd_rawmidi *rmidi;	struct pardevice *pardev;	int pardev_claimed;	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 __devinit 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);		c &= MTS64_STAT_BSY;		if (c != 0) 			return 1;	} 	return 0;}/*  Init device (LED blinking startup magic) * *  Returns: *  0 init ok *  -EIO failure */static int __devinit mts64_device_init(struct parport *p){	int i;	mts64_write_command(p, MTS64_CMD_RESET);	for (i = 0; i < 64; ++i) {		msleep(100);		if (mts64_probe(p) == 0) {			/* success */			mts64_disable_readout(p);			return 0;		}	}	mts64_disable_readout(p);	return -EIO;}/*  *  Opens the device (set communication mode) */static int mts64_device_open(struct mts64 *mts){	int i;	struct parport *p = mts->pardev->port;	for (i = 0; i < 5; ++i)		mts64_write_command(p, MTS64_CMD_COM_OPEN);	return 0;}/*   *  Close device (clear communication mode) */static int mts64_device_close(struct mts64 *mts){	int i;	struct parport *p = mts->pardev->port;	for (i = 0; i < 5; ++i) {		mts64_write_command(p, MTS64_CMD_COM_CLOSE1);		mts64_write_command(p, MTS64_CMD_COM_CLOSE2);	}	return 0;}/*  map hardware port to substream number *  *  When reading a byte from the device, the device tells us *  on what port the byte is. This HW port has to be mapped to *  the midiport (substream number). *  substream 0-3 are Midiports 1-4 *  substream 4 is SMPTE Timecode *  The mapping is done by the table: *  HW | 0 | 1 | 2 | 3 | 4  *  SW | 0 | 1 | 4 | 2 | 3 */static u8 mts64_map_midi_input(u8 c){	static u8 map[] = { 0, 1, 4, 2, 3 };	return map[c];}/*  Probe parport for device * *  Do we have a Miditerminal 4140 on parport?  *  Returns: *  0       device found *  -ENODEV no device */static int __devinit mts64_probe(struct parport *p){	u8 c;	mts64_smpte_stop(p);	mts64_write_command(p, MTS64_CMD_PROBE);	msleep(50);		c = mts64_read(p);	c &= 0x00ff;	if (c != MTS64_CMD_PROBE) 		return -ENODEV;	else 		return 0;}/*  Read byte incl. status from device * *  Returns: *  data in lower 8 bits and status in upper 8 bits */static u16 mts64_read(struct parport *p){	u8 data, status;	mts64_device_ready(p);	mts64_enable_readout(p);	status = parport_read_status(p);	data = mts64_read_char(p);	mts64_disable_readout(p);	return (status << 8) | data;}/*  Read a byte from device * *  Note, that readout mode has to be enabled. *  readout procedure is as follows:  *  - Write number of the Bit to read to DATA *  - Read STATUS *  - Bit 5 of STATUS indicates if Bit is set * *  Returns: *  Byte read from device */static u8 mts64_read_char(struct parport *p){	u8 c = 0;	u8 status;	u8 i;	for (i = 0; i < 8; ++i) {		parport_write_data(p, i);		c >>= 1;		status = parport_read_status(p);		if (status & MTS64_STAT_BIT_SET) 			c |= 0x80;	}		return c;}/*  Starts SMPTE Timecode generation * *  The device creates SMPTE Timecode by hardware. *  0 24 fps *  1 25 fps *  2 29.97 fps *  3 30 fps (Drop-frame) *  4 30 fps */static void mts64_smpte_start(struct parport *p,			      u8 hours, u8 minutes,			      u8 seconds, u8 frames,			      u8 idx){	static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, 			     MTS64_CMD_SMPTE_FPS_25,			     MTS64_CMD_SMPTE_FPS_2997, 			     MTS64_CMD_SMPTE_FPS_30D,			     MTS64_CMD_SMPTE_FPS_30    };	mts64_write_command(p, MTS64_CMD_SMPTE_SET_TIME);	mts64_write_command(p, frames);	mts64_write_command(p, seconds);	mts64_write_command(p, minutes);	mts64_write_command(p, hours);	mts64_write_command(p, MTS64_CMD_SMPTE_SET_FPS);	mts64_write_command(p, fps[idx]);}/*  Stops SMPTE Timecode generation */static void mts64_smpte_stop(struct parport *p){	mts64_write_command(p, MTS64_CMD_SMPTE_STOP);}/*  Write a command byte to device */static void mts64_write_command(struct parport *p, u8 c){	mts64_device_ready(p);	parport_write_data(p, c);	parport_write_control(p, MTS64_CTL_WRITE_CMD);	parport_write_control(p, MTS64_CTL_WRITE_CMD | MTS64_CTL_STROBE);	parport_write_control(p, MTS64_CTL_WRITE_CMD);}/*  Write a data byte to device  */static void mts64_write_data(struct parport *p, u8 c){	mts64_device_ready(p);	parport_write_data(p, c);	parport_write_control(p, MTS64_CTL_WRITE_DATA);	parport_write_control(p, MTS64_CTL_WRITE_DATA | MTS64_CTL_STROBE);	parport_write_control(p, MTS64_CTL_WRITE_DATA);}/*  Write a MIDI byte to midiport * *  midiport ranges from 0-3 and maps to Ports 1-4 *  assumptions: communication mode is on */static void mts64_write_midi(struct mts64 *mts, u8 c,			     int midiport){	struct parport *p = mts->pardev->port;	/* check current midiport */	if (mts->current_midi_output_port != midiport)		mts64_write_command(p, midiport);	/* write midi byte */	mts64_write_data(p, c);}/********************************************************************* * Control elements *********************************************************************//* SMPTE Switch */#define snd_mts64_ctl_smpte_switch_info		snd_ctl_boolean_mono_infostatic int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl,					  struct snd_ctl_elem_value *uctl){	struct mts64 *mts = snd_kcontrol_chip(kctl);	spin_lock_irq(&mts->lock);	uctl->value.integer.value[0] = mts->smpte_switch;	spin_unlock_irq(&mts->lock);	return 0;}/* smpte_switch is not accessed from IRQ handler, so we just need   to protect the HW access */static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl,					  struct snd_ctl_elem_value *uctl){	struct mts64 *mts = snd_kcontrol_chip(kctl);	int changed = 0;	spin_lock_irq(&mts->lock);	if (mts->smpte_switch == uctl->value.integer.value[0])		goto __out;	changed = 1;	mts->smpte_switch = uctl->value.integer.value[0];	if (mts->smpte_switch) {		mts64_smpte_start(mts->pardev->port,				  mts->time[0], mts->time[1],				  mts->time[2], mts->time[3],				  mts->fps);	} else {		mts64_smpte_stop(mts->pardev->port);	}__out:	spin_unlock_irq(&mts->lock);	return changed;}static struct snd_kcontrol_new mts64_ctl_smpte_switch __devinitdata = {	.iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI,	.name  = "SMPTE Playback Switch",	.index = 0,	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,	.private_value = 0,	.info = snd_mts64_ctl_smpte_switch_info,	.get  = snd_mts64_ctl_smpte_switch_get,	.put  = snd_mts64_ctl_smpte_switch_put};/* Time */static int snd_mts64_ctl_smpte_time_h_info(struct snd_kcontrol *kctl,					   struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 23;	return 0;}static int snd_mts64_ctl_smpte_time_f_info(struct snd_kcontrol *kctl,					   struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 99;	return 0;}static int snd_mts64_ctl_smpte_time_info(struct snd_kcontrol *kctl,					 struct snd_ctl_elem_info *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 59;	return 0;}static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl,					struct snd_ctl_elem_value *uctl){	struct mts64 *mts = snd_kcontrol_chip(kctl);	int idx = kctl->private_value;	spin_lock_irq(&mts->lock);	uctl->value.integer.value[0] = mts->time[idx];	spin_unlock_irq(&mts->lock);	return 0;}static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl,					struct snd_ctl_elem_value *uctl){	struct mts64 *mts = snd_kcontrol_chip(kctl);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -