linux/drivers/media/radio/radio-gemtek-pci.c
<<
>>
Prefs
   1/*
   2 ***************************************************************************
   3 *
   4 *     radio-gemtek-pci.c - Gemtek PCI Radio driver
   5 *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
   6 *
   7 ***************************************************************************
   8 *
   9 *     This program is free software; you can redistribute it and/or
  10 *     modify it under the terms of the GNU General Public License as
  11 *     published by the Free Software Foundation; either version 2 of
  12 *     the License, or (at your option) any later version.
  13 *
  14 *     This program is distributed in the hope that it will be useful,
  15 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *     GNU General Public License for more details.
  18 *
  19 *     You should have received a copy of the GNU General Public
  20 *     License along with this program; if not, write to the Free
  21 *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  22 *     USA.
  23 *
  24 ***************************************************************************
  25 *
  26 *     Gemtek Corp still silently refuses to release any specifications
  27 *     of their multimedia devices, so the protocol still has to be
  28 *     reverse engineered.
  29 *
  30 *     The v4l code was inspired by Jonas Munsin's  Gemtek serial line
  31 *     radio device driver.
  32 *
  33 *     Please, let me know if this piece of code was useful :)
  34 *
  35 *     TODO: multiple device support and portability were not tested
  36 *
  37 *     Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  38 *
  39 ***************************************************************************
  40 */
  41
  42#include <linux/types.h>
  43#include <linux/list.h>
  44#include <linux/module.h>
  45#include <linux/init.h>
  46#include <linux/pci.h>
  47#include <linux/videodev2.h>
  48#include <linux/errno.h>
  49#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
  50#include <linux/io.h>
  51#include <linux/slab.h>
  52#include <media/v4l2-device.h>
  53#include <media/v4l2-ioctl.h>
  54
  55MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
  56MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
  57MODULE_LICENSE("GPL");
  58
  59static int nr_radio = -1;
  60static int mx = 1;
  61
  62module_param(mx, bool, 0);
  63MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
  64module_param(nr_radio, int, 0);
  65MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
  66
  67#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
  68
  69#ifndef PCI_VENDOR_ID_GEMTEK
  70#define PCI_VENDOR_ID_GEMTEK 0x5046
  71#endif
  72
  73#ifndef PCI_DEVICE_ID_GEMTEK_PR103
  74#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
  75#endif
  76
  77#ifndef GEMTEK_PCI_RANGE_LOW
  78#define GEMTEK_PCI_RANGE_LOW (87*16000)
  79#endif
  80
  81#ifndef GEMTEK_PCI_RANGE_HIGH
  82#define GEMTEK_PCI_RANGE_HIGH (108*16000)
  83#endif
  84
  85struct gemtek_pci {
  86        struct v4l2_device v4l2_dev;
  87        struct video_device vdev;
  88        struct mutex lock;
  89        struct pci_dev *pdev;
  90
  91        u32 iobase;
  92        u32 length;
  93
  94        u32 current_frequency;
  95        u8  mute;
  96};
  97
  98static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
  99{
 100        return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
 101}
 102
 103static inline u8 gemtek_pci_out(u16 value, u32 port)
 104{
 105        outw(value, port);
 106
 107        return (u8)value;
 108}
 109
 110#define _b0(v) (*((u8 *)&v))
 111
 112static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
 113{
 114        u8 byte = *last_byte;
 115
 116        if (!value) {
 117                if (!keep)
 118                        value = (u16)port;
 119                byte &= 0xfd;
 120        } else
 121                byte |= 2;
 122
 123        _b0(value) = byte;
 124        outw(value, port);
 125        byte |= 1;
 126        _b0(value) = byte;
 127        outw(value, port);
 128        byte &= 0xfe;
 129        _b0(value) = byte;
 130        outw(value, port);
 131
 132        *last_byte = byte;
 133}
 134
 135static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
 136{
 137        __gemtek_pci_cmd(0x00, port, last_byte, false);
 138}
 139
 140static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
 141{
 142        __gemtek_pci_cmd(cmd, port, last_byte, true);
 143}
 144
 145static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
 146{
 147        int i;
 148        u32 value = frequency / 200 + 856;
 149        u16 mask = 0x8000;
 150        u8 last_byte;
 151        u32 port = card->iobase;
 152
 153        mutex_lock(&card->lock);
 154        card->current_frequency = frequency;
 155        last_byte = gemtek_pci_out(0x06, port);
 156
 157        i = 0;
 158        do {
 159                gemtek_pci_nil(port, &last_byte);
 160                i++;
 161        } while (i < 9);
 162
 163        i = 0;
 164        do {
 165                gemtek_pci_cmd(value & mask, port, &last_byte);
 166                mask >>= 1;
 167                i++;
 168        } while (i < 16);
 169
 170        outw(0x10, port);
 171        mutex_unlock(&card->lock);
 172}
 173
 174
 175static void gemtek_pci_mute(struct gemtek_pci *card)
 176{
 177        mutex_lock(&card->lock);
 178        outb(0x1f, card->iobase);
 179        card->mute = true;
 180        mutex_unlock(&card->lock);
 181}
 182
 183static void gemtek_pci_unmute(struct gemtek_pci *card)
 184{
 185        if (card->mute) {
 186                gemtek_pci_setfrequency(card, card->current_frequency);
 187                card->mute = false;
 188        }
 189}
 190
 191static int gemtek_pci_getsignal(struct gemtek_pci *card)
 192{
 193        int sig;
 194
 195        mutex_lock(&card->lock);
 196        sig = (inb(card->iobase) & 0x08) ? 0 : 1;
 197        mutex_unlock(&card->lock);
 198        return sig;
 199}
 200
 201static int vidioc_querycap(struct file *file, void *priv,
 202                                        struct v4l2_capability *v)
 203{
 204        struct gemtek_pci *card = video_drvdata(file);
 205
 206        strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
 207        strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
 208        snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
 209        v->version = RADIO_VERSION;
 210        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 211        return 0;
 212}
 213
 214static int vidioc_g_tuner(struct file *file, void *priv,
 215                                        struct v4l2_tuner *v)
 216{
 217        struct gemtek_pci *card = video_drvdata(file);
 218
 219        if (v->index > 0)
 220                return -EINVAL;
 221
 222        strlcpy(v->name, "FM", sizeof(v->name));
 223        v->type = V4L2_TUNER_RADIO;
 224        v->rangelow = GEMTEK_PCI_RANGE_LOW;
 225        v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
 226        v->rxsubchans = V4L2_TUNER_SUB_MONO;
 227        v->capability = V4L2_TUNER_CAP_LOW;
 228        v->audmode = V4L2_TUNER_MODE_MONO;
 229        v->signal = 0xffff * gemtek_pci_getsignal(card);
 230        return 0;
 231}
 232
 233static int vidioc_s_tuner(struct file *file, void *priv,
 234                                        struct v4l2_tuner *v)
 235{
 236        return v->index ? -EINVAL : 0;
 237}
 238
 239static int vidioc_s_frequency(struct file *file, void *priv,
 240                                        struct v4l2_frequency *f)
 241{
 242        struct gemtek_pci *card = video_drvdata(file);
 243
 244        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 245                return -EINVAL;
 246        if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
 247            f->frequency > GEMTEK_PCI_RANGE_HIGH)
 248                return -EINVAL;
 249        gemtek_pci_setfrequency(card, f->frequency);
 250        card->mute = false;
 251        return 0;
 252}
 253
 254static int vidioc_g_frequency(struct file *file, void *priv,
 255                                        struct v4l2_frequency *f)
 256{
 257        struct gemtek_pci *card = video_drvdata(file);
 258
 259        if (f->tuner != 0)
 260                return -EINVAL;
 261        f->type = V4L2_TUNER_RADIO;
 262        f->frequency = card->current_frequency;
 263        return 0;
 264}
 265
 266static int vidioc_queryctrl(struct file *file, void *priv,
 267                                        struct v4l2_queryctrl *qc)
 268{
 269        switch (qc->id) {
 270        case V4L2_CID_AUDIO_MUTE:
 271                return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
 272        case V4L2_CID_AUDIO_VOLUME:
 273                return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
 274        }
 275        return -EINVAL;
 276}
 277
 278static int vidioc_g_ctrl(struct file *file, void *priv,
 279                                        struct v4l2_control *ctrl)
 280{
 281        struct gemtek_pci *card = video_drvdata(file);
 282
 283        switch (ctrl->id) {
 284        case V4L2_CID_AUDIO_MUTE:
 285                ctrl->value = card->mute;
 286                return 0;
 287        case V4L2_CID_AUDIO_VOLUME:
 288                if (card->mute)
 289                        ctrl->value = 0;
 290                else
 291                        ctrl->value = 65535;
 292                return 0;
 293        }
 294        return -EINVAL;
 295}
 296
 297static int vidioc_s_ctrl(struct file *file, void *priv,
 298                                        struct v4l2_control *ctrl)
 299{
 300        struct gemtek_pci *card = video_drvdata(file);
 301
 302        switch (ctrl->id) {
 303        case V4L2_CID_AUDIO_MUTE:
 304                if (ctrl->value)
 305                        gemtek_pci_mute(card);
 306                else
 307                        gemtek_pci_unmute(card);
 308                return 0;
 309        case V4L2_CID_AUDIO_VOLUME:
 310                if (ctrl->value)
 311                        gemtek_pci_unmute(card);
 312                else
 313                        gemtek_pci_mute(card);
 314                return 0;
 315        }
 316        return -EINVAL;
 317}
 318
 319static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 320{
 321        *i = 0;
 322        return 0;
 323}
 324
 325static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 326{
 327        return i ? -EINVAL : 0;
 328}
 329
 330static int vidioc_g_audio(struct file *file, void *priv,
 331                                        struct v4l2_audio *a)
 332{
 333        a->index = 0;
 334        strlcpy(a->name, "Radio", sizeof(a->name));
 335        a->capability = V4L2_AUDCAP_STEREO;
 336        return 0;
 337}
 338
 339static int vidioc_s_audio(struct file *file, void *priv,
 340                                        struct v4l2_audio *a)
 341{
 342        return a->index ? -EINVAL : 0;
 343}
 344
 345enum {
 346        GEMTEK_PR103
 347};
 348
 349static char *card_names[] __devinitdata = {
 350        "GEMTEK_PR103"
 351};
 352
 353static struct pci_device_id gemtek_pci_id[] =
 354{
 355        { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
 356          PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
 357        { 0 }
 358};
 359
 360MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
 361
 362static const struct v4l2_file_operations gemtek_pci_fops = {
 363        .owner          = THIS_MODULE,
 364        .ioctl          = video_ioctl2,
 365};
 366
 367static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
 368        .vidioc_querycap    = vidioc_querycap,
 369        .vidioc_g_tuner     = vidioc_g_tuner,
 370        .vidioc_s_tuner     = vidioc_s_tuner,
 371        .vidioc_g_audio     = vidioc_g_audio,
 372        .vidioc_s_audio     = vidioc_s_audio,
 373        .vidioc_g_input     = vidioc_g_input,
 374        .vidioc_s_input     = vidioc_s_input,
 375        .vidioc_g_frequency = vidioc_g_frequency,
 376        .vidioc_s_frequency = vidioc_s_frequency,
 377        .vidioc_queryctrl   = vidioc_queryctrl,
 378        .vidioc_g_ctrl      = vidioc_g_ctrl,
 379        .vidioc_s_ctrl      = vidioc_s_ctrl,
 380};
 381
 382static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 383{
 384        struct gemtek_pci *card;
 385        struct v4l2_device *v4l2_dev;
 386        int res;
 387
 388        card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
 389        if (card == NULL) {
 390                dev_err(&pdev->dev, "out of memory\n");
 391                return -ENOMEM;
 392        }
 393
 394        v4l2_dev = &card->v4l2_dev;
 395        mutex_init(&card->lock);
 396        card->pdev = pdev;
 397
 398        strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
 399
 400        res = v4l2_device_register(&pdev->dev, v4l2_dev);
 401        if (res < 0) {
 402                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 403                kfree(card);
 404                return res;
 405        }
 406
 407        if (pci_enable_device(pdev))
 408                goto err_pci;
 409
 410        card->iobase = pci_resource_start(pdev, 0);
 411        card->length = pci_resource_len(pdev, 0);
 412
 413        if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
 414                v4l2_err(v4l2_dev, "i/o port already in use\n");
 415                goto err_pci;
 416        }
 417
 418        strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
 419        card->vdev.v4l2_dev = v4l2_dev;
 420        card->vdev.fops = &gemtek_pci_fops;
 421        card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
 422        card->vdev.release = video_device_release_empty;
 423        video_set_drvdata(&card->vdev, card);
 424
 425        if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
 426                goto err_video;
 427
 428        gemtek_pci_mute(card);
 429
 430        v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
 431                pdev->revision, card->iobase, card->iobase + card->length - 1);
 432
 433        return 0;
 434
 435err_video:
 436        release_region(card->iobase, card->length);
 437
 438err_pci:
 439        v4l2_device_unregister(v4l2_dev);
 440        kfree(card);
 441        return -ENODEV;
 442}
 443
 444static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
 445{
 446        struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
 447        struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
 448
 449        video_unregister_device(&card->vdev);
 450        v4l2_device_unregister(v4l2_dev);
 451
 452        release_region(card->iobase, card->length);
 453
 454        if (mx)
 455                gemtek_pci_mute(card);
 456
 457        kfree(card);
 458}
 459
 460static struct pci_driver gemtek_pci_driver = {
 461        .name           = "gemtek_pci",
 462        .id_table       = gemtek_pci_id,
 463        .probe          = gemtek_pci_probe,
 464        .remove         = __devexit_p(gemtek_pci_remove),
 465};
 466
 467static int __init gemtek_pci_init(void)
 468{
 469        return pci_register_driver(&gemtek_pci_driver);
 470}
 471
 472static void __exit gemtek_pci_exit(void)
 473{
 474        pci_unregister_driver(&gemtek_pci_driver);
 475}
 476
 477module_init(gemtek_pci_init);
 478module_exit(gemtek_pci_exit);
 479