linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / sound / oss / esssolo1.c
index cbd78ed..849b59f 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
+#include <linux/dma-mapping.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;
 
 /* --------------------------------------------------------------------- */
@@ -226,7 +231,9 @@ struct solo1_state {
                unsigned char obuf[MIDIOUTBUF];
        } midi;
 
-       struct gameport gameport;
+#if SUPPORT_JOYSTICK
+       struct gameport *gameport;
+#endif
 };
 
 /* --------------------------------------------------------------------- */
@@ -445,7 +452,7 @@ static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
                if (!db->rawbuf)
                        return -ENOMEM;
                db->buforder = order;
-               /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+               /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
                pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
                for (page = virt_to_page(db->rawbuf); page <= pend; page++)
                        SetPageReserved(page);
@@ -508,7 +515,7 @@ static inline int prog_dmabuf_adc(struct solo1_state *s)
        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;
@@ -694,37 +701,38 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
        };
        unsigned char l, r, rl, rr, vidx;
        int i, val;
+       int __user *p = (int __user *)arg;
 
        VALIDATE_STATE(s);
 
        if (cmd == SOUND_MIXER_PRIVATE1) {
                /* enable/disable/query mixer preamp */
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                if (val != -1) {
                        val = val ? 0xff : 0xf7;
                        write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
                }
                val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
-               return put_user(val, (int *)arg);
+               return put_user(val, p);
        }
        if (cmd == SOUND_MIXER_PRIVATE2) {
                /* enable/disable/query spatializer */
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                if (val != -1) {
                        val &= 0x3f;
                        write_mixer(s, 0x52, val);
                        write_mixer(s, 0x50, val ? 0x08 : 0);
                }
-               return put_user(read_mixer(s, 0x52), (int *)arg);
+               return put_user(read_mixer(s, 0x52), p);
        }
         if (cmd == SOUND_MIXER_INFO) {
                mixer_info info;
                strncpy(info.id, "Solo1", sizeof(info.id));
                strncpy(info.name, "ESS Solo1", sizeof(info.name));
                info.modify_counter = s->mix.modcnt;
-               if (copy_to_user((void *)arg, &info, sizeof(info)))
+               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
                        return -EFAULT;
                return 0;
        }
@@ -732,41 +740,41 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
                _old_mixer_info info;
                strncpy(info.id, "Solo1", sizeof(info.id));
                strncpy(info.name, "ESS Solo1", sizeof(info.name));
-               if (copy_to_user((void *)arg, &info, sizeof(info)))
+               if (copy_to_user((void __user *)arg, &info, sizeof(info)))
                        return -EFAULT;
                return 0;
        }
        if (cmd == OSS_GETVERSION)
-               return put_user(SOUND_VERSION, (int *)arg);
+               return put_user(SOUND_VERSION, p);
        if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
                 return -EINVAL;
         if (_SIOC_DIR(cmd) == _SIOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-                       return put_user(mixer_src[read_mixer(s, 0x1c) & 7], (int *)arg);
+                       return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p);
 
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
                        return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
                                        SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
                                        SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
-                                       SOUND_MASK_SPEAKER, (int *)arg);
+                                       SOUND_MASK_SPEAKER, p);
 
                 case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-                       return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, (int *)arg);
+                       return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p);
 
                 case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
                        return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
                                        SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
-                                       SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, (int *)arg);
+                                       SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p);
                        
                 case SOUND_MIXER_CAPS:
-                       return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+                       return put_user(SOUND_CAP_EXCL_INPUT, p);
 
                default:
                        i = _IOC_NR(cmd);
                         if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
                                 return -EINVAL;
-                       return put_user(s->mix.vol[vidx-1], (int *)arg);
+                       return put_user(s->mix.vol[vidx-1], p);
                }
        }
         if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
@@ -788,7 +796,7 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
                               0xb4, read_ctrl(s, 0xb4));
                }
 #endif
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                 i = hweight32(val);
                 if (i == 0)
