root/drivers/media/radio/radio-isa.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. radio_isa_querycap
  2. radio_isa_g_tuner
  3. radio_isa_s_tuner
  4. radio_isa_s_frequency
  5. radio_isa_g_frequency
  6. radio_isa_s_ctrl
  7. radio_isa_log_status
  8. radio_isa_match
  9. radio_isa_valid_io
  10. radio_isa_alloc
  11. radio_isa_common_probe
  12. radio_isa_common_remove
  13. radio_isa_probe
  14. radio_isa_remove
  15. radio_isa_pnp_probe
  16. radio_isa_pnp_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Framework for ISA radio drivers.
   4  * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
   5  * to concentrate on the actual hardware operation.
   6  *
   7  * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
   8  */
   9 
  10 #include <linux/module.h>
  11 #include <linux/init.h>
  12 #include <linux/ioport.h>
  13 #include <linux/delay.h>
  14 #include <linux/videodev2.h>
  15 #include <linux/io.h>
  16 #include <linux/slab.h>
  17 #include <media/v4l2-device.h>
  18 #include <media/v4l2-ioctl.h>
  19 #include <media/v4l2-fh.h>
  20 #include <media/v4l2-ctrls.h>
  21 #include <media/v4l2-event.h>
  22 
  23 #include "radio-isa.h"
  24 
  25 MODULE_AUTHOR("Hans Verkuil");
  26 MODULE_DESCRIPTION("A framework for ISA radio drivers.");
  27 MODULE_LICENSE("GPL");
  28 
  29 #define FREQ_LOW  (87U * 16000U)
  30 #define FREQ_HIGH (108U * 16000U)
  31 
  32 static int radio_isa_querycap(struct file *file, void  *priv,
  33                                         struct v4l2_capability *v)
  34 {
  35         struct radio_isa_card *isa = video_drvdata(file);
  36 
  37         strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
  38         strscpy(v->card, isa->drv->card, sizeof(v->card));
  39         snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
  40         return 0;
  41 }
  42 
  43 static int radio_isa_g_tuner(struct file *file, void *priv,
  44                                 struct v4l2_tuner *v)
  45 {
  46         struct radio_isa_card *isa = video_drvdata(file);
  47         const struct radio_isa_ops *ops = isa->drv->ops;
  48 
  49         if (v->index > 0)
  50                 return -EINVAL;
  51 
  52         strscpy(v->name, "FM", sizeof(v->name));
  53         v->type = V4L2_TUNER_RADIO;
  54         v->rangelow = FREQ_LOW;
  55         v->rangehigh = FREQ_HIGH;
  56         v->capability = V4L2_TUNER_CAP_LOW;
  57         if (isa->drv->has_stereo)
  58                 v->capability |= V4L2_TUNER_CAP_STEREO;
  59 
  60         if (ops->g_rxsubchans)
  61                 v->rxsubchans = ops->g_rxsubchans(isa);
  62         else
  63                 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
  64         v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
  65         if (ops->g_signal)
  66                 v->signal = ops->g_signal(isa);
  67         else
  68                 v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ?
  69                                                                 0xffff : 0;
  70         return 0;
  71 }
  72 
  73 static int radio_isa_s_tuner(struct file *file, void *priv,
  74                                 const struct v4l2_tuner *v)
  75 {
  76         struct radio_isa_card *isa = video_drvdata(file);
  77         const struct radio_isa_ops *ops = isa->drv->ops;
  78 
  79         if (v->index)
  80                 return -EINVAL;
  81         if (ops->s_stereo) {
  82                 isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO);
  83                 return ops->s_stereo(isa, isa->stereo);
  84         }
  85         return 0;
  86 }
  87 
  88 static int radio_isa_s_frequency(struct file *file, void *priv,
  89                                 const struct v4l2_frequency *f)
  90 {
  91         struct radio_isa_card *isa = video_drvdata(file);
  92         u32 freq = f->frequency;
  93         int res;
  94 
  95         if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
  96                 return -EINVAL;
  97         freq = clamp(freq, FREQ_LOW, FREQ_HIGH);
  98         res = isa->drv->ops->s_frequency(isa, freq);
  99         if (res == 0)
 100                 isa->freq = freq;
 101         return res;
 102 }
 103 
 104 static int radio_isa_g_frequency(struct file *file, void *priv,
 105                                 struct v4l2_frequency *f)
 106 {
 107         struct radio_isa_card *isa = video_drvdata(file);
 108 
 109         if (f->tuner != 0)
 110                 return -EINVAL;
 111         f->type = V4L2_TUNER_RADIO;
 112         f->frequency = isa->freq;
 113         return 0;
 114 }
 115 
 116 static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl)
 117 {
 118         struct radio_isa_card *isa =
 119                 container_of(ctrl->handler, struct radio_isa_card, hdl);
 120 
 121         switch (ctrl->id) {
 122         case V4L2_CID_AUDIO_MUTE:
 123                 return isa->drv->ops->s_mute_volume(isa, ctrl->val,
 124                                 isa->volume ? isa->volume->val : 0);
 125         }
 126         return -EINVAL;
 127 }
 128 
 129 static int radio_isa_log_status(struct file *file, void *priv)
 130 {
 131         struct radio_isa_card *isa = video_drvdata(file);
 132 
 133         v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io);
 134         v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name);
 135         return 0;
 136 }
 137 
 138 static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
 139         .s_ctrl = radio_isa_s_ctrl,
 140 };
 141 
 142 static const struct v4l2_file_operations radio_isa_fops = {
 143         .owner          = THIS_MODULE,
 144         .open           = v4l2_fh_open,
 145         .release        = v4l2_fh_release,
 146         .poll           = v4l2_ctrl_poll,
 147         .unlocked_ioctl = video_ioctl2,
 148 };
 149 
 150 static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = {
 151         .vidioc_querycap    = radio_isa_querycap,
 152         .vidioc_g_tuner     = radio_isa_g_tuner,
 153         .vidioc_s_tuner     = radio_isa_s_tuner,
 154         .vidioc_g_frequency = radio_isa_g_frequency,
 155         .vidioc_s_frequency = radio_isa_s_frequency,
 156         .vidioc_log_status  = radio_isa_log_status,
 157         .vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
 158         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 159 };
 160 
 161 int radio_isa_match(struct device *pdev, unsigned int dev)
 162 {
 163         struct radio_isa_driver *drv = pdev->platform_data;
 164 
 165         return drv->probe || drv->io_params[dev] >= 0;
 166 }
 167 EXPORT_SYMBOL_GPL(radio_isa_match);
 168 
 169 static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io)
 170 {
 171         int i;
 172 
 173         for (i = 0; i < drv->num_of_io_ports; i++)
 174                 if (drv->io_ports[i] == io)
 175                         return true;
 176         return false;
 177 }
 178 
 179 static struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv,
 180                                 struct device *pdev)
 181 {
 182         struct v4l2_device *v4l2_dev;
 183         struct radio_isa_card *isa = drv->ops->alloc();
 184         if (!isa)
 185                 return NULL;
 186 
 187         dev_set_drvdata(pdev, isa);
 188         isa->drv = drv;
 189         v4l2_dev = &isa->v4l2_dev;
 190         strscpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
 191 
 192         return isa;
 193 }
 194 
 195 static int radio_isa_common_probe(struct radio_isa_card *isa,
 196                                   struct device *pdev,
 197                                   int radio_nr, unsigned region_size)
 198 {
 199         const struct radio_isa_driver *drv = isa->drv;
 200         const struct radio_isa_ops *ops = drv->ops;
 201         struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
 202         int res;
 203 
 204         if (!request_region(isa->io, region_size, v4l2_dev->name)) {
 205                 v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
 206                 kfree(isa);
 207                 return -EBUSY;
 208         }
 209 
 210         res = v4l2_device_register(pdev, v4l2_dev);
 211         if (res < 0) {
 212                 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
 213                 goto err_dev_reg;
 214         }
 215 
 216         v4l2_ctrl_handler_init(&isa->hdl, 1);
 217         isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
 218                                 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 219         if (drv->max_volume)
 220                 isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
 221                         V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1,
 222                         drv->max_volume);
 223         v4l2_dev->ctrl_handler = &isa->hdl;
 224         if (isa->hdl.error) {
 225                 res = isa->hdl.error;
 226                 v4l2_err(v4l2_dev, "Could not register controls\n");
 227                 goto err_hdl;
 228         }
 229         if (drv->max_volume)
 230                 v4l2_ctrl_cluster(2, &isa->mute);
 231         v4l2_dev->ctrl_handler = &isa->hdl;
 232 
 233         mutex_init(&isa->lock);
 234         isa->vdev.lock = &isa->lock;
 235         strscpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
 236         isa->vdev.v4l2_dev = v4l2_dev;
 237         isa->vdev.fops = &radio_isa_fops;
 238         isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
 239         isa->vdev.release = video_device_release_empty;
 240         isa->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 241         video_set_drvdata(&isa->vdev, isa);
 242         isa->freq = FREQ_LOW;
 243         isa->stereo = drv->has_stereo;
 244 
 245         if (ops->init)
 246                 res = ops->init(isa);
 247         if (!res)
 248                 res = v4l2_ctrl_handler_setup(&isa->hdl);
 249         if (!res)
 250                 res = ops->s_frequency(isa, isa->freq);
 251         if (!res && ops->s_stereo)
 252                 res = ops->s_stereo(isa, isa->stereo);
 253         if (res < 0) {
 254                 v4l2_err(v4l2_dev, "Could not setup card\n");
 255                 goto err_hdl;
 256         }
 257         res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, radio_nr);
 258 
 259         if (res < 0) {
 260                 v4l2_err(v4l2_dev, "Could not register device node\n");
 261                 goto err_hdl;
 262         }
 263 
 264         v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
 265                         drv->card, isa->io);
 266         return 0;
 267 
 268 err_hdl:
 269         v4l2_ctrl_handler_free(&isa->hdl);
 270 err_dev_reg:
 271         release_region(isa->io, region_size);
 272         kfree(isa);
 273         return res;
 274 }
 275 
 276 static int radio_isa_common_remove(struct radio_isa_card *isa,
 277                                    unsigned region_size)
 278 {
 279         const struct radio_isa_ops *ops = isa->drv->ops;
 280 
 281         ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
 282         video_unregister_device(&isa->vdev);
 283         v4l2_ctrl_handler_free(&isa->hdl);
 284         v4l2_device_unregister(&isa->v4l2_dev);
 285         release_region(isa->io, region_size);
 286         v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
 287         kfree(isa);
 288         return 0;
 289 }
 290 
 291 int radio_isa_probe(struct device *pdev, unsigned int dev)
 292 {
 293         struct radio_isa_driver *drv = pdev->platform_data;
 294         const struct radio_isa_ops *ops = drv->ops;
 295         struct v4l2_device *v4l2_dev;
 296         struct radio_isa_card *isa;
 297 
 298         isa = radio_isa_alloc(drv, pdev);
 299         if (!isa)
 300                 return -ENOMEM;
 301         isa->io = drv->io_params[dev];
 302         v4l2_dev = &isa->v4l2_dev;
 303 
 304         if (drv->probe && ops->probe) {
 305                 int i;
 306 
 307                 for (i = 0; i < drv->num_of_io_ports; ++i) {
 308                         int io = drv->io_ports[i];
 309 
 310                         if (request_region(io, drv->region_size, v4l2_dev->name)) {
 311                                 bool found = ops->probe(isa, io);
 312 
 313                                 release_region(io, drv->region_size);
 314                                 if (found) {
 315                                         isa->io = io;
 316                                         break;
 317                                 }
 318                         }
 319                 }
 320         }
 321 
 322         if (!radio_isa_valid_io(drv, isa->io)) {
 323                 int i;
 324 
 325                 if (isa->io < 0)
 326                         return -ENODEV;
 327                 v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
 328                                 drv->io_ports[0]);
 329                 for (i = 1; i < drv->num_of_io_ports; i++)
 330                         printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
 331                 printk(KERN_CONT ".\n");
 332                 kfree(isa);
 333                 return -EINVAL;
 334         }
 335 
 336         return radio_isa_common_probe(isa, pdev, drv->radio_nr_params[dev],
 337                                         drv->region_size);
 338 }
 339 EXPORT_SYMBOL_GPL(radio_isa_probe);
 340 
 341 int radio_isa_remove(struct device *pdev, unsigned int dev)
 342 {
 343         struct radio_isa_card *isa = dev_get_drvdata(pdev);
 344 
 345         return radio_isa_common_remove(isa, isa->drv->region_size);
 346 }
 347 EXPORT_SYMBOL_GPL(radio_isa_remove);
 348 
 349 #ifdef CONFIG_PNP
 350 int radio_isa_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 351 {
 352         struct pnp_driver *pnp_drv = to_pnp_driver(dev->dev.driver);
 353         struct radio_isa_driver *drv = container_of(pnp_drv,
 354                                         struct radio_isa_driver, pnp_driver);
 355         struct radio_isa_card *isa;
 356 
 357         if (!pnp_port_valid(dev, 0))
 358                 return -ENODEV;
 359 
 360         isa = radio_isa_alloc(drv, &dev->dev);
 361         if (!isa)
 362                 return -ENOMEM;
 363 
 364         isa->io = pnp_port_start(dev, 0);
 365 
 366         return radio_isa_common_probe(isa, &dev->dev, drv->radio_nr_params[0],
 367                                         pnp_port_len(dev, 0));
 368 }
 369 EXPORT_SYMBOL_GPL(radio_isa_pnp_probe);
 370 
 371 void radio_isa_pnp_remove(struct pnp_dev *dev)
 372 {
 373         struct radio_isa_card *isa = dev_get_drvdata(&dev->dev);
 374 
 375         radio_isa_common_remove(isa, pnp_port_len(dev, 0));
 376 }
 377 EXPORT_SYMBOL_GPL(radio_isa_pnp_remove);
 378 #endif

/* [<][>][^][v][top][bottom][index][help] */