11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux 31da177e4SLinus Torvalds * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net> 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Based in the radio Maestro PCI driver. Actually it uses the same chip 61da177e4SLinus Torvalds * for radio but different pci controller. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * I didn't have any specs I reversed engineered the protocol from 91da177e4SLinus Torvalds * the windows driver (radio.dll). 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * The card uses the TEA5757 chip that includes a search function but it 121da177e4SLinus Torvalds * is useless as I haven't found any way to read back the frequency. If 131da177e4SLinus Torvalds * anybody does please mail me. 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * For the pdf file see: 161da177e4SLinus Torvalds * http://www.semiconductors.philips.com/pip/TEA5757H/V1 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * CHANGES: 201da177e4SLinus Torvalds * 0.75b 211da177e4SLinus Torvalds * - better pci interface thanks to Francois Romieu <romieu@cogenit.fr> 221da177e4SLinus Torvalds * 23*e84fef6bSMauro Carvalho Chehab * 0.75 Sun Feb 4 22:51:27 EET 2001 241da177e4SLinus Torvalds * - tiding up 251da177e4SLinus Torvalds * - removed support for multiple devices as it didn't work anyway 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * BUGS: 281da177e4SLinus Torvalds * - card unmutes if you change frequency 291da177e4SLinus Torvalds * 30*e84fef6bSMauro Carvalho Chehab * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #include <linux/module.h> 351da177e4SLinus Torvalds #include <linux/init.h> 361da177e4SLinus Torvalds #include <linux/ioport.h> 371da177e4SLinus Torvalds #include <linux/delay.h> 381da177e4SLinus Torvalds #include <linux/sched.h> 391da177e4SLinus Torvalds #include <asm/io.h> 401da177e4SLinus Torvalds #include <asm/uaccess.h> 413593cab5SIngo Molnar #include <linux/mutex.h> 423593cab5SIngo Molnar 431da177e4SLinus Torvalds #include <linux/pci.h> 44*e84fef6bSMauro Carvalho Chehab #include <linux/videodev2.h> 455e87efa3SMauro Carvalho Chehab #include <media/v4l2-common.h> 461da177e4SLinus Torvalds 47*e84fef6bSMauro Carvalho Chehab #define DRIVER_VERSION "0.76" 48*e84fef6bSMauro Carvalho Chehab 49*e84fef6bSMauro Carvalho Chehab #include <linux/version.h> /* for KERNEL_VERSION MACRO */ 50*e84fef6bSMauro Carvalho Chehab #define RADIO_VERSION KERNEL_VERSION(0,7,6) 51*e84fef6bSMauro Carvalho Chehab 52*e84fef6bSMauro Carvalho Chehab static struct v4l2_queryctrl radio_qctrl[] = { 53*e84fef6bSMauro Carvalho Chehab { 54*e84fef6bSMauro Carvalho Chehab .id = V4L2_CID_AUDIO_MUTE, 55*e84fef6bSMauro Carvalho Chehab .name = "Mute", 56*e84fef6bSMauro Carvalho Chehab .minimum = 0, 57*e84fef6bSMauro Carvalho Chehab .maximum = 1, 58*e84fef6bSMauro Carvalho Chehab .default_value = 1, 59*e84fef6bSMauro Carvalho Chehab .type = V4L2_CTRL_TYPE_BOOLEAN, 60*e84fef6bSMauro Carvalho Chehab } 61*e84fef6bSMauro Carvalho Chehab }; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds #ifndef PCI_VENDOR_ID_GUILLEMOT 641da177e4SLinus Torvalds #define PCI_VENDOR_ID_GUILLEMOT 0x5046 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds #ifndef PCI_DEVICE_ID_GUILLEMOT 681da177e4SLinus Torvalds #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 691da177e4SLinus Torvalds #endif 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* TEA5757 pin mappings */ 731da177e4SLinus Torvalds static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds static int radio_nr = -1; 761da177e4SLinus Torvalds module_param(radio_nr, int, 0); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds #define FREQ_LO 50*16000 801da177e4SLinus Torvalds #define FREQ_HI 150*16000 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds #define FREQ_IF 171200 /* 10.7*16000 */ 831da177e4SLinus Torvalds #define FREQ_STEP 200 /* 12.5*16 */ 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds #define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ 861da177e4SLinus Torvalds /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds static int radio_ioctl(struct inode *inode, struct file *file, 921da177e4SLinus Torvalds unsigned int cmd, unsigned long arg); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static struct file_operations maxiradio_fops = { 951da177e4SLinus Torvalds .owner = THIS_MODULE, 961da177e4SLinus Torvalds .open = video_exclusive_open, 971da177e4SLinus Torvalds .release = video_exclusive_release, 981da177e4SLinus Torvalds .ioctl = radio_ioctl, 990d0fbf81SArnd Bergmann .compat_ioctl = v4l_compat_ioctl32, 1001da177e4SLinus Torvalds .llseek = no_llseek, 1011da177e4SLinus Torvalds }; 1021da177e4SLinus Torvalds static struct video_device maxiradio_radio = 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds .owner = THIS_MODULE, 1051da177e4SLinus Torvalds .name = "Maxi Radio FM2000 radio", 1061da177e4SLinus Torvalds .type = VID_TYPE_TUNER, 1071da177e4SLinus Torvalds .fops = &maxiradio_fops, 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static struct radio_device 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds __u16 io, /* base of radio io */ 1131da177e4SLinus Torvalds muted, /* VIDEO_AUDIO_MUTE */ 1141da177e4SLinus Torvalds stereo, /* VIDEO_TUNER_STEREO_ON */ 1151da177e4SLinus Torvalds tuned; /* signal strength (0 or 0xffff) */ 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds unsigned long freq; 1181da177e4SLinus Torvalds 1193593cab5SIngo Molnar struct mutex lock; 1201da177e4SLinus Torvalds } radio_unit = {0, 0, 0, 0, }; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds static void outbit(unsigned long bit, __u16 io) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds if(bit != 0) 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds outb( power|wren|data ,io); udelay(4); 1281da177e4SLinus Torvalds outb( power|wren|data|clk ,io); udelay(4); 1291da177e4SLinus Torvalds outb( power|wren|data ,io); udelay(4); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds else 1321da177e4SLinus Torvalds { 1331da177e4SLinus Torvalds outb( power|wren ,io); udelay(4); 1341da177e4SLinus Torvalds outb( power|wren|clk ,io); udelay(4); 1351da177e4SLinus Torvalds outb( power|wren ,io); udelay(4); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static void turn_power(__u16 io, int p) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds if(p != 0) outb(power, io); else outb(0,io); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds static void set_freq(__u16 io, __u32 data) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds unsigned long int si; 1481da177e4SLinus Torvalds int bl; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* TEA5757 shift register bits (see pdf) */ 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds outbit(0,io); // 24 search 1531da177e4SLinus Torvalds outbit(1,io); // 23 search up/down 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds outbit(0,io); // 22 stereo/mono 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds outbit(0,io); // 21 band 1581da177e4SLinus Torvalds outbit(0,io); // 20 band (only 00=FM works I think) 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds outbit(0,io); // 19 port ? 1611da177e4SLinus Torvalds outbit(0,io); // 18 port ? 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds outbit(0,io); // 17 search level 1641da177e4SLinus Torvalds outbit(0,io); // 16 search level 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds si = 0x8000; 1671da177e4SLinus Torvalds for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds outb(power,io); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds static int get_stereo(__u16 io) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds outb(power,io); udelay(4); 1751da177e4SLinus Torvalds return !(inb(io) & mo_st); 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds static int get_tune(__u16 io) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds outb(power+clk,io); udelay(4); 1811da177e4SLinus Torvalds return !(inb(io) & mo_st); 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds 18577933d72SJesper Juhl static inline int radio_function(struct inode *inode, struct file *file, 1861da177e4SLinus Torvalds unsigned int cmd, void *arg) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds struct video_device *dev = video_devdata(file); 1891da177e4SLinus Torvalds struct radio_device *card=dev->priv; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds switch(cmd) { 192*e84fef6bSMauro Carvalho Chehab case VIDIOC_QUERYCAP: 193*e84fef6bSMauro Carvalho Chehab { 194*e84fef6bSMauro Carvalho Chehab struct v4l2_capability *v = arg; 1951da177e4SLinus Torvalds memset(v,0,sizeof(*v)); 196*e84fef6bSMauro Carvalho Chehab strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver)); 197*e84fef6bSMauro Carvalho Chehab strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card)); 198*e84fef6bSMauro Carvalho Chehab sprintf(v->bus_info,"ISA"); 199*e84fef6bSMauro Carvalho Chehab v->version = RADIO_VERSION; 200*e84fef6bSMauro Carvalho Chehab v->capabilities = V4L2_CAP_TUNER; 201*e84fef6bSMauro Carvalho Chehab 2021da177e4SLinus Torvalds return 0; 2031da177e4SLinus Torvalds } 204*e84fef6bSMauro Carvalho Chehab case VIDIOC_G_TUNER: 205*e84fef6bSMauro Carvalho Chehab { 206*e84fef6bSMauro Carvalho Chehab struct v4l2_tuner *v = arg; 2071da177e4SLinus Torvalds 208*e84fef6bSMauro Carvalho Chehab if (v->index > 0) 2091da177e4SLinus Torvalds return -EINVAL; 2101da177e4SLinus Torvalds 211*e84fef6bSMauro Carvalho Chehab memset(v,0,sizeof(*v)); 2121da177e4SLinus Torvalds strcpy(v->name, "FM"); 213*e84fef6bSMauro Carvalho Chehab v->type = V4L2_TUNER_RADIO; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds v->rangelow=FREQ_LO; 2161da177e4SLinus Torvalds v->rangehigh=FREQ_HI; 217*e84fef6bSMauro Carvalho Chehab v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; 218*e84fef6bSMauro Carvalho Chehab v->capability=V4L2_TUNER_CAP_LOW; 219*e84fef6bSMauro Carvalho Chehab if(get_stereo(card->io)) 220*e84fef6bSMauro Carvalho Chehab v->audmode = V4L2_TUNER_MODE_STEREO; 221*e84fef6bSMauro Carvalho Chehab else 222*e84fef6bSMauro Carvalho Chehab v->audmode = V4L2_TUNER_MODE_MONO; 223*e84fef6bSMauro Carvalho Chehab v->signal=0xffff*get_tune(card->io); 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds return 0; 2261da177e4SLinus Torvalds } 227*e84fef6bSMauro Carvalho Chehab case VIDIOC_S_TUNER: 228*e84fef6bSMauro Carvalho Chehab { 229*e84fef6bSMauro Carvalho Chehab struct v4l2_tuner *v = arg; 230*e84fef6bSMauro Carvalho Chehab 231*e84fef6bSMauro Carvalho Chehab if (v->index > 0) 2321da177e4SLinus Torvalds return -EINVAL; 233*e84fef6bSMauro Carvalho Chehab 2341da177e4SLinus Torvalds return 0; 2351da177e4SLinus Torvalds } 236*e84fef6bSMauro Carvalho Chehab case VIDIOC_S_FREQUENCY: 237*e84fef6bSMauro Carvalho Chehab { 238*e84fef6bSMauro Carvalho Chehab struct v4l2_frequency *f = arg; 2391da177e4SLinus Torvalds 240*e84fef6bSMauro Carvalho Chehab if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) 2411da177e4SLinus Torvalds return -EINVAL; 242*e84fef6bSMauro Carvalho Chehab 243*e84fef6bSMauro Carvalho Chehab card->freq = f->frequency; 2441da177e4SLinus Torvalds set_freq(card->io, FREQ2BITS(card->freq)); 2451da177e4SLinus Torvalds msleep(125); 2461da177e4SLinus Torvalds return 0; 2471da177e4SLinus Torvalds } 248*e84fef6bSMauro Carvalho Chehab case VIDIOC_G_FREQUENCY: 249*e84fef6bSMauro Carvalho Chehab { 250*e84fef6bSMauro Carvalho Chehab struct v4l2_frequency *f = arg; 251*e84fef6bSMauro Carvalho Chehab 252*e84fef6bSMauro Carvalho Chehab f->type = V4L2_TUNER_RADIO; 253*e84fef6bSMauro Carvalho Chehab f->frequency = card->freq; 254*e84fef6bSMauro Carvalho Chehab 2551da177e4SLinus Torvalds return 0; 2561da177e4SLinus Torvalds } 257*e84fef6bSMauro Carvalho Chehab case VIDIOC_QUERYCTRL: 258*e84fef6bSMauro Carvalho Chehab { 259*e84fef6bSMauro Carvalho Chehab struct v4l2_queryctrl *qc = arg; 260*e84fef6bSMauro Carvalho Chehab int i; 2611da177e4SLinus Torvalds 262*e84fef6bSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 263*e84fef6bSMauro Carvalho Chehab if (qc->id && qc->id == radio_qctrl[i].id) { 264*e84fef6bSMauro Carvalho Chehab memcpy(qc, &(radio_qctrl[i]), 265*e84fef6bSMauro Carvalho Chehab sizeof(*qc)); 266*e84fef6bSMauro Carvalho Chehab return (0); 267*e84fef6bSMauro Carvalho Chehab } 268*e84fef6bSMauro Carvalho Chehab } 2691da177e4SLinus Torvalds return -EINVAL; 270*e84fef6bSMauro Carvalho Chehab } 271*e84fef6bSMauro Carvalho Chehab case VIDIOC_G_CTRL: 272*e84fef6bSMauro Carvalho Chehab { 273*e84fef6bSMauro Carvalho Chehab struct v4l2_control *ctrl= arg; 274*e84fef6bSMauro Carvalho Chehab 275*e84fef6bSMauro Carvalho Chehab switch (ctrl->id) { 276*e84fef6bSMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 277*e84fef6bSMauro Carvalho Chehab ctrl->value=card->muted; 278*e84fef6bSMauro Carvalho Chehab return (0); 279*e84fef6bSMauro Carvalho Chehab } 280*e84fef6bSMauro Carvalho Chehab return -EINVAL; 281*e84fef6bSMauro Carvalho Chehab } 282*e84fef6bSMauro Carvalho Chehab case VIDIOC_S_CTRL: 283*e84fef6bSMauro Carvalho Chehab { 284*e84fef6bSMauro Carvalho Chehab struct v4l2_control *ctrl= arg; 285*e84fef6bSMauro Carvalho Chehab 286*e84fef6bSMauro Carvalho Chehab switch (ctrl->id) { 287*e84fef6bSMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 288*e84fef6bSMauro Carvalho Chehab card->muted = ctrl->value; 2891da177e4SLinus Torvalds if(card->muted) 2901da177e4SLinus Torvalds turn_power(card->io, 0); 2911da177e4SLinus Torvalds else 2921da177e4SLinus Torvalds set_freq(card->io, FREQ2BITS(card->freq)); 2931da177e4SLinus Torvalds return 0; 2941da177e4SLinus Torvalds } 295*e84fef6bSMauro Carvalho Chehab return -EINVAL; 2961da177e4SLinus Torvalds } 297*e84fef6bSMauro Carvalho Chehab 298*e84fef6bSMauro Carvalho Chehab default: 299*e84fef6bSMauro Carvalho Chehab return v4l_compat_translate_ioctl(inode,file,cmd,arg, 300*e84fef6bSMauro Carvalho Chehab radio_function); 301*e84fef6bSMauro Carvalho Chehab 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds static int radio_ioctl(struct inode *inode, struct file *file, 3061da177e4SLinus Torvalds unsigned int cmd, unsigned long arg) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds struct video_device *dev = video_devdata(file); 3091da177e4SLinus Torvalds struct radio_device *card=dev->priv; 3101da177e4SLinus Torvalds int ret; 3111da177e4SLinus Torvalds 3123593cab5SIngo Molnar mutex_lock(&card->lock); 3131da177e4SLinus Torvalds ret = video_usercopy(inode, file, cmd, arg, radio_function); 3143593cab5SIngo Molnar mutex_unlock(&card->lock); 3151da177e4SLinus Torvalds return ret; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); 3191da177e4SLinus Torvalds MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); 3201da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 3241da177e4SLinus Torvalds { 3251da177e4SLinus Torvalds if(!request_region(pci_resource_start(pdev, 0), 3261da177e4SLinus Torvalds pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { 3271da177e4SLinus Torvalds printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n"); 3281da177e4SLinus Torvalds goto err_out; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds if (pci_enable_device(pdev)) 3321da177e4SLinus Torvalds goto err_out_free_region; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds radio_unit.io = pci_resource_start(pdev, 0); 3353593cab5SIngo Molnar mutex_init(&radio_unit.lock); 3361da177e4SLinus Torvalds maxiradio_radio.priv = &radio_unit; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { 3391da177e4SLinus Torvalds printk("radio-maxiradio: can't register device!"); 3401da177e4SLinus Torvalds goto err_out_free_region; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds printk(KERN_INFO "radio-maxiradio: version " 3441da177e4SLinus Torvalds DRIVER_VERSION 3451da177e4SLinus Torvalds " time " 3461da177e4SLinus Torvalds __TIME__ " " 3471da177e4SLinus Torvalds __DATE__ 3481da177e4SLinus Torvalds "\n"); 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n", 3511da177e4SLinus Torvalds radio_unit.io); 3521da177e4SLinus Torvalds return 0; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds err_out_free_region: 3551da177e4SLinus Torvalds release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 3561da177e4SLinus Torvalds err_out: 3571da177e4SLinus Torvalds return -ENODEV; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds static void __devexit maxiradio_remove_one(struct pci_dev *pdev) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds video_unregister_device(&maxiradio_radio); 3631da177e4SLinus Torvalds release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds static struct pci_device_id maxiradio_pci_tbl[] = { 3671da177e4SLinus Torvalds { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, 3681da177e4SLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, }, 3691da177e4SLinus Torvalds { 0,} 3701da177e4SLinus Torvalds }; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds static struct pci_driver maxiradio_driver = { 3751da177e4SLinus Torvalds .name = "radio-maxiradio", 3761da177e4SLinus Torvalds .id_table = maxiradio_pci_tbl, 3771da177e4SLinus Torvalds .probe = maxiradio_init_one, 3781da177e4SLinus Torvalds .remove = __devexit_p(maxiradio_remove_one), 3791da177e4SLinus Torvalds }; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds static int __init maxiradio_radio_init(void) 3821da177e4SLinus Torvalds { 3839bfab8ceSRichard Knutsson return pci_register_driver(&maxiradio_driver); 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds static void __exit maxiradio_radio_exit(void) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds pci_unregister_driver(&maxiradio_driver); 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds module_init(maxiradio_radio_init); 3921da177e4SLinus Torvalds module_exit(maxiradio_radio_exit); 393