*
* Lock order (high->low)
* lock - hardware lock
- * open_sem - guard opens
+ * open_mutex - guard opens
* sem - guard dmabuf, write re-entry etc
*/
#include <linux/pm.h>
#include <linux/gameport.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.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,}
};
unsigned chans_num;
unsigned long fmt_flag;
/* Guard against mmap/write/read races */
- struct semaphore sem;
+ struct mutex sem;
};
struct trident_card *next;
/* single open lock mechanism, only used for recording */
- struct semaphore open_sem;
+ struct mutex open_mutex;
/* The trident has a certain amount of cross channel interaction
so we use a single per card lock */
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- down(&state->sem);
+ mutex_lock(&state->sem);
if (!dmabuf->ready && (ret = prog_dmabuf_record(state)))
goto out;
goto out;
}
- up(&state->sem);
+ mutex_unlock(&state->sem);
/* No matter how much space left in the buffer, */
/* we have to wait until CSO == ESO/2 or CSO == ESO */
/* when address engine interrupts */
ret = -ERESTARTSYS;
goto out;
}
- down(&state->sem);
+ mutex_lock(&state->sem);
if (dmabuf->mapped) {
if (!ret)
ret = -ENXIO;
start_adc(state);
}
out:
- up(&state->sem);
+ mutex_unlock(&state->sem);
return ret;
}
* Guard against an mmap or ioctl while writing
*/
- down(&state->sem);
+ mutex_lock(&state->sem);
if (dmabuf->mapped) {
ret = -ENXIO;
tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
tmo >>= sample_shift[dmabuf->fmt];
unlock_set_fmt(state);
- up(&state->sem);
+ mutex_unlock(&state->sem);
/* There are two situations when sleep_on_timeout */
/* returns, one is when the interrupt is serviced */
ret = -ERESTARTSYS;
goto out_nolock;
}
- down(&state->sem);
+ mutex_lock(&state->sem);
if (dmabuf->mapped) {
if (!ret)
ret = -ENXIO;
start_dac(state);
}
out:
- up(&state->sem);
+ mutex_unlock(&state->sem);
out_nolock:
return ret;
}
* prog_dmabuf events
*/
- down(&state->sem);
+ mutex_lock(&state->sem);
if (file->f_mode & FMODE_WRITE) {
if (!dmabuf->ready && prog_dmabuf_playback(state)) {
- up(&state->sem);
+ mutex_unlock(&state->sem);
return 0;
}
poll_wait(file, &dmabuf->wait, wait);
}
if (file->f_mode & FMODE_READ) {
if (!dmabuf->ready && prog_dmabuf_record(state)) {
- up(&state->sem);
+ mutex_unlock(&state->sem);
return 0;
}
poll_wait(file, &dmabuf->wait, wait);
}
- up(&state->sem);
+ mutex_unlock(&state->sem);
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
* a read or write against an mmap.
*/
- down(&state->sem);
+ mutex_lock(&state->sem);
if (vma->vm_flags & VM_WRITE) {
if ((ret = prog_dmabuf_playback(state)) != 0)
dmabuf->mapped = 1;
ret = 0;
out:
- up(&state->sem);
+ mutex_unlock(&state->sem);
return ret;
}
unlock_set_fmt(state);
break;
}
- down(&state->card->open_sem);
+ mutex_lock(&state->card->open_mutex);
ret = ali_allocate_other_states_resources(state, 6);
if (ret < 0) {
- up(&state->card->open_sem);
+ mutex_unlock(&state->card->open_mutex);
unlock_set_fmt(state);
break;
}
state->card->multi_channel_use_count++;
- up(&state->card->open_sem);
+ mutex_unlock(&state->card->open_mutex);
} else
val = 2; /*yield to 2-channels */
} else
/* find an available virtual channel (instance of /dev/dsp) */
while (card != NULL) {
- down(&card->open_sem);
+ mutex_lock(&card->open_mutex);
if (file->f_mode & FMODE_READ) {
/* Skip opens on cards that are in 6 channel mode */
if (card->multi_channel_use_count > 0) {
- up(&card->open_sem);
+ mutex_unlock(&card->open_mutex);
card = card->next;
continue;
}
if (card->states[i] == NULL) {
state = card->states[i] = kmalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL) {
- up(&card->open_sem);
+ mutex_unlock(&card->open_mutex);
return -ENOMEM;
}
memset(state, 0, sizeof(*state));
- init_MUTEX(&state->sem);
+ mutex_init(&state->sem);
dmabuf = &state->dmabuf;
goto found_virt;
}
}
- up(&card->open_sem);
+ mutex_unlock(&card->open_mutex);
card = card->next;
}
/* no more virtual channel avaiable */
}
state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- up(&card->open_sem);
+ mutex_unlock(&card->open_mutex);
pr_debug("trident: open virtual channel %d, hard channel %d\n",
state->virt, dmabuf->channel->num);
state->virt, dmabuf->channel->num);
/* stop DMA state machine and free DMA buffers/channels */
- down(&card->open_sem);
+ mutex_lock(&card->open_mutex);
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
card->states[state->virt] = NULL;
kfree(state);
- /* we're covered by the open_sem */
- up(&card->open_sem);
+ /* we're covered by the open_mutex */
+ mutex_unlock(&card->open_mutex);
return 0;
}
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->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->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->port_data;
int i;
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->port_data;
return 0;
}
-static int __devinit
-trident_register_gameport(struct trident_card *card)
+static int __devinit trident_register_gameport(struct trident_card *card)
{
struct gameport *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;
- init_MUTEX(&card->open_sem);
+ mutex_init(&card->open_mutex);
spin_lock_init(&card->lock);
init_timer(&card->timer);
}
/* Unregister gameport */
- if (card->gameport)
- gameport_unregister_port(card->gameport);
+ trident_unregister_gameport(card);
/* Kill interrupts, and SP/DIF */
trident_disable_loop_interrupts(card);