@@ -805,7 +813,7 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
                return 0;
 
        case SOUND_MIXER_VOLUME:
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                l = val & 0xff;
                if (l > 100)
@@ -834,10 +842,10 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
 #else
                 s->mix.vol[9] = val;
 #endif
-               return put_user(s->mix.vol[9], (int *)arg);
+               return put_user(s->mix.vol[9], p);
 
        case SOUND_MIXER_SPEAKER:
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                l = val & 0xff;
                if (l > 100)
@@ -852,10 +860,10 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
 #else
                 s->mix.vol[7] = val;
 #endif
-               return put_user(s->mix.vol[7], (int *)arg);
+               return put_user(s->mix.vol[7], p);
 
        case SOUND_MIXER_RECLEV:
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                l = (val << 1) & 0x1fe;
                if (l > 200)
@@ -877,13 +885,13 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
 #else
                 s->mix.vol[8] = val;
 #endif
-               return put_user(s->mix.vol[8], (int *)arg);
+               return put_user(s->mix.vol[8], p);
 
        default:
                i = _IOC_NR(cmd);
                if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
                        return -EINVAL;
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                l = (val << 1) & 0x1fe;
                if (l > 200)
@@ -905,7 +913,7 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
 #else
                 s->mix.vol[vidx-1] = val;
 #endif
-               return put_user(s->mix.vol[vidx-1], (int *)arg);
+               return put_user(s->mix.vol[vidx-1], p);
        }
 }
 
@@ -932,7 +940,7 @@ static int solo1_open_mixdev(struct inode *inode, struct file *file)
                return -ENODEV;
                VALIDATE_STATE(s);
        file->private_data = s;
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int solo1_release_mixdev(struct inode *inode, struct file *file)
@@ -999,7 +1007,7 @@ static int drain_dac(struct solo1_state *s, int nonblock)
 
 /* --------------------------------------------------------------------- */
 
-static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
        DECLARE_WAITQUEUE(wait, current);
@@ -1009,8 +1017,6 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t
        int cnt;
 
        VALIDATE_STATE(s);
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
        if (s->dma_adc.mapped)
                return -ENXIO;
        if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
@@ -1095,7 +1101,7 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t
        return ret;
 }
 
-static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
        DECLARE_WAITQUEUE(wait, current);
@@ -1105,8 +1111,6 @@ static ssize_t solo1_write(struct file *file, const char *buffer, size_t count,
        int cnt;
 
        VALIDATE_STATE(s);
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
        if (s->dma_dac.mapped)
                return -ENXIO;
        if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
@@ -1245,7 +1249,9 @@ static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
        if (size > (PAGE_SIZE << db->buforder))
                goto out;
        ret = -EAGAIN;
-       if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+       if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+                               size, vma->vm_page_prot))
                goto out;
        db->mapped = 1;
        ret = 0;
@@ -1263,13 +1269,15 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        int val, mapped, ret, count;
         int div1, div2;
         unsigned rate1, rate2;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
 
        VALIDATE_STATE(s);
         mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
                ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
        switch (cmd) {
        case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, (int *)arg);
+               return put_user(SOUND_VERSION, p);
 
        case SNDCTL_DSP_SYNC:
                if (file->f_mode & FMODE_WRITE)
@@ -1280,7 +1288,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
                
         case SNDCTL_DSP_RESET:
                if (file->f_mode & FMODE_WRITE) {
@@ -1297,7 +1305,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                return 0;
 
         case SNDCTL_DSP_SPEED:
-                if (get_user(val, (int *)arg))
+                if (get_user(val, p))
                        return -EFAULT;
                if (val >= 0) {
                        stop_adc(s);
@@ -1322,10 +1330,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        s->clkdiv = div1;
                        prog_codec(s);
                }
-               return put_user(s->rate, (int *)arg);
+               return put_user(s->rate, p);
                
         case SNDCTL_DSP_STEREO:
-                if (get_user(val, (int *)arg))
+                if (get_user(val, p))
                        return -EFAULT;
                stop_adc(s);
                stop_dac(s);
@@ -1336,7 +1344,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, (int *)arg))
+                if (get_user(val, p))
                        return -EFAULT;
                if (val != 0) {
                        stop_adc(s);
@@ -1346,13 +1354,13 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        s->channels = (val >= 2) ? 2 : 1;
                        prog_codec(s);
                }
