#include <linux/smp_lock.h>
#include <linux/gameport.h>
#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+
#include <asm/io.h>
#include <asm/page.h>
#define FMODE_DMFM 0x10
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
static struct pci_driver solo1_driver;
/* --------------------------------------------------------------------- */
unsigned ena;
spinlock_t lock;
- struct semaphore open_sem;
+ struct mutex open_mutex;
mode_t open_mode;
wait_queue_head_t open_wait;
unsigned char obuf[MIDIOUTBUF];
} midi;
- struct gameport gameport;
+#if SUPPORT_JOYSTICK
+ struct gameport *gameport;
+#endif
};
/* --------------------------------------------------------------------- */
return 0;
}
-static inline int prog_dmabuf_dac(struct solo1_state *s)
+static int prog_dmabuf_dac(struct solo1_state *s)
{
unsigned long va;
int c;
lock_kernel();
if (file->f_mode & FMODE_WRITE)
drain_dac(s, file->f_flags & O_NONBLOCK);
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
outb(0, s->iobase+6); /* disable DMA */
}
s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
wake_up(&s->open_wait);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
unlock_kernel();
return 0;
}
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
if (file->f_flags & O_NONBLOCK) {
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
return -EBUSY;
}
add_wait_queue(&s->open_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
schedule();
remove_wait_queue(&s->open_wait, &wait);
set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
}
s->fmt = AFMT_U8;
s->channels = 1;
s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
s->dma_dac.enabled = 1;
s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
prog_codec(s);
return nonseekable_open(inode, file);
}
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
if (file->f_flags & O_NONBLOCK) {
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
return -EBUSY;
}
add_wait_queue(&s->open_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
schedule();
remove_wait_queue(&s->open_wait, &wait);
set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
}
spin_lock_irqsave(&s->lock, flags);
if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
}
spin_unlock_irqrestore(&s->lock, flags);
s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
return nonseekable_open(inode, file);
}
remove_wait_queue(&s->midi.owait, &wait);
set_current_state(TASK_RUNNING);
}
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
spin_lock_irqsave(&s->lock, flags);
if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
}
spin_unlock_irqrestore(&s->lock, flags);
wake_up(&s->open_wait);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
unlock_kernel();
return 0;
}
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
while (s->open_mode & FMODE_DMFM) {
if (file->f_flags & O_NONBLOCK) {
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
return -EBUSY;
}
add_wait_queue(&s->open_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
schedule();
remove_wait_queue(&s->open_wait, &wait);
set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
}
if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
return -EBUSY;
}
outb(5, s->sbbase+2);
outb(1, s->sbbase+3); /* enable OPL3 */
s->open_mode |= FMODE_DMFM;
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
return nonseekable_open(inode, file);
}
VALIDATE_STATE(s);
lock_kernel();
- down(&s->open_sem);
+ mutex_lock(&s->open_mutex);
s->open_mode &= ~FMODE_DMFM;
for (regb = 0xb0; regb < 0xb9; regb++) {
outb(regb, s->sbbase);
}
release_region(s->sbbase, FMSYNTH_EXTENT);
wake_up(&s->open_wait);
- up(&s->open_sem);
+ mutex_unlock(&s->open_mutex);
unlock_kernel();
return 0;
}
static struct initvol {
int mixch;
int vol;
-} initvol[] __initdata = {
+} initvol[] __devinitdata = {
{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
{ SOUND_MIXER_WRITE_PCM, 0x4040 },
{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
}
static int
-solo1_suspend(struct pci_dev *pci_dev, u32 state) {
+solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
if (!s)
return 1;
return 0;
}
+#ifdef SUPPORT_JOYSTICK
+static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
+{
+ struct gameport *gp;
+
+ if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
+ printk(KERN_ERR "solo1: gameport io ports are in use\n");
+ return -EBUSY;
+ }
+
+ s->gameport = gp = gameport_allocate_port();
+ if (!gp) {
+ printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
+ release_region(io_port, GAMEPORT_EXTENT);
+ return -ENOMEM;
+ }
+
+ gameport_set_name(gp, "ESS Solo1 Gameport");
+ gameport_set_phys(gp, "isa%04x/gameport0", io_port);
+ gp->dev.parent = &s->dev->dev;
+ gp->io = io_port;
+
+ gameport_register_port(gp);
+
+ return 0;
+}
+
+static inline void solo1_unregister_gameport(struct solo1_state *s)
+{
+ if (s->gameport) {
+ int gpio = s->gameport->io;
+ gameport_unregister_port(s->gameport);
+ release_region(gpio, GAMEPORT_EXTENT);
+ }
+}
+#else
+static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
+static inline void solo1_unregister_gameport(struct solo1_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct solo1_state *s;
+ int gpio;
int ret;
if ((ret=pci_enable_device(pcidev)))
/* Recording requires 24-bit DMA, so attempt to set dma mask
* to 24 bits first, then 32 bits (playback only) if that fails.
*/
- if (pci_set_dma_mask(pcidev, 0x00ffffff) &&
- pci_set_dma_mask(pcidev, 0xffffffff)) {
+ if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
+ pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
return -ENODEV;
}
init_waitqueue_head(&s->open_wait);
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
- init_MUTEX(&s->open_sem);
+ mutex_init(&s->open_mutex);
spin_lock_init(&s->lock);
s->magic = SOLO1_MAGIC;
s->dev = pcidev;
s->vcbase = pci_resource_start(pcidev, 2);
s->ddmabase = s->vcbase + DDMABASE_OFFSET;
s->mpubase = pci_resource_start(pcidev, 3);
- s->gameport.io = pci_resource_start(pcidev, 4);
+ gpio = pci_resource_start(pcidev, 4);
s->irq = pcidev->irq;
ret = -EBUSY;
if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
printk(KERN_ERR "solo1: io ports in use\n");
goto err_region4;
}
- if (s->gameport.io && !request_region(s->gameport.io, GAMEPORT_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: gameport io ports in use\n");
- s->gameport.io = 0;
- }
if ((ret=request_irq(s->irq,solo1_interrupt,SA_SHIRQ,"ESS Solo1",s))) {
printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
goto err_irq;
}
- printk(KERN_INFO "solo1: joystick port at %#x\n", s->gameport.io+1);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
ret = s->dev_audio;
goto err;
}
/* register gameport */
- gameport_register_port(&s->gameport);
+ solo1_register_gameport(s, gpio);
/* store it in the driver field */
pci_set_drvdata(pcidev, s);
return 0;
printk(KERN_ERR "solo1: initialisation error\n");
free_irq(s->irq, s);
err_irq:
- if (s->gameport.io)
- release_region(s->gameport.io, GAMEPORT_EXTENT);
release_region(s->mpubase, MPUBASE_EXTENT);
err_region4:
release_region(s->ddmabase, DDMABASE_EXTENT);
synchronize_irq(s->irq);
pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
free_irq(s->irq, s);
- if (s->gameport.io) {
- gameport_unregister_port(&s->gameport);
- release_region(s->gameport.io, GAMEPORT_EXTENT);
- }
+ solo1_unregister_gameport(s);
release_region(s->iobase, IOBASE_EXTENT);
release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
release_region(s->ddmabase, DDMABASE_EXTENT);