#include <linux/gameport.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
-#include <asm/hardirq.h>
#include <asm/io.h>
#include <asm/dma.h>
#define DRIVER_VERSION "0.14.10j-2.6"
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
/* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
};
static struct pci_device_id trident_pci_tbl[] = {
- {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX},
- {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018},
- {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI_5451},
- {PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5050,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CYBER5050},
+ {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX),
+ PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TRIDENT_4D_DX},
+ {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX),
+ 0, 0, TRIDENT_4D_NX},
+ {PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018), 0, 0, SIS_7018},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451), 0, 0, ALI_5451},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5050),
+ 0, 0, CYBER5050},
{0,}
};
struct timer_list timer;
/* Game port support */
- struct gameport gameport;
+ struct gameport *gameport;
};
enum dmabuf_mode {
static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
static void ali_restore_regs(struct trident_card *card);
static void ali_save_regs(struct trident_card *card);
-static int trident_suspend(struct pci_dev *dev, u32 unused);
+static int trident_suspend(struct pci_dev *dev, pm_message_t unused);
static int trident_resume(struct pci_dev *dev);
static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
static void ali_disable_spdif_in(struct trident_card *card);
static void ali_disable_special_channel(struct trident_card *card, int ch);
static void ali_setup_spdif_out(struct trident_card *card, int flag);
-static int ali_write_5_1(struct trident_state *state, const char *buffer,
+static int ali_write_5_1(struct trident_state *state,
+ const char __user *buffer,
int cnt_for_multi_channel, unsigned int *copy_count,
unsigned int *state_cnt);
static int ali_allocate_other_states_resources(struct trident_state *state,
dmabuf->buforder = order;
/* now mark the pages as reserved; otherwise */
- /* remap_page_range doesn't do what we want */
+ /* remap_pfn_range doesn't do what we want */
pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(rawbuf); page <= pend; page++)
SetPageReserved(page);
/* to be copied to the user's buffer. it is filled by the dma machine and */
/* drained by this loop. */
static ssize_t
-trident_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
+trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
{
struct trident_state *state = (struct trident_state *)file->private_data;
struct dmabuf *dmabuf = &state->dmabuf;
pr_debug("trident: trident_read called, count = %d\n", count);
VALIDATE_STATE(state);
- if (ppos != &file->f_pos)
- return -ESPIPE;
if (dmabuf->mapped)
return -ENXIO;
the soundcard. it is drained by the dma machine and filled by this loop. */
static ssize_t
-trident_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+trident_write(struct file *file, const char __user *buffer, size_t count, loff_t * ppos)
{
struct trident_state *state = (struct trident_state *)file->private_data;
struct dmabuf *dmabuf = &state->dmabuf;
pr_debug("trident: trident_write called, count = %d\n", count);
VALIDATE_STATE(state);
- if (ppos != &file->f_pos)
- return -ESPIPE;
/*
* Guard against an mmap or ioctl while writing
if (size > (PAGE_SIZE << dmabuf->buforder))
goto out;
ret = -EAGAIN;
- if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
size, vma->vm_page_prot))
goto out;
dmabuf->mapped = 1;
audio_buf_info abinfo;
count_info cinfo;
int val, mapped, ret = 0;
-
struct trident_card *card = state->card;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
VALIDATE_STATE(state);
mapped = ((file->f_mode & (FMODE_WRITE | FMODE_READ)) && dmabuf->mapped);
pr_debug("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
- _IOC_NR(cmd), arg ? *(int *) arg : 0);
+ _IOC_NR(cmd), arg ? *p : 0);
switch (cmd) {
case OSS_GETVERSION:
- ret = put_user(SOUND_VERSION, (int *) arg);
+ ret = put_user(SOUND_VERSION, p);
break;
case SNDCTL_DSP_RESET:
break;
case SNDCTL_DSP_SPEED: /* set smaple rate */
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
spin_unlock_irqrestore(&state->card->lock, flags);
}
}
- ret = put_user(dmabuf->rate, (int *) arg);
+ ret = put_user(dmabuf->rate, p);
break;
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
if ((val = prog_dmabuf_playback(state)))
ret = val;
else
- ret = put_user(dmabuf->fragsize, (int *) arg);
+ ret = put_user(dmabuf->fragsize, p);
break;
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf_record(state)))
ret = val;
else
- ret = put_user(dmabuf->fragsize, (int *) arg);
+ ret = put_user(dmabuf->fragsize, p);
break;
}
/* neither READ nor WRITE? is this even possible? */
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */
ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8, (int *) arg);
+ AFMT_U8, p);
break;
case SNDCTL_DSP_SETFMT: /* Select sample format */
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
}
unlock_set_fmt(state);
ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
- AFMT_U8, (int *) arg);
+ AFMT_U8, p);
break;
case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
}
unlock_set_fmt(state);
}
- ret = put_user(val, (int *) arg);
+ ret = put_user(val, p);
break;
case SNDCTL_DSP_POST:
ret = -EINVAL;
break;
}
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
break;
case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user((void *) arg, &abinfo, sizeof (abinfo)) ?
+ ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
-EFAULT : 0;
break;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user((void *) arg, &abinfo, sizeof (abinfo)) ?
+ ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
-EFAULT : 0;
break;
case SNDCTL_DSP_GETCAPS:
ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
- DSP_CAP_MMAP | DSP_CAP_BIND, (int *) arg);
+ DSP_CAP_MMAP | DSP_CAP_BIND, p);
break;
case SNDCTL_DSP_GETTRIGGER:
val |= PCM_ENABLE_INPUT;
if ((file->f_mode & FMODE_WRITE) && dmabuf->enable)
val |= PCM_ENABLE_OUTPUT;
- ret = put_user(val, (int *) arg);
+ ret = put_user(val, p);
break;
case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize - 1;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user((void *) arg, &cinfo, sizeof (cinfo)) ?
+ ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
-EFAULT : 0;
break;
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize - 1;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user((void *) arg, &cinfo, sizeof (cinfo)) ?
+ ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
-EFAULT : 0;
break;
trident_update_ptr(state);
val = dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = put_user(val, (int *) arg);
+ ret = put_user(val, p);
break;
case SOUND_PCM_READ_RATE:
- ret = put_user(dmabuf->rate, (int *) arg);
+ ret = put_user(dmabuf->rate, p);
break;
case SOUND_PCM_READ_CHANNELS:
ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
- (int *) arg);
+ p);
break;
case SOUND_PCM_READ_BITS:
ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
- AFMT_U8, (int *) arg);
+ AFMT_U8, p);
break;
case SNDCTL_DSP_GETCHANNELMASK:
ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR |
- DSP_BIND_CENTER_LFE, (int *) arg);
+ DSP_BIND_CENTER_LFE, p);
break;
case SNDCTL_DSP_BIND_CHANNEL:
break;
}
- if (get_user(val, (int *) arg)) {
+ if (get_user(val, p)) {
ret = -EFAULT;
break;
}
SRC_ENABLE);
dmabuf->channel->attribute |= mask2attr[ffs(val)];
}
- ret = put_user(val, (int *) arg);
+ ret = put_user(val, p);
break;
case SNDCTL_DSP_MAPINBUF:
pr_debug("trident: open virtual channel %d, hard channel %d\n",
state->virt, dmabuf->channel->num);
- return 0;
+ return nonseekable_open(inode, file);
}
static int
}
static int
-trident_suspend(struct pci_dev *dev, u32 unused)
+trident_suspend(struct pci_dev *dev, pm_message_t unused)
{
struct trident_card *card = pci_get_drvdata(dev);
state DMA is protected by a spinlock.
*/
static int
-ali_write_5_1(struct trident_state *state, const char *buf,
+ali_write_5_1(struct trident_state *state, const char __user *buf,
int cnt_for_multi_channel, unsigned int *copy_count,
unsigned int *state_cnt)
{
struct dmabuf *dmabuf = &state->dmabuf;
struct dmabuf *dmabuf_temp;
- const char *buffer = buf;
+ const char __user *buffer = buf;
unsigned swptr, other_dma_nums, sample_s;
unsigned int i, loop;
}
}
-struct proc_dir_entry *res;
+static struct proc_dir_entry *res;
+
static int
-ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
+ali_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
struct trident_card *card = (struct trident_card *) data;
unsigned long flags;
match:
file->private_data = card->ac97_codec[i];
- return 0;
+ return nonseekable_open(inode, file);
}
static int
return num_ac97 + 1;
}
+#ifdef SUPPORT_JOYSTICK
/* Gameport functions for the cards ADC gameport */
-static unsigned char
-trident_game_read(struct gameport *gameport)
+static unsigned char trident_game_read(struct gameport *gameport)
{
- struct trident_card *card = gameport->driver;
+ struct trident_card *card = gameport->port_data;
+
return inb(TRID_REG(card, T4D_GAME_LEG));
}
-static void
-trident_game_trigger(struct gameport *gameport)
+static void trident_game_trigger(struct gameport *gameport)
{
- struct trident_card *card = gameport->driver;
+ struct trident_card *card = gameport->port_data;
+
outb(0xff, TRID_REG(card, T4D_GAME_LEG));
}
-static int
-trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int trident_game_cooked_read(struct gameport *gameport,
+ int *axes, int *buttons)
{
- struct trident_card *card = gameport->driver;
+ struct trident_card *card = gameport->port_data;
int i;
*buttons = (~inb(TRID_REG(card, T4D_GAME_LEG)) >> 4) & 0xf;
return 0;
}
-static int
-trident_game_open(struct gameport *gameport, int mode)
+static int trident_game_open(struct gameport *gameport, int mode)
{
- struct trident_card *card = gameport->driver;
+ struct trident_card *card = gameport->port_data;
switch (mode) {
case GAMEPORT_MODE_COOKED:
return 0;
}
+static int __devinit trident_register_gameport(struct trident_card *card)
+{
+ struct gameport *gp;
+
+ card->gameport = gp = gameport_allocate_port();
+ if (!gp) {
+ printk(KERN_ERR "trident: can not allocate memory for gameport\n");
+ return -ENOMEM;
+ }
+
+ gameport_set_name(gp, "Trident 4DWave");
+ gameport_set_phys(gp, "pci%s/gameport0", pci_name(card->pci_dev));
+ gp->read = trident_game_read;
+ gp->trigger = trident_game_trigger;
+ gp->cooked_read = trident_game_cooked_read;
+ gp->open = trident_game_open;
+ gp->fuzz = 64;
+ gp->port_data = card;
+
+ gameport_register_port(gp);
+
+ return 0;
+}
+
+static inline void trident_unregister_gameport(struct trident_card *card)
+{
+ if (card->gameport)
+ gameport_unregister_port(card->gameport);
+}
+
+#else
+static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
+static inline void trident_unregister_gameport(struct trident_card *card) { }
+#endif /* SUPPORT_JOYSTICK */
+
/* install the driver, we do not allocate hardware channel nor DMA buffer */
/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
/* open/read/write/ioctl/mmap) */
card->banks[BANK_B].addresses = &bank_b_addrs;
card->banks[BANK_B].bitmap = 0UL;
- card->gameport.driver = card;
- card->gameport.fuzz = 64;
- card->gameport.read = trident_game_read;
- card->gameport.trigger = trident_game_trigger;
- card->gameport.cooked_read = trident_game_cooked_read;
- card->gameport.open = trident_game_open;
-
init_MUTEX(&card->open_sem);
spin_lock_init(&card->lock);
init_timer(&card->timer);
trident_enable_loop_interrupts(card);
/* Register gameport */
- gameport_register_port(&card->gameport);
+ trident_register_gameport(card);
out:
return rc;
}
/* Unregister gameport */
- gameport_unregister_port(&card->gameport);
+ trident_unregister_gameport(card);
/* Kill interrupts, and SP/DIF */
trident_disable_loop_interrupts(card);
"5050 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " "
__DATE__ "\n");
- if (!pci_register_driver(&trident_pci_driver)) {
- pci_unregister_driver(&trident_pci_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_register_driver(&trident_pci_driver);
}
static void __exit