11da177e4SLinus Torvalds /* radio-aztech.c - Aztech radio card driver for Linux 2.2 21da177e4SLinus Torvalds * 3a4366af4SMauro Carvalho Chehab * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 41da177e4SLinus Torvalds * Adapted to support the Video for Linux API by 51da177e4SLinus Torvalds * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by: 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Quay Ly 81da177e4SLinus Torvalds * Donald Song 91da177e4SLinus Torvalds * Jason Lewis (jlewis@twilight.vtc.vsc.edu) 101da177e4SLinus Torvalds * Scott McGrath (smcgrath@twilight.vtc.vsc.edu) 111da177e4SLinus Torvalds * William McGrath (wmcgrath@twilight.vtc.vsc.edu) 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ 141da177e4SLinus Torvalds * along with more information on the card itself. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * History: 171da177e4SLinus Torvalds * 1999-02-24 Russell Kroll <rkroll@exploits.org> 181da177e4SLinus Torvalds * Fine tuning/VIDEO_TUNER_LOW 191da177e4SLinus Torvalds * Range expanded to 87-108 MHz (from 87.9-107.8) 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * Notable changes from the original source: 221da177e4SLinus Torvalds * - includes stripped down to the essentials 231da177e4SLinus Torvalds * - for loops used as delays replaced with udelay() 241da177e4SLinus Torvalds * - #defines removed, changed to static values 251da177e4SLinus Torvalds * - tuning structure changed - no more character arrays, other changes 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> /* Modules */ 291da177e4SLinus Torvalds #include <linux/init.h> /* Initdata */ 30fb911ee8SPeter Osterlund #include <linux/ioport.h> /* request_region */ 311da177e4SLinus Torvalds #include <linux/delay.h> /* udelay */ 321da177e4SLinus Torvalds #include <asm/io.h> /* outb, outb_p */ 331da177e4SLinus Torvalds #include <asm/uaccess.h> /* copy to/from user */ 34a4366af4SMauro Carvalho Chehab #include <linux/videodev2.h> /* kernel radio structs */ 355e87efa3SMauro Carvalho Chehab #include <media/v4l2-common.h> 3635ea11ffSHans Verkuil #include <media/v4l2-ioctl.h> 371da177e4SLinus Torvalds 38a4366af4SMauro Carvalho Chehab #include <linux/version.h> /* for KERNEL_VERSION MACRO */ 39a4366af4SMauro Carvalho Chehab #define RADIO_VERSION KERNEL_VERSION(0,0,2) 40a4366af4SMauro Carvalho Chehab 41a4366af4SMauro Carvalho Chehab static struct v4l2_queryctrl radio_qctrl[] = { 42a4366af4SMauro Carvalho Chehab { 43a4366af4SMauro Carvalho Chehab .id = V4L2_CID_AUDIO_MUTE, 44a4366af4SMauro Carvalho Chehab .name = "Mute", 45a4366af4SMauro Carvalho Chehab .minimum = 0, 46a4366af4SMauro Carvalho Chehab .maximum = 1, 47a4366af4SMauro Carvalho Chehab .default_value = 1, 48a4366af4SMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_BOOLEAN, 49a4366af4SMauro Carvalho Chehab },{ 50a4366af4SMauro Carvalho Chehab .id = V4L2_CID_AUDIO_VOLUME, 51a4366af4SMauro Carvalho Chehab .name = "Volume", 52a4366af4SMauro Carvalho Chehab .minimum = 0, 53a4366af4SMauro Carvalho Chehab .maximum = 0xff, 54a4366af4SMauro Carvalho Chehab .step = 1, 55a4366af4SMauro Carvalho Chehab .default_value = 0xff, 56a4366af4SMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_INTEGER, 57a4366af4SMauro Carvalho Chehab } 58a4366af4SMauro Carvalho Chehab }; 59a4366af4SMauro Carvalho Chehab 601da177e4SLinus Torvalds /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds #ifndef CONFIG_RADIO_AZTECH_PORT 631da177e4SLinus Torvalds #define CONFIG_RADIO_AZTECH_PORT -1 641da177e4SLinus Torvalds #endif 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds static int io = CONFIG_RADIO_AZTECH_PORT; 671da177e4SLinus Torvalds static int radio_nr = -1; 681da177e4SLinus Torvalds static int radio_wait_time = 1000; 693593cab5SIngo Molnar static struct mutex lock; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds struct az_device 721da177e4SLinus Torvalds { 733ca685aaSHans Verkuil unsigned long in_use; 741da177e4SLinus Torvalds int curvol; 751da177e4SLinus Torvalds unsigned long curfreq; 761da177e4SLinus Torvalds int stereo; 771da177e4SLinus Torvalds }; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static int volconvert(int level) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds level>>=14; /* Map 16bits down to 2 bit */ 821da177e4SLinus Torvalds level&=3; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* convert to card-friendly values */ 851da177e4SLinus Torvalds switch (level) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds case 0: 881da177e4SLinus Torvalds return 0; 891da177e4SLinus Torvalds case 1: 901da177e4SLinus Torvalds return 1; 911da177e4SLinus Torvalds case 2: 921da177e4SLinus Torvalds return 4; 931da177e4SLinus Torvalds case 3: 941da177e4SLinus Torvalds return 5; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds return 0; /* Quieten gcc */ 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds static void send_0_byte (struct az_device *dev) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds udelay(radio_wait_time); 1021da177e4SLinus Torvalds outb_p(2+volconvert(dev->curvol), io); 1031da177e4SLinus Torvalds outb_p(64+2+volconvert(dev->curvol), io); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds static void send_1_byte (struct az_device *dev) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds udelay (radio_wait_time); 1091da177e4SLinus Torvalds outb_p(128+2+volconvert(dev->curvol), io); 1101da177e4SLinus Torvalds outb_p(128+64+2+volconvert(dev->curvol), io); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static int az_setvol(struct az_device *dev, int vol) 1141da177e4SLinus Torvalds { 1153593cab5SIngo Molnar mutex_lock(&lock); 1161da177e4SLinus Torvalds outb (volconvert(vol), io); 1173593cab5SIngo Molnar mutex_unlock(&lock); 1181da177e4SLinus Torvalds return 0; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* thanks to Michael Dwyer for giving me a dose of clues in 1221da177e4SLinus Torvalds * the signal strength department.. 1231da177e4SLinus Torvalds * 1241da177e4SLinus Torvalds * This card has a stereo bit - bit 0 set = mono, not set = stereo 1251da177e4SLinus Torvalds * It also has a "signal" bit - bit 1 set = bad signal, not set = good 1261da177e4SLinus Torvalds * 1271da177e4SLinus Torvalds */ 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds static int az_getsigstr(struct az_device *dev) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds if (inb(io) & 2) /* bit set = no signal present */ 1321da177e4SLinus Torvalds return 0; 1331da177e4SLinus Torvalds return 1; /* signal present */ 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds static int az_getstereo(struct az_device *dev) 1371da177e4SLinus Torvalds { 1381da177e4SLinus Torvalds if (inb(io) & 1) /* bit set = mono */ 1391da177e4SLinus Torvalds return 0; 1401da177e4SLinus Torvalds return 1; /* stereo */ 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds static int az_setfreq(struct az_device *dev, unsigned long frequency) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds int i; 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds frequency += 171200; /* Add 10.7 MHz IF */ 1481da177e4SLinus Torvalds frequency /= 800; /* Convert to 50 kHz units */ 1491da177e4SLinus Torvalds 1503593cab5SIngo Molnar mutex_lock(&lock); 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds send_0_byte (dev); /* 0: LSB of frequency */ 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ 1551da177e4SLinus Torvalds if (frequency & (1 << i)) 1561da177e4SLinus Torvalds send_1_byte (dev); 1571da177e4SLinus Torvalds else 1581da177e4SLinus Torvalds send_0_byte (dev); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds send_0_byte (dev); /* 14: test bit - always 0 */ 1611da177e4SLinus Torvalds send_0_byte (dev); /* 15: test bit - always 0 */ 1621da177e4SLinus Torvalds send_0_byte (dev); /* 16: band data 0 - always 0 */ 1631da177e4SLinus Torvalds if (dev->stereo) /* 17: stereo (1 to enable) */ 1641da177e4SLinus Torvalds send_1_byte (dev); 1651da177e4SLinus Torvalds else 1661da177e4SLinus Torvalds send_0_byte (dev); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds send_1_byte (dev); /* 18: band data 1 - unknown */ 1691da177e4SLinus Torvalds send_0_byte (dev); /* 19: time base - always 0 */ 1701da177e4SLinus Torvalds send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */ 1711da177e4SLinus Torvalds send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */ 1721da177e4SLinus Torvalds send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */ 1731da177e4SLinus Torvalds send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */ 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* latch frequency */ 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds udelay (radio_wait_time); 1781da177e4SLinus Torvalds outb_p(128+64+volconvert(dev->curvol), io); 1791da177e4SLinus Torvalds 1803593cab5SIngo Molnar mutex_unlock(&lock); 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds return 0; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 18599218fe4SMauro Carvalho Chehab static int vidioc_querycap (struct file *file, void *priv, 18699218fe4SMauro Carvalho Chehab struct v4l2_capability *v) 1871da177e4SLinus Torvalds { 188a4366af4SMauro Carvalho Chehab strlcpy(v->driver, "radio-aztech", sizeof (v->driver)); 189a4366af4SMauro Carvalho Chehab strlcpy(v->card, "Aztech Radio", sizeof (v->card)); 190a4366af4SMauro Carvalho Chehab sprintf(v->bus_info,"ISA"); 191a4366af4SMauro Carvalho Chehab v->version = RADIO_VERSION; 192a4366af4SMauro Carvalho Chehab v->capabilities = V4L2_CAP_TUNER; 1931da177e4SLinus Torvalds return 0; 1941da177e4SLinus Torvalds } 19599218fe4SMauro Carvalho Chehab 19699218fe4SMauro Carvalho Chehab static int vidioc_g_tuner (struct file *file, void *priv, 19799218fe4SMauro Carvalho Chehab struct v4l2_tuner *v) 1981da177e4SLinus Torvalds { 19999218fe4SMauro Carvalho Chehab struct video_device *dev = video_devdata(file); 20099218fe4SMauro Carvalho Chehab struct az_device *az = dev->priv; 201a4366af4SMauro Carvalho Chehab 202a4366af4SMauro Carvalho Chehab if (v->index > 0) 2031da177e4SLinus Torvalds return -EINVAL; 204a4366af4SMauro Carvalho Chehab 205a4366af4SMauro Carvalho Chehab strcpy(v->name, "FM"); 206a4366af4SMauro Carvalho Chehab v->type = V4L2_TUNER_RADIO; 207a4366af4SMauro Carvalho Chehab 2081da177e4SLinus Torvalds v->rangelow=(87*16000); 2091da177e4SLinus Torvalds v->rangehigh=(108*16000); 210a4366af4SMauro Carvalho Chehab v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; 211a4366af4SMauro Carvalho Chehab v->capability=V4L2_TUNER_CAP_LOW; 2121da177e4SLinus Torvalds if(az_getstereo(az)) 213a4366af4SMauro Carvalho Chehab v->audmode = V4L2_TUNER_MODE_STEREO; 214a4366af4SMauro Carvalho Chehab else 215a4366af4SMauro Carvalho Chehab v->audmode = V4L2_TUNER_MODE_MONO; 216a4366af4SMauro Carvalho Chehab v->signal=0xFFFF*az_getsigstr(az); 217a4366af4SMauro Carvalho Chehab 2181da177e4SLinus Torvalds return 0; 2191da177e4SLinus Torvalds } 220a4366af4SMauro Carvalho Chehab 22199218fe4SMauro Carvalho Chehab 22299218fe4SMauro Carvalho Chehab static int vidioc_s_tuner (struct file *file, void *priv, 22399218fe4SMauro Carvalho Chehab struct v4l2_tuner *v) 22499218fe4SMauro Carvalho Chehab { 225a4366af4SMauro Carvalho Chehab if (v->index > 0) 2261da177e4SLinus Torvalds return -EINVAL; 227a4366af4SMauro Carvalho Chehab 2281da177e4SLinus Torvalds return 0; 2291da177e4SLinus Torvalds } 23099218fe4SMauro Carvalho Chehab 231676b0ac7SMauro Carvalho Chehab static int vidioc_g_audio (struct file *file, void *priv, 232676b0ac7SMauro Carvalho Chehab struct v4l2_audio *a) 233676b0ac7SMauro Carvalho Chehab { 234676b0ac7SMauro Carvalho Chehab if (a->index > 1) 235676b0ac7SMauro Carvalho Chehab return -EINVAL; 236676b0ac7SMauro Carvalho Chehab 237676b0ac7SMauro Carvalho Chehab strcpy(a->name, "Radio"); 238676b0ac7SMauro Carvalho Chehab a->capability = V4L2_AUDCAP_STEREO; 239676b0ac7SMauro Carvalho Chehab return 0; 240676b0ac7SMauro Carvalho Chehab } 241676b0ac7SMauro Carvalho Chehab 242a0c05ab9SMauro Carvalho Chehab static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 243a0c05ab9SMauro Carvalho Chehab { 244a0c05ab9SMauro Carvalho Chehab *i = 0; 245a0c05ab9SMauro Carvalho Chehab return 0; 246a0c05ab9SMauro Carvalho Chehab } 247a0c05ab9SMauro Carvalho Chehab 248a0c05ab9SMauro Carvalho Chehab static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 249a0c05ab9SMauro Carvalho Chehab { 250a0c05ab9SMauro Carvalho Chehab if (i != 0) 251a0c05ab9SMauro Carvalho Chehab return -EINVAL; 252a0c05ab9SMauro Carvalho Chehab return 0; 253a0c05ab9SMauro Carvalho Chehab } 254a0c05ab9SMauro Carvalho Chehab 255a0c05ab9SMauro Carvalho Chehab 256676b0ac7SMauro Carvalho Chehab static int vidioc_s_audio (struct file *file, void *priv, 257676b0ac7SMauro Carvalho Chehab struct v4l2_audio *a) 258676b0ac7SMauro Carvalho Chehab { 259676b0ac7SMauro Carvalho Chehab if (a->index != 0) 260676b0ac7SMauro Carvalho Chehab return -EINVAL; 261676b0ac7SMauro Carvalho Chehab 262676b0ac7SMauro Carvalho Chehab return 0; 263676b0ac7SMauro Carvalho Chehab } 264676b0ac7SMauro Carvalho Chehab 26599218fe4SMauro Carvalho Chehab static int vidioc_s_frequency (struct file *file, void *priv, 26699218fe4SMauro Carvalho Chehab struct v4l2_frequency *f) 2671da177e4SLinus Torvalds { 26899218fe4SMauro Carvalho Chehab struct video_device *dev = video_devdata(file); 26999218fe4SMauro Carvalho Chehab struct az_device *az = dev->priv; 270a4366af4SMauro Carvalho Chehab 271a4366af4SMauro Carvalho Chehab az->curfreq = f->frequency; 2721da177e4SLinus Torvalds az_setfreq(az, az->curfreq); 2731da177e4SLinus Torvalds return 0; 2741da177e4SLinus Torvalds } 27599218fe4SMauro Carvalho Chehab 27699218fe4SMauro Carvalho Chehab static int vidioc_g_frequency (struct file *file, void *priv, 27799218fe4SMauro Carvalho Chehab struct v4l2_frequency *f) 2781da177e4SLinus Torvalds { 27999218fe4SMauro Carvalho Chehab struct video_device *dev = video_devdata(file); 28099218fe4SMauro Carvalho Chehab struct az_device *az = dev->priv; 2811da177e4SLinus Torvalds 282a4366af4SMauro Carvalho Chehab f->type = V4L2_TUNER_RADIO; 283a4366af4SMauro Carvalho Chehab f->frequency = az->curfreq; 284a4366af4SMauro Carvalho Chehab 2851da177e4SLinus Torvalds return 0; 2861da177e4SLinus Torvalds } 287a4366af4SMauro Carvalho Chehab 28899218fe4SMauro Carvalho Chehab static int vidioc_queryctrl (struct file *file, void *priv, 28999218fe4SMauro Carvalho Chehab struct v4l2_queryctrl *qc) 290a4366af4SMauro Carvalho Chehab { 291a4366af4SMauro Carvalho Chehab int i; 292a4366af4SMauro Carvalho Chehab 293a4366af4SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 294a4366af4SMauro Carvalho Chehab if (qc->id && qc->id == radio_qctrl[i].id) { 295a4366af4SMauro Carvalho Chehab memcpy(qc, &(radio_qctrl[i]), 296a4366af4SMauro Carvalho Chehab sizeof(*qc)); 297a4366af4SMauro Carvalho Chehab return (0); 298a4366af4SMauro Carvalho Chehab } 299a4366af4SMauro Carvalho Chehab } 300a4366af4SMauro Carvalho Chehab return -EINVAL; 301a4366af4SMauro Carvalho Chehab } 30299218fe4SMauro Carvalho Chehab 30399218fe4SMauro Carvalho Chehab static int vidioc_g_ctrl (struct file *file, void *priv, 30499218fe4SMauro Carvalho Chehab struct v4l2_control *ctrl) 305a4366af4SMauro Carvalho Chehab { 30699218fe4SMauro Carvalho Chehab struct video_device *dev = video_devdata(file); 30799218fe4SMauro Carvalho Chehab struct az_device *az = dev->priv; 308a4366af4SMauro Carvalho Chehab 309a4366af4SMauro Carvalho Chehab switch (ctrl->id) { 310a4366af4SMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 311a4366af4SMauro Carvalho Chehab if (az->curvol==0) 312a4366af4SMauro Carvalho Chehab ctrl->value=1; 313a4366af4SMauro Carvalho Chehab else 314a4366af4SMauro Carvalho Chehab ctrl->value=0; 315a4366af4SMauro Carvalho Chehab return (0); 316a4366af4SMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME: 317a4366af4SMauro Carvalho Chehab ctrl->value=az->curvol * 6554; 318a4366af4SMauro Carvalho Chehab return (0); 319a4366af4SMauro Carvalho Chehab } 320a4366af4SMauro Carvalho Chehab return -EINVAL; 321a4366af4SMauro Carvalho Chehab } 32299218fe4SMauro Carvalho Chehab 32399218fe4SMauro Carvalho Chehab static int vidioc_s_ctrl (struct file *file, void *priv, 32499218fe4SMauro Carvalho Chehab struct v4l2_control *ctrl) 325a4366af4SMauro Carvalho Chehab { 32699218fe4SMauro Carvalho Chehab struct video_device *dev = video_devdata(file); 32799218fe4SMauro Carvalho Chehab struct az_device *az = dev->priv; 328a4366af4SMauro Carvalho Chehab 329a4366af4SMauro Carvalho Chehab switch (ctrl->id) { 330a4366af4SMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 331a4366af4SMauro Carvalho Chehab if (ctrl->value) { 332a4366af4SMauro Carvalho Chehab az_setvol(az,0); 333a4366af4SMauro Carvalho Chehab } else { 334a4366af4SMauro Carvalho Chehab az_setvol(az,az->curvol); 335a4366af4SMauro Carvalho Chehab } 336a4366af4SMauro Carvalho Chehab return (0); 337a4366af4SMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME: 338a4366af4SMauro Carvalho Chehab az_setvol(az,ctrl->value); 339a4366af4SMauro Carvalho Chehab return (0); 340a4366af4SMauro Carvalho Chehab } 341a4366af4SMauro Carvalho Chehab return -EINVAL; 342a4366af4SMauro Carvalho Chehab } 343a4366af4SMauro Carvalho Chehab 3441da177e4SLinus Torvalds static struct az_device aztech_unit; 3451da177e4SLinus Torvalds 3463ca685aaSHans Verkuil static int aztech_exclusive_open(struct inode *inode, struct file *file) 3473ca685aaSHans Verkuil { 3483ca685aaSHans Verkuil return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0; 3493ca685aaSHans Verkuil } 3503ca685aaSHans Verkuil 3513ca685aaSHans Verkuil static int aztech_exclusive_release(struct inode *inode, struct file *file) 3523ca685aaSHans Verkuil { 3533ca685aaSHans Verkuil clear_bit(0, &aztech_unit.in_use); 3543ca685aaSHans Verkuil return 0; 3553ca685aaSHans Verkuil } 3563ca685aaSHans Verkuil 357fa027c2aSArjan van de Ven static const struct file_operations aztech_fops = { 3581da177e4SLinus Torvalds .owner = THIS_MODULE, 3593ca685aaSHans Verkuil .open = aztech_exclusive_open, 3603ca685aaSHans Verkuil .release = aztech_exclusive_release, 36199218fe4SMauro Carvalho Chehab .ioctl = video_ioctl2, 362078ff795SDouglas Schilling Landgraf #ifdef CONFIG_COMPAT 3630d0fbf81SArnd Bergmann .compat_ioctl = v4l_compat_ioctl32, 364078ff795SDouglas Schilling Landgraf #endif 3651da177e4SLinus Torvalds .llseek = no_llseek, 3661da177e4SLinus Torvalds }; 3671da177e4SLinus Torvalds 368a399810cSHans Verkuil static const struct v4l2_ioctl_ops aztech_ioctl_ops = { 36999218fe4SMauro Carvalho Chehab .vidioc_querycap = vidioc_querycap, 37099218fe4SMauro Carvalho Chehab .vidioc_g_tuner = vidioc_g_tuner, 37199218fe4SMauro Carvalho Chehab .vidioc_s_tuner = vidioc_s_tuner, 372676b0ac7SMauro Carvalho Chehab .vidioc_g_audio = vidioc_g_audio, 373676b0ac7SMauro Carvalho Chehab .vidioc_s_audio = vidioc_s_audio, 374a0c05ab9SMauro Carvalho Chehab .vidioc_g_input = vidioc_g_input, 375a0c05ab9SMauro Carvalho Chehab .vidioc_s_input = vidioc_s_input, 37699218fe4SMauro Carvalho Chehab .vidioc_g_frequency = vidioc_g_frequency, 37799218fe4SMauro Carvalho Chehab .vidioc_s_frequency = vidioc_s_frequency, 37899218fe4SMauro Carvalho Chehab .vidioc_queryctrl = vidioc_queryctrl, 37999218fe4SMauro Carvalho Chehab .vidioc_g_ctrl = vidioc_g_ctrl, 38099218fe4SMauro Carvalho Chehab .vidioc_s_ctrl = vidioc_s_ctrl, 3811da177e4SLinus Torvalds }; 3821da177e4SLinus Torvalds 383a399810cSHans Verkuil static struct video_device aztech_radio = { 384a399810cSHans Verkuil .name = "Aztech radio", 385a399810cSHans Verkuil .fops = &aztech_fops, 386a399810cSHans Verkuil .ioctl_ops = &aztech_ioctl_ops, 387a399810cSHans Verkuil }; 388a399810cSHans Verkuil 38999218fe4SMauro Carvalho Chehab module_param_named(debug,aztech_radio.debug, int, 0644); 39099218fe4SMauro Carvalho Chehab MODULE_PARM_DESC(debug,"activates debug info"); 39199218fe4SMauro Carvalho Chehab 3921da177e4SLinus Torvalds static int __init aztech_init(void) 3931da177e4SLinus Torvalds { 3941da177e4SLinus Torvalds if(io==-1) 3951da177e4SLinus Torvalds { 3961da177e4SLinus Torvalds printk(KERN_ERR "You must set an I/O address with io=0x???\n"); 3971da177e4SLinus Torvalds return -EINVAL; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds if (!request_region(io, 2, "aztech")) 4011da177e4SLinus Torvalds { 4021da177e4SLinus Torvalds printk(KERN_ERR "aztech: port 0x%x already in use\n", io); 4031da177e4SLinus Torvalds return -EBUSY; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4063593cab5SIngo Molnar mutex_init(&lock); 4071da177e4SLinus Torvalds aztech_radio.priv=&aztech_unit; 4081da177e4SLinus Torvalds 409cba99ae8SHans Verkuil if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) { 4101da177e4SLinus Torvalds release_region(io,2); 4111da177e4SLinus Torvalds return -EINVAL; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); 4151da177e4SLinus Torvalds /* mute card - prevents noisy bootups */ 4161da177e4SLinus Torvalds outb (0, io); 4171da177e4SLinus Torvalds return 0; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); 4211da177e4SLinus Torvalds MODULE_DESCRIPTION("A driver for the Aztech radio card."); 4221da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds module_param(io, int, 0); 4251da177e4SLinus Torvalds module_param(radio_nr, int, 0); 4261da177e4SLinus Torvalds MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds static void __exit aztech_cleanup(void) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds video_unregister_device(&aztech_radio); 4311da177e4SLinus Torvalds release_region(io,2); 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds module_init(aztech_init); 4351da177e4SLinus Torvalds module_exit(aztech_cleanup); 436