-               return put_user(s->channels, (int *)arg);
+               return put_user(s->channels, p);
 
        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+                return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p);
 
        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                if (val != AFMT_QUERY) {
                        stop_adc(s);
@@ -1365,7 +1373,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        s->fmt = val;
                        prog_codec(s);
                }
-               return put_user(s->fmt, (int *)arg);
+               return put_user(s->fmt, p);
 
        case SNDCTL_DSP_POST:
                 return 0;
@@ -1376,10 +1384,10 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        val |= PCM_ENABLE_INPUT;
                if (file->f_mode & s->ena & FMODE_WRITE)
                        val |= PCM_ENABLE_OUTPUT;
-               return put_user(val, (int *)arg);
+               return put_user(val, p);
 
        case SNDCTL_DSP_SETTRIGGER:
-               if (get_user(val, (int *)arg))
+               if (get_user(val, p))
                        return -EFAULT;
                if (file->f_mode & FMODE_READ) {
                        if (val & PCM_ENABLE_INPUT) {
@@ -1422,7 +1430,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                 abinfo.fragstotal = s->dma_dac.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
                spin_unlock_irqrestore(&s->lock, flags);
-               return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
        case SNDCTL_DSP_GETISPACE:
                if (!(file->f_mode & FMODE_READ))
@@ -1436,7 +1444,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                 abinfo.fragstotal = s->dma_adc.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
                spin_unlock_irqrestore(&s->lock, flags);
-               return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+               return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
         case SNDCTL_DSP_NONBLOCK:
                 file->f_flags |= O_NONBLOCK;
@@ -1453,7 +1461,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                spin_unlock_irqrestore(&s->lock, flags);
                if (count < 0)
                        count = 0;
-               return put_user(count, (int *)arg);
+               return put_user(count, p);
 
         case SNDCTL_DSP_GETIPTR:
                if (!(file->f_mode & FMODE_READ))
@@ -1468,7 +1476,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                if (s->dma_adc.mapped)
                        s->dma_adc.count &= s->dma_adc.fragsize-1;
                spin_unlock_irqrestore(&s->lock, flags);
-               if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
+               if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
                        return -EFAULT;
                return 0;
 
@@ -1494,7 +1502,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                       cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
                       s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
 #endif
-               if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
+               if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
                        return -EFAULT;
                return 0;
 
@@ -1502,14 +1510,14 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                if (file->f_mode & FMODE_WRITE) {
                        if ((val = prog_dmabuf_dac(s)))
                                return val;
-                       return put_user(s->dma_dac.fragsize, (int *)arg);
+                       return put_user(s->dma_dac.fragsize, p);
                }
                if ((val = prog_dmabuf_adc(s)))
                        return val;
-               return put_user(s->dma_adc.fragsize, (int *)arg);
+               return put_user(s->dma_adc.fragsize, p);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, (int *)arg))
+                if (get_user(val, p))
                        return -EFAULT;
                if (file->f_mode & FMODE_READ) {
                        s->dma_adc.ossfragshift = val & 0xffff;
@@ -1537,7 +1545,7 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
                    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
                        return -EINVAL;
-                if (get_user(val, (int *)arg))
+                if (get_user(val, p))
                        return -EFAULT;
                if (val != 1 && val != 2 && val != 4)
                        return -EINVAL;
@@ -1548,13 +1556,13 @@ static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                return 0;
 
         case SOUND_PCM_READ_RATE:
-               return put_user(s->rate, (int *)arg);
+               return put_user(s->rate, p);
 
         case SOUND_PCM_READ_CHANNELS:
-               return put_user(s->channels, (int *)arg);
+               return put_user(s->channels, p);
 
         case SOUND_PCM_READ_BITS:
-               return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg);
+               return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p);
 
         case SOUND_PCM_WRITE_FILTER:
         case SNDCTL_DSP_SETSYNCRO:
@@ -1644,7 +1652,7 @@ static int solo1_open(struct inode *inode, struct file *file)
        s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
        up(&s->open_sem);
        prog_codec(s);
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static /*const*/ struct file_operations solo1_audio_fops = {
@@ -1727,7 +1735,7 @@ static void solo1_midi_timer(unsigned long data)
 
 /* --------------------------------------------------------------------- */
 
-static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
        DECLARE_WAITQUEUE(wait, current);
@@ -1737,8 +1745,6 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo
        int cnt;
 
        VALIDATE_STATE(s);
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
        if (!access_ok(VERIFY_WRITE, buffer, count))
                return -EFAULT;
        if (count == 0)
@@ -1790,7 +1796,7 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo
        return ret;
 }
 
-static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
        struct solo1_state *s = (struct solo1_state *)file->private_data;
        DECLARE_WAITQUEUE(wait, current);
@@ -1800,8 +1806,6 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co
        int cnt;
 
        VALIDATE_STATE(s);
-       if (ppos != &file->f_pos)
-               return -ESPIPE;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
        if (count == 0)
@@ -1948,7 +1952,7 @@ static int solo1_midi_open(struct inode *inode, struct file *file)
        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);
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int solo1_midi_release(struct inode *inode, struct file *file)
@@ -2032,7 +2036,7 @@ static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int
                return 0;
 
        case FM_IOCTL_PLAY_NOTE:
-               if (copy_from_user(&n, (void *)arg, sizeof(n)))
+               if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
                        return -EFAULT;
                if (n.voice >= 18)
                        return -EINVAL;
@@ -2050,7 +2054,7 @@ static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int
                return 0;
 
        case FM_IOCTL_SET_VOICE:
-               if (copy_from_user(&v, (void *)arg, sizeof(v)))
+               if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
                        return -EFAULT;
                if (v.voice >= 18)
                        return -EINVAL;
@@ -2080,7 +2084,7 @@ static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int
                return 0;
                
        case FM_IOCTL_SET_PARAMS:
-               if (copy_from_user(&p, (void *)arg, sizeof(p)))
+               if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
                        return -EFAULT;
                outb(0x08, s->sbbase);
                outb((p.kbd_split & 1) << 6, s->sbbase+1);
@@ -2158,7 +2162,7 @@ static int solo1_dmfm_open(struct inode *inode, struct file *file)
        outb(1, s->sbbase+3);  /* enable OPL3 */
        s->open_mode |= FMODE_DMFM;
        up(&s->open_sem);
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int solo1_dmfm_release(struct inode *inode, struct file *file)
@@ -2196,7 +2200,7 @@ static /*const*/ struct file_operations solo1_dmfm_fops = {
 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 },
@@ -2260,7 +2264,7 @@ static int setup_solo1(struct solo1_state *s)
 }
 
 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;
@@ -2283,9 +2287,50 @@ solo1_resume(struct pci_dev *pci_dev) {
        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)))
@@ -2302,7 +2347,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
         * 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)) {
+           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;
        }
@@ -2326,7 +2371,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
        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")) {
@@ -2345,15 +2390,10 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
                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;
@@ -2376,7 +2416,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
                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;
@@ -2393,8 +2433,6 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
        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);
@@ -2420,10 +2458,7 @@ static void __devexit solo1_remove(struct pci_dev *dev)
        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);
@@ -2456,11 +2491,7 @@ static struct pci_driver solo1_driver = {
 static int __init init_solo1(void)
 {
        printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
-       if (!pci_register_driver(&solo1_driver)) {
-               pci_unregister_driver(&solo1_driver);
-                return -ENODEV;
-       }
-       return 0;
+       return pci_register_driver(&solo1_driver);
 }
 
 /* --------------------------------------------------------------------- */