📄 radio-gemtek.c
字号:
return 1;}/* * Automatic probing for card. */static int gemtek_probe(void){ int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; int i; if (!probe) { printk(KERN_INFO "Automatic device probing disabled.\n"); return -1; } printk(KERN_INFO "Automatic device probing enabled.\n"); for (i = 0; i < ARRAY_SIZE(ioports); ++i) { printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]); if (!request_region(ioports[i], 1, "gemtek-probe")) { printk(KERN_WARNING "I/O port 0x%x busy!\n", ioports[i]); continue; } if (gemtek_verify(ioports[i])) { printk(KERN_INFO "Card found from I/O port " "0x%x!\n", ioports[i]); release_region(ioports[i], 1); io = ioports[i]; return io; } release_region(ioports[i], 1); } printk(KERN_ERR "Automatic probing failed!\n"); return -1;}/* * Video 4 Linux stuff. */static struct v4l2_queryctrl radio_qctrl[] = { { .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, .maximum = 1, .default_value = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, }, { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, .maximum = 65535, .step = 65535, .default_value = 0xff, .type = V4L2_CTRL_TYPE_INTEGER, }};static int gemtek_exclusive_open(struct inode *inode, struct file *file){ return test_and_set_bit(0, &in_use) ? -EBUSY : 0;}static int gemtek_exclusive_release(struct inode *inode, struct file *file){ clear_bit(0, &in_use); return 0;}static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = gemtek_exclusive_open, .release = gemtek_exclusive_release, .ioctl = video_ioctl2,#ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32,#endif .llseek = no_llseek};static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v){ strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); sprintf(v->bus_info, "ISA"); v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0;}static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v){ if (v->index > 0) return -EINVAL; strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; v->rangelow = GEMTEK_LOWFREQ; v->rangehigh = GEMTEK_HIGHFREQ; v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; v->signal = 0xffff * gemtek_getsigstr(); if (v->signal) { v->audmode = V4L2_TUNER_MODE_STEREO; v->rxsubchans = V4L2_TUNER_SUB_STEREO; } else { v->audmode = V4L2_TUNER_MODE_MONO; v->rxsubchans = V4L2_TUNER_SUB_MONO; } return 0;}static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v){ if (v->index > 0) return -EINVAL; return 0;}static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f){ struct gemtek_device *rt = video_drvdata(file); gemtek_setfreq(rt, f->frequency); return 0;}static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f){ struct gemtek_device *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->lastfreq; return 0;}static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc){ int i; for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) { if (qc->id && qc->id == radio_qctrl[i].id) { memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } return -EINVAL;}static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ struct gemtek_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = rt->muted; return 0; case V4L2_CID_AUDIO_VOLUME: if (rt->muted) ctrl->value = 0; else ctrl->value = 65535; return 0; } return -EINVAL;}static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl){ struct gemtek_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) gemtek_mute(rt); else gemtek_unmute(rt); return 0; case V4L2_CID_AUDIO_VOLUME: if (ctrl->value) gemtek_unmute(rt); else gemtek_mute(rt); return 0; } return -EINVAL;}static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a){ if (a->index > 1) return -EINVAL; strcpy(a->name, "Radio"); a->capability = V4L2_AUDCAP_STEREO; return 0;}static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i){ *i = 0; return 0;}static int vidioc_s_input(struct file *filp, void *priv, unsigned int i){ if (i != 0) return -EINVAL; return 0;}static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a){ if (a->index != 0) return -EINVAL; return 0;}static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl};static struct video_device gemtek_radio = { .name = "GemTek Radio card", .fops = &gemtek_fops, .ioctl_ops = &gemtek_ioctl_ops, .release = video_device_release_empty,};/* * Initialization / cleanup related stuff. *//* * Initilize card. */static int __init gemtek_init(void){ printk(KERN_INFO RADIO_BANNER "\n"); spin_lock_init(&lock); gemtek_probe(); if (io) { if (!request_region(io, 1, "gemtek")) { printk(KERN_ERR "I/O port 0x%x already in use.\n", io); return -EBUSY; } if (!gemtek_verify(io)) printk(KERN_WARNING "Card at I/O port 0x%x does not " "respond properly, check your " "configuration.\n", io); else printk(KERN_INFO "Using I/O port 0x%x.\n", io); } else if (probe) { printk(KERN_ERR "Automatic probing failed and no " "fixed I/O port defined.\n"); return -ENODEV; } else { printk(KERN_ERR "Automatic probing disabled but no fixed " "I/O port defined."); return -EINVAL; } video_set_drvdata(&gemtek_radio, &gemtek_unit); if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 1); return -EBUSY; } /* Set defaults */ gemtek_unit.lastfreq = GEMTEK_LOWFREQ; gemtek_unit.bu2614data = 0; if (initmute) gemtek_mute(&gemtek_unit); return 0;}/* * Module cleanup */static void __exit gemtek_exit(void){ if (shutdown) { hardmute = 1; /* Turn off PLL */ gemtek_mute(&gemtek_unit); } else { printk(KERN_INFO "Module unloaded but card not muted!\n"); } video_unregister_device(&gemtek_radio); release_region(io, 1);}module_init(gemtek_init);module_exit(gemtek_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -