Commit 3374cd1a authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/core-cleanup' into for-linus

parents e40152ee 670ff6ab
...@@ -5518,34 +5518,41 @@ struct _snd_pcm_runtime { ...@@ -5518,34 +5518,41 @@ struct _snd_pcm_runtime {
]]> ]]>
</programlisting> </programlisting>
</informalexample> </informalexample>
For the raw data, <structfield>size</structfield> field must be
set properly. This specifies the maximum size of the proc file access.
</para> </para>
<para> <para>
The callback is much more complicated than the text-file The read/write callbacks of raw mode are more direct than the text mode.
version. You need to use a low-level I/O functions such as You need to use a low-level I/O functions such as
<function>copy_from/to_user()</function> to transfer the <function>copy_from/to_user()</function> to transfer the
data. data.
<informalexample> <informalexample>
<programlisting> <programlisting>
<![CDATA[ <![CDATA[
static long my_file_io_read(struct snd_info_entry *entry, static ssize_t my_file_io_read(struct snd_info_entry *entry,
void *file_private_data, void *file_private_data,
struct file *file, struct file *file,
char *buf, char *buf,
unsigned long count, size_t count,
unsigned long pos) loff_t pos)
{ {
long size = count; if (copy_to_user(buf, local_data + pos, count))
if (pos + size > local_max_size)
size = local_max_size - pos;
if (copy_to_user(buf, local_data + pos, size))
return -EFAULT; return -EFAULT;
return size; return count;
} }
]]> ]]>
</programlisting> </programlisting>
</informalexample> </informalexample>
If the size of the info entry has been set up properly,
<structfield>count</structfield> and <structfield>pos</structfield> are
guaranteed to fit within 0 and the given size.
You don't have to check the range in the callbacks unless any
other condition is required.
</para> </para>
</chapter> </chapter>
......
...@@ -51,16 +51,16 @@ struct snd_info_entry_ops { ...@@ -51,16 +51,16 @@ struct snd_info_entry_ops {
unsigned short mode, void **file_private_data); unsigned short mode, void **file_private_data);
int (*release)(struct snd_info_entry *entry, int (*release)(struct snd_info_entry *entry,
unsigned short mode, void *file_private_data); unsigned short mode, void *file_private_data);
long (*read)(struct snd_info_entry *entry, void *file_private_data, ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos); size_t count, loff_t pos);
long (*write)(struct snd_info_entry *entry, void *file_private_data, ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data,
struct file *file, const char __user *buf, struct file *file, const char __user *buf,
unsigned long count, unsigned long pos); size_t count, loff_t pos);
long long (*llseek)(struct snd_info_entry *entry, loff_t (*llseek)(struct snd_info_entry *entry,
void *file_private_data, struct file *file, void *file_private_data, struct file *file,
long long offset, int orig); loff_t offset, int orig);
unsigned int(*poll)(struct snd_info_entry *entry, unsigned int (*poll)(struct snd_info_entry *entry,
void *file_private_data, struct file *file, void *file_private_data, struct file *file,
poll_table *wait); poll_table *wait);
int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
......
...@@ -12,7 +12,7 @@ config SND_ATMEL_AC97C ...@@ -12,7 +12,7 @@ config SND_ATMEL_AC97C
tristate "Atmel AC97 Controller (AC97C) driver" tristate "Atmel AC97 Controller (AC97C) driver"
select SND_PCM select SND_PCM
select SND_AC97_CODEC select SND_AC97_CODEC
depends on DW_DMAC && AVR32 depends on (DW_DMAC && AVR32) || ARCH_AT91
help help
ALSA sound driver for the Atmel AC97 controller. ALSA sound driver for the Atmel AC97 controller.
......
This diff is collapsed.
...@@ -50,6 +50,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ...@@ -50,6 +50,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
struct snd_ctl_file *ctl; struct snd_ctl_file *ctl;
int err; int err;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
if (!card) { if (!card) {
err = -ENODEV; err = -ENODEV;
...@@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops = ...@@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops =
.read = snd_ctl_read, .read = snd_ctl_read,
.open = snd_ctl_open, .open = snd_ctl_open,
.release = snd_ctl_release, .release = snd_ctl_release,
.llseek = no_llseek,
.poll = snd_ctl_poll, .poll = snd_ctl_poll,
.unlocked_ioctl = snd_ctl_ioctl, .unlocked_ioctl = snd_ctl_ioctl,
.compat_ioctl = snd_ctl_ioctl_compat, .compat_ioctl = snd_ctl_ioctl_compat,
......
...@@ -164,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) ...@@ -164,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
{ {
struct snd_info_private_data *data; struct snd_info_private_data *data;
struct snd_info_entry *entry; struct snd_info_entry *entry;
loff_t ret; loff_t ret = -EINVAL, size;
data = file->private_data; data = file->private_data;
entry = data->entry; entry = data->entry;
lock_kernel(); mutex_lock(&entry->access);
switch (entry->content) { if (entry->content == SNDRV_INFO_CONTENT_DATA &&
case SNDRV_INFO_CONTENT_TEXT: entry->c.ops->llseek) {
offset = entry->c.ops->llseek(entry,
data->file_private_data,
file, offset, orig);
goto out;
}
if (entry->content == SNDRV_INFO_CONTENT_DATA)
size = entry->size;
else
size = 0;
switch (orig) { switch (orig) {
case SEEK_SET: case SEEK_SET:
file->f_pos = offset; break;
ret = file->f_pos;
goto out;
case SEEK_CUR: case SEEK_CUR:
file->f_pos += offset; offset += file->f_pos;
ret = file->f_pos; break;
goto out;
case SEEK_END: case SEEK_END:
default: if (!size)
ret = -EINVAL;
goto out; goto out;
} offset += size;
break; break;
case SNDRV_INFO_CONTENT_DATA: default:
if (entry->c.ops->llseek) {
ret = entry->c.ops->llseek(entry,
data->file_private_data,
file, offset, orig);
goto out; goto out;
} }
break; if (offset < 0)
} goto out;
ret = -ENXIO; if (size && offset > size)
out: offset = size;
unlock_kernel(); file->f_pos = offset;
ret = offset;
out:
mutex_unlock(&entry->access);
return ret; return ret;
} }
...@@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, ...@@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
return -EFAULT; return -EFAULT;
break; break;
case SNDRV_INFO_CONTENT_DATA: case SNDRV_INFO_CONTENT_DATA:
if (entry->c.ops->read) if (pos >= entry->size)
return 0;
if (entry->c.ops->read) {
size = entry->size - pos;
size = min(count, size);
size = entry->c.ops->read(entry, size = entry->c.ops->read(entry,
data->file_private_data, data->file_private_data,
file, buffer, count, pos); file, buffer, size, pos);
}
break; break;
} }
if ((ssize_t) size > 0) if ((ssize_t) size > 0)
...@@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer ...@@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
size = count; size = count;
break; break;
case SNDRV_INFO_CONTENT_DATA: case SNDRV_INFO_CONTENT_DATA:
if (entry->c.ops->write) if (entry->c.ops->write && count > 0) {
size_t maxsize = entry->size - pos;
count = min(count, maxsize);
size = entry->c.ops->write(entry, size = entry->c.ops->write(entry,
data->file_private_data, data->file_private_data,
file, buffer, count, pos); file, buffer, count, pos);
}
break; break;
} }
if ((ssize_t) size > 0) if ((ssize_t) size > 0)
......
...@@ -43,6 +43,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) ...@@ -43,6 +43,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
struct snd_mixer_oss_file *fmixer; struct snd_mixer_oss_file *fmixer;
int err; int err;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
card = snd_lookup_oss_minor_data(iminor(inode), card = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_MIXER); SNDRV_OSS_DEVICE_TYPE_MIXER);
if (card == NULL) if (card == NULL)
...@@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops = ...@@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops =
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = snd_mixer_oss_open, .open = snd_mixer_oss_open,
.release = snd_mixer_oss_release, .release = snd_mixer_oss_release,
.llseek = no_llseek,
.unlocked_ioctl = snd_mixer_oss_ioctl, .unlocked_ioctl = snd_mixer_oss_ioctl,
.compat_ioctl = snd_mixer_oss_ioctl_compat, .compat_ioctl = snd_mixer_oss_ioctl_compat,
}; };
......
...@@ -2379,6 +2379,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -2379,6 +2379,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
int nonblock; int nonblock;
wait_queue_t wait; wait_queue_t wait;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
pcm = snd_lookup_oss_minor_data(iminor(inode), pcm = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_PCM); SNDRV_OSS_DEVICE_TYPE_PCM);
if (pcm == NULL) { if (pcm == NULL) {
...@@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg = ...@@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg =
.write = snd_pcm_oss_write, .write = snd_pcm_oss_write,
.open = snd_pcm_oss_open, .open = snd_pcm_oss_open,
.release = snd_pcm_oss_release, .release = snd_pcm_oss_release,
.llseek = no_llseek,
.poll = snd_pcm_oss_poll, .poll = snd_pcm_oss_poll,
.unlocked_ioctl = snd_pcm_oss_ioctl, .unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat, .compat_ioctl = snd_pcm_oss_ioctl_compat,
......
...@@ -2110,7 +2110,9 @@ static int snd_pcm_open_file(struct file *file, ...@@ -2110,7 +2110,9 @@ static int snd_pcm_open_file(struct file *file,
static int snd_pcm_playback_open(struct inode *inode, struct file *file) static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{ {
struct snd_pcm *pcm; struct snd_pcm *pcm;
int err = nonseekable_open(inode, file);
if (err < 0)
return err;
pcm = snd_lookup_minor_data(iminor(inode), pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK); SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
...@@ -2119,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) ...@@ -2119,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
static int snd_pcm_capture_open(struct inode *inode, struct file *file) static int snd_pcm_capture_open(struct inode *inode, struct file *file)
{ {
struct snd_pcm *pcm; struct snd_pcm *pcm;
int err = nonseekable_open(inode, file);
if (err < 0)
return err;
pcm = snd_lookup_minor_data(iminor(inode), pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_CAPTURE); SNDRV_DEVICE_TYPE_PCM_CAPTURE);
return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
...@@ -3310,18 +3314,13 @@ static int snd_pcm_fasync(int fd, struct file * file, int on) ...@@ -3310,18 +3314,13 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
struct snd_pcm_file * pcm_file; struct snd_pcm_file * pcm_file;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
int err = -ENXIO;
lock_kernel();
pcm_file = file->private_data; pcm_file = file->private_data;
substream = pcm_file->substream; substream = pcm_file->substream;
if (PCM_RUNTIME_CHECK(substream)) if (PCM_RUNTIME_CHECK(substream))
goto out; return -ENXIO;
runtime = substream->runtime; runtime = substream->runtime;
err = fasync_helper(fd, file, on, &runtime->fasync); return fasync_helper(fd, file, on, &runtime->fasync);
out:
unlock_kernel();
return err;
} }
/* /*
...@@ -3462,6 +3461,7 @@ const struct file_operations snd_pcm_f_ops[2] = { ...@@ -3462,6 +3461,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.aio_write = snd_pcm_aio_write, .aio_write = snd_pcm_aio_write,
.open = snd_pcm_playback_open, .open = snd_pcm_playback_open,
.release = snd_pcm_release, .release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_playback_poll, .poll = snd_pcm_playback_poll,
.unlocked_ioctl = snd_pcm_playback_ioctl, .unlocked_ioctl = snd_pcm_playback_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat, .compat_ioctl = snd_pcm_ioctl_compat,
...@@ -3475,6 +3475,7 @@ const struct file_operations snd_pcm_f_ops[2] = { ...@@ -3475,6 +3475,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.aio_read = snd_pcm_aio_read, .aio_read = snd_pcm_aio_read,
.open = snd_pcm_capture_open, .open = snd_pcm_capture_open,
.release = snd_pcm_release, .release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_capture_poll, .poll = snd_pcm_capture_poll,
.unlocked_ioctl = snd_pcm_capture_ioctl, .unlocked_ioctl = snd_pcm_capture_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat, .compat_ioctl = snd_pcm_ioctl_compat,
......
...@@ -376,6 +376,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) ...@@ -376,6 +376,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */ return -EINVAL; /* invalid combination */
err = nonseekable_open(inode, file);
if (err < 0)
return err;
if (maj == snd_major) { if (maj == snd_major) {
rmidi = snd_lookup_minor_data(iminor(inode), rmidi = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_RAWMIDI); SNDRV_DEVICE_TYPE_RAWMIDI);
...@@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops = ...@@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops =
.write = snd_rawmidi_write, .write = snd_rawmidi_write,
.open = snd_rawmidi_open, .open = snd_rawmidi_open,
.release = snd_rawmidi_release, .release = snd_rawmidi_release,
.llseek = no_llseek,
.poll = snd_rawmidi_poll, .poll = snd_rawmidi_poll,
.unlocked_ioctl = snd_rawmidi_ioctl, .unlocked_ioctl = snd_rawmidi_ioctl,
.compat_ioctl = snd_rawmidi_ioctl_compat, .compat_ioctl = snd_rawmidi_ioctl_compat,
......
...@@ -318,6 +318,11 @@ static int snd_seq_open(struct inode *inode, struct file *file) ...@@ -318,6 +318,11 @@ static int snd_seq_open(struct inode *inode, struct file *file)
int c, mode; /* client id */ int c, mode; /* client id */
struct snd_seq_client *client; struct snd_seq_client *client;
struct snd_seq_user_client *user; struct snd_seq_user_client *user;
int err;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
if (mutex_lock_interruptible(&register_mutex)) if (mutex_lock_interruptible(&register_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops = ...@@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops =
.write = snd_seq_write, .write = snd_seq_write,
.open = snd_seq_open, .open = snd_seq_open,
.release = snd_seq_release, .release = snd_seq_release,
.llseek = no_llseek,
.poll = snd_seq_poll, .poll = snd_seq_poll,
.unlocked_ioctl = snd_seq_ioctl, .unlocked_ioctl = snd_seq_ioctl,
.compat_ioctl = snd_seq_ioctl_compat, .compat_ioctl = snd_seq_ioctl_compat,
......
...@@ -120,19 +120,12 @@ void *snd_lookup_minor_data(unsigned int minor, int type) ...@@ -120,19 +120,12 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
EXPORT_SYMBOL(snd_lookup_minor_data); EXPORT_SYMBOL(snd_lookup_minor_data);
static int __snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
const struct file_operations *old_fops;
int err = 0;
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
mptr = snd_minors[minor];
if (mptr == NULL) {
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
int dev = SNDRV_MINOR_DEVICE(minor); static struct snd_minor *autoload_device(unsigned int minor)
{
int dev;
mutex_unlock(&sound_mutex); /* release lock temporarily */
dev = SNDRV_MINOR_DEVICE(minor);
if (dev == SNDRV_MINOR_CONTROL) { if (dev == SNDRV_MINOR_CONTROL) {
/* /dev/aloadC? */ /* /dev/aloadC? */
int card = SNDRV_MINOR_CARD(minor); int card = SNDRV_MINOR_CARD(minor);
...@@ -142,42 +135,52 @@ static int __snd_open(struct inode *inode, struct file *file) ...@@ -142,42 +135,52 @@ static int __snd_open(struct inode *inode, struct file *file)
/* /dev/aloadSEQ */ /* /dev/aloadSEQ */
snd_request_other(minor); snd_request_other(minor);
} }
#ifndef CONFIG_SND_DYNAMIC_MINORS mutex_lock(&sound_mutex); /* reacuire lock */
/* /dev/snd/{controlC?,seq} */ return snd_minors[minor];
}
#else /* !CONFIG_MODULES */
#define autoload_device(minor) NULL
#endif /* CONFIG_MODULES */
static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
const struct file_operations *old_fops;
int err = 0;
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
mutex_lock(&sound_mutex);
mptr = snd_minors[minor]; mptr = snd_minors[minor];
if (mptr == NULL) if (mptr == NULL) {
#endif mptr = autoload_device(minor);
#endif if (!mptr) {
mutex_unlock(&sound_mutex);
return -ENODEV; return -ENODEV;
} }
}
old_fops = file->f_op; old_fops = file->f_op;
file->f_op = fops_get(mptr->f_ops); file->f_op = fops_get(mptr->f_ops);
if (file->f_op == NULL) { if (file->f_op == NULL) {
file->f_op = old_fops; file->f_op = old_fops;
return -ENODEV; err = -ENODEV;
} }
if (file->f_op->open) mutex_unlock(&sound_mutex);
if (err < 0)
return err;
if (file->f_op->open) {
err = file->f_op->open(inode, file); err = file->f_op->open(inode, file);
if (err) { if (err) {
fops_put(file->f_op); fops_put(file->f_op);
file->f_op = fops_get(old_fops); file->f_op = fops_get(old_fops);
} }
}
fops_put(old_fops); fops_put(old_fops);
return err; return err;
} }
/* BKL pushdown: nasty #ifdef avoidance wrapper */
static int snd_open(struct inode *inode, struct file *file)
{
int ret;
lock_kernel();
ret = __snd_open(inode, file);
unlock_kernel();
return ret;
}
static const struct file_operations snd_fops = static const struct file_operations snd_fops =
{ {
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -1238,6 +1238,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, ...@@ -1238,6 +1238,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
static int snd_timer_user_open(struct inode *inode, struct file *file) static int snd_timer_user_open(struct inode *inode, struct file *file)
{ {
struct snd_timer_user *tu; struct snd_timer_user *tu;
int err;
err = nonseekable_open(inode, file);
if (err < 0)
return err;
tu = kzalloc(sizeof(*tu), GFP_KERNEL); tu = kzalloc(sizeof(*tu), GFP_KERNEL);
if (tu == NULL) if (tu == NULL)
...@@ -1922,6 +1927,7 @@ static const struct file_operations snd_timer_f_ops = ...@@ -1922,6 +1927,7 @@ static const struct file_operations snd_timer_f_ops =
.read = snd_timer_user_read, .read = snd_timer_user_read,
.open = snd_timer_user_open, .open = snd_timer_user_open,
.release = snd_timer_user_release, .release = snd_timer_user_release,
.llseek = no_llseek,
.poll = snd_timer_user_poll, .poll = snd_timer_user_poll,
.unlocked_ioctl = snd_timer_user_ioctl, .unlocked_ioctl = snd_timer_user_ioctl,
.compat_ioctl = snd_timer_user_ioctl_compat, .compat_ioctl = snd_timer_user_ioctl_compat,
......
...@@ -49,77 +49,45 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry, ...@@ -49,77 +49,45 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry,
return 0; return 0;
} }
static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *_buf, struct file *file, char __user *_buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
struct snd_opl4 *opl4 = entry->private_data; struct snd_opl4 *opl4 = entry->private_data;
long size;
char* buf; char* buf;
size = count; buf = vmalloc(count);
if (pos + size > entry->size)
size = entry->size - pos;
if (size > 0) {
buf = vmalloc(size);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
snd_opl4_read_memory(opl4, buf, pos, size); snd_opl4_read_memory(opl4, buf, pos, count);
if (copy_to_user(_buf, buf, size)) { if (copy_to_user(_buf, buf, count)) {
vfree(buf); vfree(buf);
return -EFAULT; return -EFAULT;
} }
vfree(buf); vfree(buf);
return size; return count;
}
return 0;
} }
static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
struct file *file, const char __user *_buf, void *file_private_data,
unsigned long count, unsigned long pos) struct file *file,
const char __user *_buf,
size_t count, loff_t pos)
{ {
struct snd_opl4 *opl4 = entry->private_data; struct snd_opl4 *opl4 = entry->private_data;
long size;
char *buf; char *buf;
size = count; buf = vmalloc(count);
if (pos + size > entry->size)
size = entry->size - pos;
if (size > 0) {
buf = vmalloc(size);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(buf, _buf, size)) { if (copy_from_user(buf, _buf, count)) {
vfree(buf); vfree(buf);
return -EFAULT; return -EFAULT;
} }
snd_opl4_write_memory(opl4, buf, pos, size); snd_opl4_write_memory(opl4, buf, pos, count);
vfree(buf); vfree(buf);
return size; return count;
}
return 0;
}
static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data,
struct file *file, long long offset, int orig)
{
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END: /* offset is negative */
file->f_pos = entry->size + offset;
break;
default:
return -EINVAL;
}
if (file->f_pos > entry->size)
file->f_pos = entry->size;
return file->f_pos;
} }
static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
...@@ -127,7 +95,6 @@ static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { ...@@ -127,7 +95,6 @@ static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
.release = snd_opl4_mem_proc_release, .release = snd_opl4_mem_proc_release,
.read = snd_opl4_mem_proc_read, .read = snd_opl4_mem_proc_read,
.write = snd_opl4_mem_proc_write, .write = snd_opl4_mem_proc_write,
.llseek = snd_opl4_mem_proc_llseek,
}; };
int snd_opl4_create_proc(struct snd_opl4 *opl4) int snd_opl4_create_proc(struct snd_opl4 *opl4)
......
...@@ -31,50 +31,19 @@ struct gus_proc_private { ...@@ -31,50 +31,19 @@ struct gus_proc_private {
struct snd_gus_card * gus; struct snd_gus_card * gus;
}; };
static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
long size;
struct gus_proc_private *priv = entry->private_data; struct gus_proc_private *priv = entry->private_data;
struct snd_gus_card *gus = priv->gus; struct snd_gus_card *gus = priv->gus;
int err; int err;
size = count; err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
if (pos + size > priv->size) if (err < 0)
size = (long)priv->size - pos;
if (size > 0) {
if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
return err; return err;
return size; return count;
}
return 0;
}
static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
void *private_file_data,
struct file *file,
long long offset,
int orig)
{
struct gus_proc_private *priv = entry->private_data;
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END: /* offset is negative */
file->f_pos = priv->size + offset;
break;
default:
return -EINVAL;
}
if (file->f_pos > priv->size)
file->f_pos = priv->size;
return file->f_pos;
} }
static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
...@@ -85,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) ...@@ -85,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
.read = snd_gf1_mem_proc_dump, .read = snd_gf1_mem_proc_dump,
.llseek = snd_gf1_mem_proc_llseek,
}; };
int snd_gf1_mem_proc_init(struct snd_gus_card * gus) int snd_gf1_mem_proc_init(struct snd_gus_card * gus)
......
...@@ -1139,40 +1139,28 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry, ...@@ -1139,40 +1139,28 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq);
} }
static long snd_cs4281_BA0_read(struct snd_info_entry *entry, static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
void *file_private_data, void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
long size;
struct cs4281 *chip = entry->private_data; struct cs4281 *chip = entry->private_data;
size = count; if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
if (pos + size > CS4281_BA0_SIZE)
size = (long)CS4281_BA0_SIZE - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
return -EFAULT; return -EFAULT;
} return count;
return size;
} }
static long snd_cs4281_BA1_read(struct snd_info_entry *entry, static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
void *file_private_data, void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
long size;
struct cs4281 *chip = entry->private_data; struct cs4281 *chip = entry->private_data;
size = count; if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
if (pos + size > CS4281_BA1_SIZE)
size = (long)CS4281_BA1_SIZE - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
return -EFAULT; return -EFAULT;
} return count;
return size;
} }
static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
......
...@@ -2657,21 +2657,16 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { } ...@@ -2657,21 +2657,16 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { }
* proc interface * proc interface
*/ */
static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
long size;
struct snd_cs46xx_region *region = entry->private_data; struct snd_cs46xx_region *region = entry->private_data;
size = count; if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
if (pos + (size_t)size > region->size)
size = region->size - pos;
if (size > 0) {
if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
return -EFAULT; return -EFAULT;
} return count;
return size;
} }
static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
......
...@@ -341,15 +341,17 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry, ...@@ -341,15 +341,17 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry,
#define TOTAL_SIZE_CODE (0x200*8) #define TOTAL_SIZE_CODE (0x200*8)
#define A_TOTAL_SIZE_CODE (0x400*8) #define A_TOTAL_SIZE_CODE (0x400*8)
static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
void *file_private_data, void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
long size;
struct snd_emu10k1 *emu = entry->private_data; struct snd_emu10k1 *emu = entry->private_data;
unsigned int offset; unsigned int offset;
int tram_addr = 0; int tram_addr = 0;
unsigned int *tmp;
long res;
unsigned int idx;
if (!strcmp(entry->name, "fx8010_tram_addr")) { if (!strcmp(entry->name, "fx8010_tram_addr")) {
offset = TANKMEMADDRREGBASE; offset = TANKMEMADDRREGBASE;
...@@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, ...@@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
} else { } else {
offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
} }
size = count;
if (pos + size > entry->size) tmp = kmalloc(count + 8, GFP_KERNEL);
size = (long)entry->size - pos; if (!tmp)
if (size > 0) {
unsigned int *tmp;
long res;
unsigned int idx;
if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
unsigned int val;
val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
if (tram_addr && emu->audigy) { if (tram_addr && emu->audigy) {
tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11; val >>= 11;
tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
} else }
tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); tmp[idx] = val;
if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
res = -EFAULT;
else {
res = size;
} }
if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count))
res = -EFAULT;
else
res = count;
kfree(tmp); kfree(tmp);
return res; return res;
}
return 0;
} }
static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry,
......
...@@ -1956,11 +1956,10 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) ...@@ -1956,11 +1956,10 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
return 0; return 0;
} }
/* /*
* initialize the chip * reset the chip
*/ */
static int __devinit aureon_init(struct snd_ice1712 *ice) static int aureon_reset(struct snd_ice1712 *ice)
{ {
static const unsigned short wm_inits_aureon[] = { static const unsigned short wm_inits_aureon[] = {
/* These come first to reduce init pop noise */ /* These come first to reduce init pop noise */
...@@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) ...@@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
(unsigned short)-1 (unsigned short)-1
}; };
struct aureon_spec *spec;
unsigned int tmp; unsigned int tmp;
const unsigned short *p; const unsigned short *p;
int err, i; int err;
struct aureon_spec *spec = ice->spec;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
ice->spec = spec;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
} else {
/* aureon 7.1 and prodigy 7.1 */
ice->num_total_dacs = 8;
ice->num_total_adcs = 2;
}
/* to remeber the register values of CS8415 */
ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
if (!ice->akm)
return -ENOMEM;
ice->akm_codecs = 1;
err = aureon_ac97_init(ice); err = aureon_ac97_init(ice);
if (err != 0) if (err != 0)
...@@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) ...@@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
/* initialize PCA9554 pin directions & set default input */ /* initialize PCA9554 pin directions & set default input */
aureon_pca9554_write(ice, PCA9554_DIR, 0x00); aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
return 0;
}
/*
* suspend/resume
*/
#ifdef CONFIG_PM
static int aureon_resume(struct snd_ice1712 *ice)
{
struct aureon_spec *spec = ice->spec;
int err, i;
err = aureon_reset(ice);
if (err != 0)
return err;
/* workaround for poking volume with alsamixer after resume:
* just set stored volume again */
for (i = 0; i < ice->num_total_dacs; i++)
wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
return 0;
}
#endif
/*
* initialize the chip
*/
static int __devinit aureon_init(struct snd_ice1712 *ice)
{
struct aureon_spec *spec;
int i, err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
ice->spec = spec;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
} else {
/* aureon 7.1 and prodigy 7.1 */
ice->num_total_dacs = 8;
ice->num_total_adcs = 2;
}
/* to remeber the register values of CS8415 */
ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
if (!ice->akm)
return -ENOMEM;
ice->akm_codecs = 1;
err = aureon_reset(ice);
if (err != 0)
return err;
spec->master[0] = WM_VOL_MUTE; spec->master[0] = WM_VOL_MUTE;
spec->master[1] = WM_VOL_MUTE; spec->master[1] = WM_VOL_MUTE;
...@@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) ...@@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
} }
#ifdef CONFIG_PM
ice->pm_resume = aureon_resume;
ice->pm_suspend_enabled = 1;
#endif
return 0; return 0;
} }
......
...@@ -1102,73 +1102,17 @@ static int snd_mixart_free(struct mixart_mgr *mgr) ...@@ -1102,73 +1102,17 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
/* /*
* proc interface * proc interface
*/ */
static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry,
void *private_file_data,
struct file *file,
long long offset,
int orig)
{
offset = offset & ~3; /* 4 bytes aligned */
switch(orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END: /* offset is negative */
file->f_pos = MIXART_BA0_SIZE + offset;
break;
default:
return -EINVAL;
}
if(file->f_pos > MIXART_BA0_SIZE)
file->f_pos = MIXART_BA0_SIZE;
return file->f_pos;
}
static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry,
void *private_file_data,
struct file *file,
long long offset,
int orig)
{
offset = offset & ~3; /* 4 bytes aligned */
switch(orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END: /* offset is negative */
file->f_pos = MIXART_BA1_SIZE + offset;
break;
default:
return -EINVAL;
}
if(file->f_pos > MIXART_BA1_SIZE)
file->f_pos = MIXART_BA1_SIZE;
return file->f_pos;
}
/* /*
mixart_BA0 proc interface for BAR 0 - read callback mixart_BA0 proc interface for BAR 0 - read callback
*/ */
static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
struct mixart_mgr *mgr = entry->private_data; struct mixart_mgr *mgr = entry->private_data;
unsigned long maxsize;
if (pos >= MIXART_BA0_SIZE)
return 0;
maxsize = MIXART_BA0_SIZE - pos;
if (count > maxsize)
count = maxsize;
count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
return -EFAULT; return -EFAULT;
...@@ -1178,18 +1122,13 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private ...@@ -1178,18 +1122,13 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private
/* /*
mixart_BA1 proc interface for BAR 1 - read callback mixart_BA1 proc interface for BAR 1 - read callback
*/ */
static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private_data, static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
void *file_private_data,
struct file *file, char __user *buf, struct file *file, char __user *buf,
unsigned long count, unsigned long pos) size_t count, loff_t pos)
{ {
struct mixart_mgr *mgr = entry->private_data; struct mixart_mgr *mgr = entry->private_data;
unsigned long maxsize;
if (pos > MIXART_BA1_SIZE)
return 0;
maxsize = MIXART_BA1_SIZE - pos;
if (count > maxsize)
count = maxsize;
count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
return -EFAULT; return -EFAULT;
...@@ -1198,12 +1137,10 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private ...@@ -1198,12 +1137,10 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private
static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
.read = snd_mixart_BA0_read, .read = snd_mixart_BA0_read,
.llseek = snd_mixart_BA0_llseek
}; };
static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = {
.read = snd_mixart_BA1_read, .read = snd_mixart_BA1_read,
.llseek = snd_mixart_BA1_llseek
}; };
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/string.h>
#include <sound/core.h> #include <sound/core.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -46,6 +47,8 @@ ...@@ -46,6 +47,8 @@
#define DBG(fmt...) #define DBG(fmt...)
#endif #endif
#define IS_G4DA (of_machine_is_compatible("PowerMac3,4"))
/* i2c address for tumbler */ /* i2c address for tumbler */
#define TAS_I2C_ADDR 0x34 #define TAS_I2C_ADDR 0x34
...@@ -243,6 +246,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix) ...@@ -243,6 +246,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set volume \n"); snd_printk(KERN_ERR "failed to set volume \n");
return -EINVAL; return -EINVAL;
} }
DBG("(I) succeeded to set volume (%u, %u)\n", left_vol, right_vol);
return 0; return 0;
} }
...@@ -353,6 +357,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix) ...@@ -353,6 +357,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set DRC\n"); snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL; return -EINVAL;
} }
DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0; return 0;
} }
...@@ -389,6 +394,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix) ...@@ -389,6 +394,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set DRC\n"); snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL; return -EINVAL;
} }
DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0; return 0;
} }
...@@ -1134,7 +1140,8 @@ static long tumbler_find_device(const char *device, const char *platform, ...@@ -1134,7 +1140,8 @@ static long tumbler_find_device(const char *device, const char *platform,
gp->inactive_val = (*base) ? 0x4 : 0x5; gp->inactive_val = (*base) ? 0x4 : 0x5;
} else { } else {
const u32 *prop = NULL; const u32 *prop = NULL;
gp->active_state = 0; gp->active_state = IS_G4DA
&& !strncmp(device, "keywest-gpio1", 13);
gp->active_val = 0x4; gp->active_val = 0x4;
gp->inactive_val = 0x5; gp->inactive_val = 0x5;
/* Here are some crude hacks to extract the GPIO polarity and /* Here are some crude hacks to extract the GPIO polarity and
...@@ -1312,6 +1319,9 @@ static int __devinit tumbler_init(struct snd_pmac *chip) ...@@ -1312,6 +1319,9 @@ static int __devinit tumbler_init(struct snd_pmac *chip)
if (irq <= NO_IRQ) if (irq <= NO_IRQ)
irq = tumbler_find_device("line-output-detect", irq = tumbler_find_device("line-output-detect",
NULL, &mix->line_detect, 1); NULL, &mix->line_detect, 1);
if (IS_G4DA && irq <= NO_IRQ)
irq = tumbler_find_device("keywest-gpio16",
NULL, &mix->line_detect, 1);
mix->lineout_irq = irq; mix->lineout_irq = irq;
tumbler_reset_audio(chip); tumbler_reset_audio(chip);
......
...@@ -65,6 +65,7 @@ config SND_USB_CAIAQ ...@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
* Native Instruments Audio 8 DJ * Native Instruments Audio 8 DJ
* Native Instruments Guitar Rig Session I/O * Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile * Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq. will be called snd-usb-caiaq.
......
...@@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol, ...@@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value; int pos = kcontrol->private_value;
int is_intval = pos & CNT_INTVAL; int is_intval = pos & CNT_INTVAL;
unsigned int id = dev->chip.usb_id; int maxval = 63;
uinfo->count = 1; uinfo->count = 1;
pos &= ~CNT_INTVAL; pos &= ~CNT_INTVAL;
if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) switch (dev->chip.usb_id) {
&& (pos == 0)) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
if (pos == 0) {
/* current input mode of A8DJ */ /* current input mode of A8DJ */
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 2; uinfo->value.integer.max = 2;
return 0; return 0;
} }
break;
if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ) case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
&& (pos == 0)) { if (pos == 0) {
/* current input mode of A4DJ */ /* current input mode of A4DJ */
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1; uinfo->value.integer.max = 1;
return 0; return 0;
} }
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
maxval = 127;
break;
}
if (is_intval) { if (is_intval) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 64; uinfo->value.integer.max = maxval;
} else { } else {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
...@@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value; int pos = kcontrol->private_value;
unsigned char cmd = EP1_CMD_WRITE_IO;
if (dev->chip.usb_id == switch (dev->chip.usb_id) {
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
/* A4DJ has only one control */ /* A4DJ has only one control */
/* do not expose hardware input mode 0 */ /* do not expose hardware input mode 0 */
dev->control_state[0] = ucontrol->value.integer.value[0] + 1; dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
...@@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol,
return 1; return 1;
} }
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
cmd = EP1_CMD_DIMM_LEDS;
break;
}
if (pos & CNT_INTVAL) { if (pos & CNT_INTVAL) {
dev->control_state[pos & ~CNT_INTVAL] dev->control_state[pos & ~CNT_INTVAL]
= ucontrol->value.integer.value[0]; = ucontrol->value.integer.value[0];
snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state)); dev->control_state, sizeof(dev->control_state));
} else { } else {
if (ucontrol->value.integer.value[0]) if (ucontrol->value.integer.value[0])
...@@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
else else
dev->control_state[pos / 8] &= ~(1 << (pos % 8)); dev->control_state[pos / 8] &= ~(1 << (pos % 8));
snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state)); dev->control_state, sizeof(dev->control_state));
} }
...@@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = { ...@@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = {
{ "Current input mode", 0 | CNT_INTVAL } { "Current input mode", 0 | CNT_INTVAL }
}; };
static struct caiaq_controller kontrolx1_controller[] = {
{ "LED FX A: ON", 7 | CNT_INTVAL },
{ "LED FX A: 1", 6 | CNT_INTVAL },
{ "LED FX A: 2", 5 | CNT_INTVAL },
{ "LED FX A: 3", 4 | CNT_INTVAL },
{ "LED FX B: ON", 3 | CNT_INTVAL },
{ "LED FX B: 1", 2 | CNT_INTVAL },
{ "LED FX B: 2", 1 | CNT_INTVAL },
{ "LED FX B: 3", 0 | CNT_INTVAL },
{ "LED Hotcue", 28 | CNT_INTVAL },
{ "LED Shift (white)", 29 | CNT_INTVAL },
{ "LED Shift (green)", 30 | CNT_INTVAL },
{ "LED Deck A: FX1", 24 | CNT_INTVAL },
{ "LED Deck A: FX2", 25 | CNT_INTVAL },
{ "LED Deck A: IN", 17 | CNT_INTVAL },
{ "LED Deck A: OUT", 16 | CNT_INTVAL },
{ "LED Deck A: < BEAT", 19 | CNT_INTVAL },
{ "LED Deck A: BEAT >", 18 | CNT_INTVAL },
{ "LED Deck A: CUE/ABS", 21 | CNT_INTVAL },
{ "LED Deck A: CUP/REL", 20 | CNT_INTVAL },
{ "LED Deck A: PLAY", 23 | CNT_INTVAL },
{ "LED Deck A: SYNC", 22 | CNT_INTVAL },
{ "LED Deck B: FX1", 26 | CNT_INTVAL },
{ "LED Deck B: FX2", 27 | CNT_INTVAL },
{ "LED Deck B: IN", 15 | CNT_INTVAL },
{ "LED Deck B: OUT", 14 | CNT_INTVAL },
{ "LED Deck B: < BEAT", 13 | CNT_INTVAL },
{ "LED Deck B: BEAT >", 12 | CNT_INTVAL },
{ "LED Deck B: CUE/ABS", 11 | CNT_INTVAL },
{ "LED Deck B: CUP/REL", 10 | CNT_INTVAL },
{ "LED Deck B: PLAY", 9 | CNT_INTVAL },
{ "LED Deck B: SYNC", 8 | CNT_INTVAL },
};
static int __devinit add_controls(struct caiaq_controller *c, int num, static int __devinit add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *dev) struct snd_usb_caiaqdev *dev)
{ {
...@@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) ...@@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
ret = add_controls(a8dj_controller, ret = add_controls(a8dj_controller,
ARRAY_SIZE(a8dj_controller), dev); ARRAY_SIZE(a8dj_controller), dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
ret = add_controls(a4dj_controller, ret = add_controls(a4dj_controller,
ARRAY_SIZE(a4dj_controller), dev); ARRAY_SIZE(a4dj_controller), dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
ret = add_controls(kontrolx1_controller,
ARRAY_SIZE(kontrolx1_controller), dev);
break;
} }
return ret; return ret;
......
...@@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," ...@@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 4 DJ}," "{Native Instruments, Audio 4 DJ},"
"{Native Instruments, Audio 8 DJ}," "{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O}," "{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}"); "{Native Instruments, GuitarRig mobile}"
"{Native Instruments, Traktor Kontrol X1}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
...@@ -128,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = { ...@@ -128,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS, .idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_AUDIO2DJ .idProduct = USB_PID_AUDIO2DJ
}, },
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORKONTROLX1
},
{ /* terminator */ } { /* terminator */ }
}; };
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
#define USB_PID_AUDIO8DJ 0x1978 #define USB_PID_AUDIO8DJ 0x1978
#define USB_PID_SESSIONIO 0x1915 #define USB_PID_SESSIONIO 0x1915
#define USB_PID_GUITARRIGMOBILE 0x0d8d #define USB_PID_GUITARRIGMOBILE 0x0d8d
#define USB_PID_TRAKTORKONTROLX1 0x2305
#define EP1_BUFSIZE 64 #define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
#define CAIAQ_USB_STR_LEN 0xff #define CAIAQ_USB_STR_LEN 0xff
#define MAX_STREAMS 32 #define MAX_STREAMS 32
...@@ -104,6 +106,8 @@ struct snd_usb_caiaqdev { ...@@ -104,6 +106,8 @@ struct snd_usb_caiaqdev {
struct input_dev *input_dev; struct input_dev *input_dev;
char phys[64]; /* physical device path */ char phys[64]; /* physical device path */
unsigned short keycode[64]; unsigned short keycode[64];
struct urb *ep4_in_urb;
unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif #endif
/* ALSA */ /* ALSA */
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include "device.h" #include "device.h"
...@@ -65,6 +66,8 @@ static unsigned short keycode_kore[] = { ...@@ -65,6 +66,8 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5 KEY_BRL_DOT5
}; };
#define KONTROLX1_INPUTS 40
#define DEG90 (range / 2) #define DEG90 (range / 2)
#define DEG180 (range) #define DEG180 (range)
#define DEG270 (DEG90 + DEG180) #define DEG270 (DEG90 + DEG180)
...@@ -162,6 +165,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, ...@@ -162,6 +165,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
input_sync(input_dev); input_sync(input_dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]);
input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
input_sync(input_dev);
break;
} }
} }
...@@ -201,7 +215,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, ...@@ -201,7 +215,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
} }
static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
char *buf, unsigned int len) unsigned char *buf, unsigned int len)
{ {
struct input_dev *input_dev = dev->input_dev; struct input_dev *input_dev = dev->input_dev;
unsigned short *keycode = input_dev->keycode; unsigned short *keycode = input_dev->keycode;
...@@ -218,15 +232,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, ...@@ -218,15 +232,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
input_report_key(input_dev, keycode[i], input_report_key(input_dev, keycode[i],
buf[i / 8] & (1 << (i % 8))); buf[i / 8] & (1 << (i % 8)));
if (dev->chip.usb_id == switch (dev->chip.usb_id) {
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
dev->chip.usb_id == case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2))
input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
/* rotary encoders */
input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf);
input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4);
input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf);
input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4);
break;
}
input_sync(input_dev); input_sync(input_dev);
} }
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *dev = urb->context;
unsigned char *buf = urb->transfer_buffer;
int ret;
if (urb->status || !dev || urb != dev->ep4_in_urb)
return;
if (urb->actual_length < 24)
goto requeue;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (buf[0] & 0x3)
snd_caiaq_input_read_io(dev, buf + 1, 7);
if (buf[0] & 0x4)
snd_caiaq_input_read_analog(dev, buf + 8, 16);
break;
}
requeue:
dev->ep4_in_urb->actual_length = 0;
ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC);
if (ret < 0)
log("unable to submit urb. OOM!?\n");
}
static int snd_usb_caiaq_input_open(struct input_dev *idev)
{
struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
if (!dev)
return -EINVAL;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO;
break;
}
return 0;
}
static void snd_usb_caiaq_input_close(struct input_dev *idev)
{
struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
if (!dev)
return;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
usb_kill_urb(dev->ep4_in_urb);
break;
}
}
void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
char *buf, char *buf,
unsigned int len) unsigned int len)
...@@ -251,7 +334,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -251,7 +334,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
{ {
struct usb_device *usb_dev = dev->chip.dev; struct usb_device *usb_dev = dev->chip.dev;
struct input_dev *input; struct input_dev *input;
int i, ret; int i, ret = 0;
input = input_allocate_device(); input = input_allocate_device();
if (!input) if (!input)
...@@ -265,6 +348,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -265,6 +348,8 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
usb_to_input_id(usb_dev, &input->id); usb_to_input_id(usb_dev, &input->id);
input->dev.parent = &usb_dev->dev; input->dev.parent = &usb_dev->dev;
input_set_drvdata(input, dev);
switch (dev->chip.usb_id) { switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
...@@ -325,26 +410,73 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -325,26 +410,73 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS);
for (i = 0; i < KONTROLX1_INPUTS; i++)
dev->keycode[i] = BTN_MISC + i;
input->keycodemax = KONTROLX1_INPUTS;
/* analog potentiometers */
input_set_abs_params(input, ABS_HAT0X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT0Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT1X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT1Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT2X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT2Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT3X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT3Y, 0, 4096, 0, 10);
/* rotary encoders */
input_set_abs_params(input, ABS_X, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_Y, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1);
dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0x4),
dev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, dev);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break; break;
default: default:
/* no input methods supported on this device */ /* no input methods supported on this device */
input_free_device(input); goto exit_free_idev;
return 0;
} }
input->open = snd_usb_caiaq_input_open;
input->close = snd_usb_caiaq_input_close;
input->keycode = dev->keycode; input->keycode = dev->keycode;
input->keycodesize = sizeof(unsigned short); input->keycodesize = sizeof(unsigned short);
for (i = 0; i < input->keycodemax; i++) for (i = 0; i < input->keycodemax; i++)
__set_bit(dev->keycode[i], input->keybit); __set_bit(dev->keycode[i], input->keybit);
ret = input_register_device(input); ret = input_register_device(input);
if (ret < 0) { if (ret < 0)
input_free_device(input); goto exit_free_idev;
return ret;
}
dev->input_dev = input; dev->input_dev = input;
return 0; return 0;
exit_free_idev:
input_free_device(input);
return ret;
} }
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
...@@ -352,6 +484,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) ...@@ -352,6 +484,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
if (!dev || !dev->input_dev) if (!dev || !dev->input_dev)
return; return;
usb_kill_urb(dev->ep4_in_urb);
usb_free_urb(dev->ep4_in_urb);
dev->ep4_in_urb = NULL;
input_unregister_device(dev->input_dev); input_unregister_device(dev->input_dev);
dev->input_dev = NULL; dev->input_dev = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment