diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-05 15:22:01 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:04:34 -0500 |
commit | 0be4375410f1ecc917f3c0caf8f98908d357c93f (patch) | |
tree | 1ec68f3804fccd515edc00b557ae8b8e80fd9584 /drivers | |
parent | 3abee53e4402b6ae39e1e610f9ef94eb74097138 (diff) |
V4L/DVB (6956): Add Radio support for em28xx
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 296 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 2 |
2 files changed, 238 insertions, 60 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 0f075f532eae..5a90462d82e5 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -61,13 +61,17 @@ static LIST_HEAD(em28xx_devlist); | |||
61 | 61 | ||
62 | static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | 62 | static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; |
63 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | 63 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; |
64 | static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | 64 | static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; |
65 | static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | ||
66 | |||
65 | module_param_array(card, int, NULL, 0444); | 67 | module_param_array(card, int, NULL, 0444); |
66 | module_param_array(video_nr, int, NULL, 0444); | 68 | module_param_array(video_nr, int, NULL, 0444); |
67 | module_param_array(vbi_nr, int, NULL, 0444); | 69 | module_param_array(vbi_nr, int, NULL, 0444); |
68 | MODULE_PARM_DESC(card,"card type"); | 70 | module_param_array(radio_nr, int, NULL, 0444); |
69 | MODULE_PARM_DESC(video_nr,"video device numbers"); | 71 | MODULE_PARM_DESC(card, "card type"); |
70 | MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); | 72 | MODULE_PARM_DESC(video_nr, "video device numbers"); |
73 | MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); | ||
74 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); | ||
71 | 75 | ||
72 | static unsigned int video_debug = 0; | 76 | static unsigned int video_debug = 0; |
73 | module_param(video_debug,int,0644); | 77 | module_param(video_debug,int,0644); |
@@ -791,7 +795,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
791 | struct em28xx_fh *fh = priv; | 795 | struct em28xx_fh *fh = priv; |
792 | struct em28xx *dev = fh->dev; | 796 | struct em28xx *dev = fh->dev; |
793 | 797 | ||
794 | f->type = V4L2_TUNER_ANALOG_TV; | 798 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; |
795 | f->frequency = dev->ctl_freq; | 799 | f->frequency = dev->ctl_freq; |
796 | 800 | ||
797 | return 0; | 801 | return 0; |
@@ -811,7 +815,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
811 | if (0 != f->tuner) | 815 | if (0 != f->tuner) |
812 | return -EINVAL; | 816 | return -EINVAL; |
813 | 817 | ||
814 | if (V4L2_TUNER_ANALOG_TV != f->type) | 818 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) |
819 | return -EINVAL; | ||
820 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | ||
815 | return -EINVAL; | 821 | return -EINVAL; |
816 | 822 | ||
817 | mutex_lock(&dev->lock); | 823 | mutex_lock(&dev->lock); |
@@ -1148,6 +1154,102 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
1148 | return 0; | 1154 | return 0; |
1149 | } | 1155 | } |
1150 | 1156 | ||
1157 | /* ----------------------------------------------------------- */ | ||
1158 | /* RADIO ESPECIFIC IOCTLS */ | ||
1159 | /* ----------------------------------------------------------- */ | ||
1160 | |||
1161 | static int radio_querycap(struct file *file, void *priv, | ||
1162 | struct v4l2_capability *cap) | ||
1163 | { | ||
1164 | struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; | ||
1165 | |||
1166 | strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); | ||
1167 | strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); | ||
1168 | strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); | ||
1169 | |||
1170 | cap->version = EM28XX_VERSION_CODE; | ||
1171 | cap->capabilities = V4L2_CAP_TUNER; | ||
1172 | return 0; | ||
1173 | } | ||
1174 | |||
1175 | static int radio_g_tuner(struct file *file, void *priv, | ||
1176 | struct v4l2_tuner *t) | ||
1177 | { | ||
1178 | struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; | ||
1179 | |||
1180 | if (unlikely(t->index > 0)) | ||
1181 | return -EINVAL; | ||
1182 | |||
1183 | strcpy(t->name, "Radio"); | ||
1184 | t->type = V4L2_TUNER_RADIO; | ||
1185 | |||
1186 | em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); | ||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | static int radio_enum_input(struct file *file, void *priv, | ||
1191 | struct v4l2_input *i) | ||
1192 | { | ||
1193 | if (i->index != 0) | ||
1194 | return -EINVAL; | ||
1195 | strcpy(i->name, "Radio"); | ||
1196 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1197 | |||
1198 | return 0; | ||
1199 | } | ||
1200 | |||
1201 | static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) | ||
1202 | { | ||
1203 | if (unlikely(a->index)) | ||
1204 | return -EINVAL; | ||
1205 | |||
1206 | strcpy(a->name, "Radio"); | ||
1207 | return 0; | ||
1208 | } | ||
1209 | |||
1210 | static int radio_s_tuner(struct file *file, void *priv, | ||
1211 | struct v4l2_tuner *t) | ||
1212 | { | ||
1213 | struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; | ||
1214 | |||
1215 | if (0 != t->index) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); | ||
1219 | |||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | static int radio_s_audio(struct file *file, void *fh, | ||
1224 | struct v4l2_audio *a) | ||
1225 | { | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int radio_s_input(struct file *file, void *fh, unsigned int i) | ||
1230 | { | ||
1231 | return 0; | ||
1232 | } | ||
1233 | |||
1234 | static int radio_queryctrl(struct file *file, void *priv, | ||
1235 | struct v4l2_queryctrl *qc) | ||
1236 | { | ||
1237 | int i; | ||
1238 | |||
1239 | if (qc->id < V4L2_CID_BASE || | ||
1240 | qc->id >= V4L2_CID_LASTP1) | ||
1241 | return -EINVAL; | ||
1242 | |||
1243 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | ||
1244 | if (qc->id && qc->id == em28xx_qctrl[i].id) { | ||
1245 | memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); | ||
1246 | return 0; | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | return -EINVAL; | ||
1251 | } | ||
1252 | |||
1151 | /* | 1253 | /* |
1152 | * em28xx_v4l2_open() | 1254 | * em28xx_v4l2_open() |
1153 | * inits the device and starts isoc transfer | 1255 | * inits the device and starts isoc transfer |
@@ -1155,7 +1257,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
1155 | static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | 1257 | static int em28xx_v4l2_open(struct inode *inode, struct file *filp) |
1156 | { | 1258 | { |
1157 | int minor = iminor(inode); | 1259 | int minor = iminor(inode); |
1158 | int errCode = 0; | 1260 | int errCode = 0, radio = 0; |
1159 | struct em28xx *h,*dev = NULL; | 1261 | struct em28xx *h,*dev = NULL; |
1160 | struct em28xx_fh *fh; | 1262 | struct em28xx_fh *fh; |
1161 | 1263 | ||
@@ -1168,6 +1270,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1168 | dev = h; | 1270 | dev = h; |
1169 | dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1271 | dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1170 | } | 1272 | } |
1273 | if (h->radio_dev && | ||
1274 | h->radio_dev->minor == minor) { | ||
1275 | radio = 1; | ||
1276 | dev = h; | ||
1277 | } | ||
1171 | } | 1278 | } |
1172 | if (NULL == dev) | 1279 | if (NULL == dev) |
1173 | return -ENODEV; | 1280 | return -ENODEV; |
@@ -1183,6 +1290,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1183 | } | 1290 | } |
1184 | mutex_lock(&dev->lock); | 1291 | mutex_lock(&dev->lock); |
1185 | fh->dev = dev; | 1292 | fh->dev = dev; |
1293 | fh->radio = radio; | ||
1186 | filp->private_data = fh; | 1294 | filp->private_data = fh; |
1187 | 1295 | ||
1188 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { | 1296 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { |
@@ -1207,6 +1315,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
1207 | 1315 | ||
1208 | em28xx_empty_framequeues(dev); | 1316 | em28xx_empty_framequeues(dev); |
1209 | } | 1317 | } |
1318 | if (fh->radio) { | ||
1319 | em28xx_videodbg("video_open: setting radio device\n"); | ||
1320 | em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); | ||
1321 | } | ||
1210 | 1322 | ||
1211 | dev->users++; | 1323 | dev->users++; |
1212 | 1324 | ||
@@ -1229,12 +1341,30 @@ static void em28xx_release_resources(struct em28xx *dev) | |||
1229 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, | 1341 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, |
1230 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); | 1342 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); |
1231 | list_del(&dev->devlist); | 1343 | list_del(&dev->devlist); |
1232 | video_unregister_device(dev->vdev); | 1344 | if (dev->radio_dev) { |
1233 | video_unregister_device(dev->vbi_dev); | 1345 | if (-1 != dev->radio_dev->minor) |
1346 | video_unregister_device(dev->radio_dev); | ||
1347 | else | ||
1348 | video_device_release(dev->radio_dev); | ||
1349 | dev->radio_dev = NULL; | ||
1350 | } | ||
1351 | if (dev->vbi_dev) { | ||
1352 | if (-1 != dev->vbi_dev->minor) | ||
1353 | video_unregister_device(dev->vbi_dev); | ||
1354 | else | ||
1355 | video_device_release(dev->vbi_dev); | ||
1356 | dev->vbi_dev = NULL; | ||
1357 | } | ||
1358 | if (dev->vdev) { | ||
1359 | if (-1 != dev->vdev->minor) | ||
1360 | video_unregister_device(dev->vdev); | ||
1361 | else | ||
1362 | video_device_release(dev->vdev); | ||
1363 | dev->vdev = NULL; | ||
1364 | } | ||
1234 | em28xx_i2c_unregister(dev); | 1365 | em28xx_i2c_unregister(dev); |
1235 | usb_put_dev(dev->udev); | 1366 | usb_put_dev(dev->udev); |
1236 | 1367 | ||
1237 | |||
1238 | /* Mark device as unused */ | 1368 | /* Mark device as unused */ |
1239 | em28xx_devused&=~(1<<dev->devno); | 1369 | em28xx_devused&=~(1<<dev->devno); |
1240 | } | 1370 | } |
@@ -1555,6 +1685,15 @@ static const struct file_operations em28xx_v4l_fops = { | |||
1555 | .compat_ioctl = v4l_compat_ioctl32, | 1685 | .compat_ioctl = v4l_compat_ioctl32, |
1556 | }; | 1686 | }; |
1557 | 1687 | ||
1688 | static const struct file_operations radio_fops = { | ||
1689 | .owner = THIS_MODULE, | ||
1690 | .open = em28xx_v4l2_open, | ||
1691 | .release = em28xx_v4l2_close, | ||
1692 | .ioctl = video_ioctl2, | ||
1693 | .compat_ioctl = v4l_compat_ioctl32, | ||
1694 | .llseek = no_llseek, | ||
1695 | }; | ||
1696 | |||
1558 | static const struct video_device em28xx_video_template = { | 1697 | static const struct video_device em28xx_video_template = { |
1559 | .fops = &em28xx_v4l_fops, | 1698 | .fops = &em28xx_v4l_fops, |
1560 | .release = video_device_release, | 1699 | .release = video_device_release, |
@@ -1595,6 +1734,25 @@ static const struct video_device em28xx_video_template = { | |||
1595 | .current_norm = V4L2_STD_PAL, | 1734 | .current_norm = V4L2_STD_PAL, |
1596 | }; | 1735 | }; |
1597 | 1736 | ||
1737 | static struct video_device em28xx_radio_template = { | ||
1738 | .name = "em28xx-radio", | ||
1739 | .type = VID_TYPE_TUNER, | ||
1740 | .fops = &radio_fops, | ||
1741 | .minor = -1, | ||
1742 | .vidioc_querycap = radio_querycap, | ||
1743 | .vidioc_g_tuner = radio_g_tuner, | ||
1744 | .vidioc_enum_input = radio_enum_input, | ||
1745 | .vidioc_g_audio = radio_g_audio, | ||
1746 | .vidioc_s_tuner = radio_s_tuner, | ||
1747 | .vidioc_s_audio = radio_s_audio, | ||
1748 | .vidioc_s_input = radio_s_input, | ||
1749 | .vidioc_queryctrl = radio_queryctrl, | ||
1750 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1751 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1752 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1753 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1754 | }; | ||
1755 | |||
1598 | /******************************** usb interface *****************************************/ | 1756 | /******************************** usb interface *****************************************/ |
1599 | 1757 | ||
1600 | 1758 | ||
@@ -1637,6 +1795,29 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) | |||
1637 | } | 1795 | } |
1638 | EXPORT_SYMBOL(em28xx_unregister_extension); | 1796 | EXPORT_SYMBOL(em28xx_unregister_extension); |
1639 | 1797 | ||
1798 | struct video_device *em28xx_vdev_init(struct em28xx *dev, | ||
1799 | const struct video_device *template, | ||
1800 | const int type, | ||
1801 | const char *type_name) | ||
1802 | { | ||
1803 | struct video_device *vfd; | ||
1804 | |||
1805 | vfd = video_device_alloc(); | ||
1806 | if (NULL == vfd) | ||
1807 | return NULL; | ||
1808 | *vfd = *template; | ||
1809 | vfd->minor = -1; | ||
1810 | vfd->dev = &dev->udev->dev; | ||
1811 | vfd->release = video_device_release; | ||
1812 | vfd->type = type; | ||
1813 | |||
1814 | snprintf(vfd->name, sizeof(vfd->name), "%s %s", | ||
1815 | dev->name, type_name); | ||
1816 | |||
1817 | return vfd; | ||
1818 | } | ||
1819 | |||
1820 | |||
1640 | /* | 1821 | /* |
1641 | * em28xx_init_dev() | 1822 | * em28xx_init_dev() |
1642 | * allocates and inits the device structs, registers i2c bus and v4l device | 1823 | * allocates and inits the device structs, registers i2c bus and v4l device |
@@ -1710,40 +1891,55 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1710 | 1891 | ||
1711 | errCode = em28xx_config(dev); | 1892 | errCode = em28xx_config(dev); |
1712 | 1893 | ||
1894 | list_add_tail(&dev->devlist, &em28xx_devlist); | ||
1895 | |||
1713 | /* allocate and fill video video_device struct */ | 1896 | /* allocate and fill video video_device struct */ |
1714 | dev->vdev = video_device_alloc(); | 1897 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, |
1898 | VID_TYPE_CAPTURE, "video"); | ||
1715 | if (NULL == dev->vdev) { | 1899 | if (NULL == dev->vdev) { |
1716 | em28xx_errdev("cannot allocate video_device.\n"); | 1900 | em28xx_errdev("cannot allocate video_device.\n"); |
1717 | em28xx_devused&=~(1<<dev->devno); | 1901 | goto fail_unreg; |
1718 | kfree(dev); | ||
1719 | return -ENOMEM; | ||
1720 | } | 1902 | } |
1721 | memcpy(dev->vdev, &em28xx_video_template, | ||
1722 | sizeof(em28xx_video_template)); | ||
1723 | dev->vdev->type = VID_TYPE_CAPTURE; | ||
1724 | if (dev->has_tuner) | 1903 | if (dev->has_tuner) |
1725 | dev->vdev->type |= VID_TYPE_TUNER; | 1904 | dev->vdev->type |= VID_TYPE_TUNER; |
1726 | dev->vdev->dev = &dev->udev->dev; | 1905 | |
1727 | snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), | 1906 | /* register v4l2 video video_device */ |
1728 | "%s#%d %s", "em28xx", dev->devno, "video"); | 1907 | retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, |
1908 | video_nr[dev->devno]); | ||
1909 | if (retval) { | ||
1910 | em28xx_errdev("unable to register video device (error=%i).\n", | ||
1911 | retval); | ||
1912 | goto fail_unreg; | ||
1913 | } | ||
1729 | 1914 | ||
1730 | /* Allocate and fill vbi video_device struct */ | 1915 | /* Allocate and fill vbi video_device struct */ |
1731 | dev->vbi_dev = video_device_alloc(); | 1916 | dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, |
1732 | if (NULL == dev->vbi_dev) { | 1917 | VFL_TYPE_VBI, "vbi"); |
1733 | em28xx_errdev("cannot allocate video_device.\n"); | 1918 | /* register v4l2 vbi video_device */ |
1734 | kfree(dev->vdev); | 1919 | if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, |
1735 | em28xx_devused&=~(1<<dev->devno); | 1920 | vbi_nr[dev->devno]) < 0) { |
1736 | kfree(dev); | 1921 | em28xx_errdev("unable to register vbi device\n"); |
1737 | return -ENOMEM; | 1922 | retval = -ENODEV; |
1923 | goto fail_unreg; | ||
1924 | } | ||
1925 | |||
1926 | if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { | ||
1927 | dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, | ||
1928 | VFL_TYPE_RADIO, "radio"); | ||
1929 | if (NULL == dev->radio_dev) { | ||
1930 | em28xx_errdev("cannot allocate video_device.\n"); | ||
1931 | goto fail_unreg; | ||
1932 | } | ||
1933 | retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | ||
1934 | radio_nr[dev->devno]); | ||
1935 | if (retval < 0) { | ||
1936 | em28xx_errdev("can't register radio device\n"); | ||
1937 | goto fail_unreg; | ||
1938 | } | ||
1939 | em28xx_info("Registered radio device as /dev/radio%d\n", | ||
1940 | dev->radio_dev->minor & 0x1f); | ||
1738 | } | 1941 | } |
1739 | memcpy(dev->vbi_dev, &em28xx_video_template, | ||
1740 | sizeof(em28xx_video_template)); | ||
1741 | dev->vbi_dev->type = VFL_TYPE_VBI; | ||
1742 | dev->vbi_dev->dev = &dev->udev->dev; | ||
1743 | snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), | ||
1744 | "%s#%d %s", "em28xx", dev->devno, "vbi"); | ||
1745 | 1942 | ||
1746 | list_add_tail(&dev->devlist,&em28xx_devlist); | ||
1747 | 1943 | ||
1748 | if (dev->has_msp34xx) { | 1944 | if (dev->has_msp34xx) { |
1749 | /* Send a reset to other chips via gpio */ | 1945 | /* Send a reset to other chips via gpio */ |
@@ -1755,32 +1951,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1755 | 1951 | ||
1756 | video_mux(dev, 0); | 1952 | video_mux(dev, 0); |
1757 | 1953 | ||
1758 | /* register v4l2 video video_device */ | ||
1759 | if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, | ||
1760 | video_nr[dev->devno]))) { | ||
1761 | em28xx_errdev("unable to register video device (error=%i).\n", | ||
1762 | retval); | ||
1763 | mutex_unlock(&dev->lock); | ||
1764 | list_del(&dev->devlist); | ||
1765 | video_device_release(dev->vdev); | ||
1766 | em28xx_devused&=~(1<<dev->devno); | ||
1767 | kfree(dev); | ||
1768 | return -ENODEV; | ||
1769 | } | ||
1770 | |||
1771 | /* register v4l2 vbi video_device */ | ||
1772 | if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, | ||
1773 | vbi_nr[dev->devno]) < 0) { | ||
1774 | printk("unable to register vbi device\n"); | ||
1775 | mutex_unlock(&dev->lock); | ||
1776 | list_del(&dev->devlist); | ||
1777 | video_device_release(dev->vbi_dev); | ||
1778 | video_device_release(dev->vdev); | ||
1779 | em28xx_devused&=~(1<<dev->devno); | ||
1780 | kfree(dev); | ||
1781 | return -ENODEV; | ||
1782 | } | ||
1783 | |||
1784 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | 1954 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", |
1785 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, | 1955 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, |
1786 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); | 1956 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); |
@@ -1795,6 +1965,12 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1795 | mutex_unlock(&em28xx_extension_devlist_lock); | 1965 | mutex_unlock(&em28xx_extension_devlist_lock); |
1796 | 1966 | ||
1797 | return 0; | 1967 | return 0; |
1968 | |||
1969 | fail_unreg: | ||
1970 | em28xx_release_resources(dev); | ||
1971 | mutex_unlock(&dev->lock); | ||
1972 | kfree(dev); | ||
1973 | return retval; | ||
1798 | } | 1974 | } |
1799 | 1975 | ||
1800 | #if defined(CONFIG_MODULES) && defined(MODULE) | 1976 | #if defined(CONFIG_MODULES) && defined(MODULE) |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 2d57330c4537..2ba34e5b4cc2 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -191,6 +191,7 @@ struct em28xx_board { | |||
191 | enum em28xx_decoder decoder; | 191 | enum em28xx_decoder decoder; |
192 | 192 | ||
193 | struct em28xx_input input[MAX_EM28XX_INPUT]; | 193 | struct em28xx_input input[MAX_EM28XX_INPUT]; |
194 | struct em28xx_input radio; | ||
194 | }; | 195 | }; |
195 | 196 | ||
196 | struct em28xx_eeprom { | 197 | struct em28xx_eeprom { |
@@ -307,6 +308,7 @@ struct em28xx { | |||
307 | struct list_head inqueue, outqueue; | 308 | struct list_head inqueue, outqueue; |
308 | wait_queue_head_t open, wait_frame, wait_stream; | 309 | wait_queue_head_t open, wait_frame, wait_stream; |
309 | struct video_device *vbi_dev; | 310 | struct video_device *vbi_dev; |
311 | struct video_device *radio_dev; | ||
310 | 312 | ||
311 | unsigned char eedata[256]; | 313 | unsigned char eedata[256]; |
312 | 314 | ||