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