diff options
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-video.c | 652 |
1 files changed, 593 insertions, 59 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index dd19c9ff76e0..c3c928937dcd 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -38,9 +38,11 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | 39 | ||
40 | #include "em28xx.h" | 40 | #include "em28xx.h" |
41 | #include "em28xx-v4l.h" | ||
41 | #include <media/v4l2-common.h> | 42 | #include <media/v4l2-common.h> |
42 | #include <media/v4l2-ioctl.h> | 43 | #include <media/v4l2-ioctl.h> |
43 | #include <media/v4l2-event.h> | 44 | #include <media/v4l2-event.h> |
45 | #include <media/v4l2-clk.h> | ||
44 | #include <media/msp3400.h> | 46 | #include <media/msp3400.h> |
45 | #include <media/tuner.h> | 47 | #include <media/tuner.h> |
46 | 48 | ||
@@ -49,19 +51,23 @@ | |||
49 | "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ | 51 | "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ |
50 | "Sascha Sommer <saschasommer@freenet.de>" | 52 | "Sascha Sommer <saschasommer@freenet.de>" |
51 | 53 | ||
52 | #define DRIVER_DESC "Empia em28xx based USB video device driver" | 54 | static unsigned int isoc_debug; |
55 | module_param(isoc_debug, int, 0644); | ||
56 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
57 | |||
58 | static unsigned int disable_vbi; | ||
59 | module_param(disable_vbi, int, 0644); | ||
60 | MODULE_PARM_DESC(disable_vbi, "disable vbi support"); | ||
53 | 61 | ||
54 | #define EM28XX_VERSION "0.2.0" | 62 | static int alt; |
63 | module_param(alt, int, 0644); | ||
64 | MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); | ||
55 | 65 | ||
56 | #define em28xx_videodbg(fmt, arg...) do {\ | 66 | #define em28xx_videodbg(fmt, arg...) do {\ |
57 | if (video_debug) \ | 67 | if (video_debug) \ |
58 | printk(KERN_INFO "%s %s :"fmt, \ | 68 | printk(KERN_INFO "%s %s :"fmt, \ |
59 | dev->name, __func__ , ##arg); } while (0) | 69 | dev->name, __func__ , ##arg); } while (0) |
60 | 70 | ||
61 | static unsigned int isoc_debug; | ||
62 | module_param(isoc_debug, int, 0644); | ||
63 | MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); | ||
64 | |||
65 | #define em28xx_isocdbg(fmt, arg...) \ | 71 | #define em28xx_isocdbg(fmt, arg...) \ |
66 | do {\ | 72 | do {\ |
67 | if (isoc_debug) { \ | 73 | if (isoc_debug) { \ |
@@ -71,7 +77,7 @@ do {\ | |||
71 | } while (0) | 77 | } while (0) |
72 | 78 | ||
73 | MODULE_AUTHOR(DRIVER_AUTHOR); | 79 | MODULE_AUTHOR(DRIVER_AUTHOR); |
74 | MODULE_DESCRIPTION(DRIVER_DESC); | 80 | MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); |
75 | MODULE_LICENSE("GPL"); | 81 | MODULE_LICENSE("GPL"); |
76 | MODULE_VERSION(EM28XX_VERSION); | 82 | MODULE_VERSION(EM28XX_VERSION); |
77 | 83 | ||
@@ -135,6 +141,257 @@ static struct em28xx_fmt format[] = { | |||
135 | }, | 141 | }, |
136 | }; | 142 | }; |
137 | 143 | ||
144 | static int em28xx_vbi_supported(struct em28xx *dev) | ||
145 | { | ||
146 | /* Modprobe option to manually disable */ | ||
147 | if (disable_vbi == 1) | ||
148 | return 0; | ||
149 | |||
150 | if (dev->board.is_webcam) | ||
151 | return 0; | ||
152 | |||
153 | /* FIXME: check subdevices for VBI support */ | ||
154 | |||
155 | if (dev->chip_id == CHIP_ID_EM2860 || | ||
156 | dev->chip_id == CHIP_ID_EM2883) | ||
157 | return 1; | ||
158 | |||
159 | /* Version of em28xx that does not support VBI */ | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * em28xx_wake_i2c() | ||
165 | * configure i2c attached devices | ||
166 | */ | ||
167 | static void em28xx_wake_i2c(struct em28xx *dev) | ||
168 | { | ||
169 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); | ||
170 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, | ||
171 | INPUT(dev->ctl_input)->vmux, 0, 0); | ||
172 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); | ||
173 | } | ||
174 | |||
175 | static int em28xx_colorlevels_set_default(struct em28xx *dev) | ||
176 | { | ||
177 | em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); | ||
178 | em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); | ||
179 | em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); | ||
180 | em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); | ||
181 | em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); | ||
182 | em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); | ||
183 | |||
184 | em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); | ||
185 | em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); | ||
186 | em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); | ||
187 | em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); | ||
188 | em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); | ||
189 | em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); | ||
190 | return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); | ||
191 | } | ||
192 | |||
193 | static int em28xx_set_outfmt(struct em28xx *dev) | ||
194 | { | ||
195 | int ret; | ||
196 | u8 fmt, vinctrl; | ||
197 | |||
198 | fmt = dev->format->reg; | ||
199 | if (!dev->is_em25xx) | ||
200 | fmt |= 0x20; | ||
201 | /* | ||
202 | * NOTE: it's not clear if this is really needed ! | ||
203 | * The datasheets say bit 5 is a reserved bit and devices seem to work | ||
204 | * fine without it. But the Windows driver sets it for em2710/50+em28xx | ||
205 | * devices and we've always been setting it, too. | ||
206 | * | ||
207 | * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, | ||
208 | * it's likely used for an additional (compressed ?) format there. | ||
209 | */ | ||
210 | ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | |||
214 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); | ||
215 | if (ret < 0) | ||
216 | return ret; | ||
217 | |||
218 | vinctrl = dev->vinctl; | ||
219 | if (em28xx_vbi_supported(dev) == 1) { | ||
220 | vinctrl |= EM28XX_VINCTRL_VBI_RAW; | ||
221 | em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); | ||
222 | em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); | ||
223 | em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); | ||
224 | if (dev->norm & V4L2_STD_525_60) { | ||
225 | /* NTSC */ | ||
226 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); | ||
227 | } else if (dev->norm & V4L2_STD_625_50) { | ||
228 | /* PAL */ | ||
229 | em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); | ||
234 | } | ||
235 | |||
236 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | ||
237 | u8 ymin, u8 ymax) | ||
238 | { | ||
239 | em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n", | ||
240 | xmin, ymin, xmax, ymax); | ||
241 | |||
242 | em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); | ||
243 | em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); | ||
244 | em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); | ||
245 | return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); | ||
246 | } | ||
247 | |||
248 | static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, | ||
249 | u16 width, u16 height) | ||
250 | { | ||
251 | u8 cwidth = width >> 2; | ||
252 | u8 cheight = height >> 2; | ||
253 | u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); | ||
254 | /* NOTE: size limit: 2047x1023 = 2MPix */ | ||
255 | |||
256 | em28xx_videodbg("capture area set to (%d,%d): %dx%d\n", | ||
257 | hstart, vstart, | ||
258 | ((overflow & 2) << 9 | cwidth << 2), | ||
259 | ((overflow & 1) << 10 | cheight << 2)); | ||
260 | |||
261 | em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); | ||
262 | em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); | ||
263 | em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); | ||
264 | em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); | ||
265 | em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); | ||
266 | |||
267 | /* FIXME: function/meaning of these registers ? */ | ||
268 | /* FIXME: align width+height to multiples of 4 ?! */ | ||
269 | if (dev->is_em25xx) { | ||
270 | em28xx_write_reg(dev, 0x34, width >> 4); | ||
271 | em28xx_write_reg(dev, 0x35, height >> 4); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) | ||
276 | { | ||
277 | u8 mode; | ||
278 | /* the em2800 scaler only supports scaling down to 50% */ | ||
279 | |||
280 | if (dev->board.is_em2800) { | ||
281 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); | ||
282 | } else { | ||
283 | u8 buf[2]; | ||
284 | |||
285 | buf[0] = h; | ||
286 | buf[1] = h >> 8; | ||
287 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); | ||
288 | |||
289 | buf[0] = v; | ||
290 | buf[1] = v >> 8; | ||
291 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); | ||
292 | /* it seems that both H and V scalers must be active | ||
293 | to work correctly */ | ||
294 | mode = (h || v) ? 0x30 : 0x00; | ||
295 | } | ||
296 | return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); | ||
297 | } | ||
298 | |||
299 | /* FIXME: this only function read values from dev */ | ||
300 | static int em28xx_resolution_set(struct em28xx *dev) | ||
301 | { | ||
302 | int width, height; | ||
303 | width = norm_maxw(dev); | ||
304 | height = norm_maxh(dev); | ||
305 | |||
306 | /* Properly setup VBI */ | ||
307 | dev->vbi_width = 720; | ||
308 | if (dev->norm & V4L2_STD_525_60) | ||
309 | dev->vbi_height = 12; | ||
310 | else | ||
311 | dev->vbi_height = 18; | ||
312 | |||
313 | em28xx_set_outfmt(dev); | ||
314 | |||
315 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | ||
316 | |||
317 | /* If we don't set the start position to 2 in VBI mode, we end up | ||
318 | with line 20/21 being YUYV encoded instead of being in 8-bit | ||
319 | greyscale. The core of the issue is that line 21 (and line 23 for | ||
320 | PAL WSS) are inside of active video region, and as a result they | ||
321 | get the pixelformatting associated with that area. So by cropping | ||
322 | it out, we end up with the same format as the rest of the VBI | ||
323 | region */ | ||
324 | if (em28xx_vbi_supported(dev) == 1) | ||
325 | em28xx_capture_area_set(dev, 0, 2, width, height); | ||
326 | else | ||
327 | em28xx_capture_area_set(dev, 0, 0, width, height); | ||
328 | |||
329 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | ||
330 | } | ||
331 | |||
332 | /* Set USB alternate setting for analog video */ | ||
333 | static int em28xx_set_alternate(struct em28xx *dev) | ||
334 | { | ||
335 | int errCode; | ||
336 | int i; | ||
337 | unsigned int min_pkt_size = dev->width * 2 + 4; | ||
338 | |||
339 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed | ||
340 | bulk transfers seem to work only with alt=0 ! */ | ||
341 | dev->alt = 0; | ||
342 | if ((alt > 0) && (alt < dev->num_alt)) { | ||
343 | em28xx_videodbg("alternate forced to %d\n", dev->alt); | ||
344 | dev->alt = alt; | ||
345 | goto set_alt; | ||
346 | } | ||
347 | if (dev->analog_xfer_bulk) | ||
348 | goto set_alt; | ||
349 | |||
350 | /* When image size is bigger than a certain value, | ||
351 | the frame size should be increased, otherwise, only | ||
352 | green screen will be received. | ||
353 | */ | ||
354 | if (dev->width * 2 * dev->height > 720 * 240 * 2) | ||
355 | min_pkt_size *= 2; | ||
356 | |||
357 | for (i = 0; i < dev->num_alt; i++) { | ||
358 | /* stop when the selected alt setting offers enough bandwidth */ | ||
359 | if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { | ||
360 | dev->alt = i; | ||
361 | break; | ||
362 | /* otherwise make sure that we end up with the maximum bandwidth | ||
363 | because the min_pkt_size equation might be wrong... | ||
364 | */ | ||
365 | } else if (dev->alt_max_pkt_size_isoc[i] > | ||
366 | dev->alt_max_pkt_size_isoc[dev->alt]) | ||
367 | dev->alt = i; | ||
368 | } | ||
369 | |||
370 | set_alt: | ||
371 | /* NOTE: for bulk transfers, we need to call usb_set_interface() | ||
372 | * even if the previous settings were the same. Otherwise streaming | ||
373 | * fails with all urbs having status = -EOVERFLOW ! */ | ||
374 | if (dev->analog_xfer_bulk) { | ||
375 | dev->max_pkt_size = 512; /* USB 2.0 spec */ | ||
376 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; | ||
377 | } else { /* isoc */ | ||
378 | em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n", | ||
379 | min_pkt_size, dev->alt); | ||
380 | dev->max_pkt_size = | ||
381 | dev->alt_max_pkt_size_isoc[dev->alt]; | ||
382 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; | ||
383 | } | ||
384 | em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", | ||
385 | dev->alt, dev->max_pkt_size); | ||
386 | errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); | ||
387 | if (errCode < 0) { | ||
388 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", | ||
389 | dev->alt, errCode); | ||
390 | return errCode; | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | |||
138 | /* ------------------------------------------------------------------ | 395 | /* ------------------------------------------------------------------ |
139 | DMA and thread functions | 396 | DMA and thread functions |
140 | ------------------------------------------------------------------*/ | 397 | ------------------------------------------------------------------*/ |
@@ -763,7 +1020,7 @@ static struct vb2_ops em28xx_video_qops = { | |||
763 | .wait_finish = vb2_ops_wait_finish, | 1020 | .wait_finish = vb2_ops_wait_finish, |
764 | }; | 1021 | }; |
765 | 1022 | ||
766 | int em28xx_vb2_setup(struct em28xx *dev) | 1023 | static int em28xx_vb2_setup(struct em28xx *dev) |
767 | { | 1024 | { |
768 | int rc; | 1025 | int rc; |
769 | struct vb2_queue *q; | 1026 | struct vb2_queue *q; |
@@ -831,7 +1088,7 @@ static void video_mux(struct em28xx *dev, int index) | |||
831 | em28xx_audio_analog_set(dev); | 1088 | em28xx_audio_analog_set(dev); |
832 | } | 1089 | } |
833 | 1090 | ||
834 | void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) | 1091 | static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) |
835 | { | 1092 | { |
836 | struct em28xx *dev = priv; | 1093 | struct em28xx *dev = priv; |
837 | 1094 | ||
@@ -890,7 +1147,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl) | |||
890 | return (ret < 0) ? ret : 0; | 1147 | return (ret < 0) ? ret : 0; |
891 | } | 1148 | } |
892 | 1149 | ||
893 | const struct v4l2_ctrl_ops em28xx_ctrl_ops = { | 1150 | static const struct v4l2_ctrl_ops em28xx_ctrl_ops = { |
894 | .s_ctrl = em28xx_s_ctrl, | 1151 | .s_ctrl = em28xx_s_ctrl, |
895 | }; | 1152 | }; |
896 | 1153 | ||
@@ -1368,7 +1625,7 @@ static int vidioc_g_register(struct file *file, void *priv, | |||
1368 | reg->val = ret; | 1625 | reg->val = ret; |
1369 | } else { | 1626 | } else { |
1370 | __le16 val = 0; | 1627 | __le16 val = 0; |
1371 | ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, | 1628 | ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, |
1372 | reg->reg, (char *)&val, 2); | 1629 | reg->reg, (char *)&val, 2); |
1373 | if (ret < 0) | 1630 | if (ret < 0) |
1374 | return ret; | 1631 | return ret; |
@@ -1570,6 +1827,10 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1570 | case VFL_TYPE_VBI: | 1827 | case VFL_TYPE_VBI: |
1571 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; | 1828 | fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; |
1572 | break; | 1829 | break; |
1830 | case VFL_TYPE_RADIO: | ||
1831 | break; | ||
1832 | default: | ||
1833 | return -EINVAL; | ||
1573 | } | 1834 | } |
1574 | 1835 | ||
1575 | em28xx_videodbg("open dev=%s type=%s users=%d\n", | 1836 | em28xx_videodbg("open dev=%s type=%s users=%d\n", |
@@ -1590,15 +1851,17 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1590 | fh->type = fh_type; | 1851 | fh->type = fh_type; |
1591 | filp->private_data = fh; | 1852 | filp->private_data = fh; |
1592 | 1853 | ||
1593 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { | 1854 | if (dev->users == 0) { |
1594 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); | 1855 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); |
1595 | em28xx_resolution_set(dev); | ||
1596 | 1856 | ||
1597 | /* Needed, since GPIO might have disabled power of | 1857 | if (vdev->vfl_type != VFL_TYPE_RADIO) |
1598 | some i2c device | 1858 | em28xx_resolution_set(dev); |
1859 | |||
1860 | /* | ||
1861 | * Needed, since GPIO might have disabled power | ||
1862 | * of some i2c devices | ||
1599 | */ | 1863 | */ |
1600 | em28xx_wake_i2c(dev); | 1864 | em28xx_wake_i2c(dev); |
1601 | |||
1602 | } | 1865 | } |
1603 | 1866 | ||
1604 | if (vdev->vfl_type == VFL_TYPE_RADIO) { | 1867 | if (vdev->vfl_type == VFL_TYPE_RADIO) { |
@@ -1615,40 +1878,59 @@ static int em28xx_v4l2_open(struct file *filp) | |||
1615 | } | 1878 | } |
1616 | 1879 | ||
1617 | /* | 1880 | /* |
1618 | * em28xx_realease_resources() | 1881 | * em28xx_v4l2_fini() |
1619 | * unregisters the v4l2,i2c and usb devices | 1882 | * unregisters the v4l2,i2c and usb devices |
1620 | * called when the device gets disconected or at module unload | 1883 | * called when the device gets disconected or at module unload |
1621 | */ | 1884 | */ |
1622 | void em28xx_release_analog_resources(struct em28xx *dev) | 1885 | static int em28xx_v4l2_fini(struct em28xx *dev) |
1623 | { | 1886 | { |
1887 | if (dev->is_audio_only) { | ||
1888 | /* Shouldn't initialize IR for this interface */ | ||
1889 | return 0; | ||
1890 | } | ||
1891 | |||
1892 | if (!dev->has_video) { | ||
1893 | /* This device does not support the v4l2 extension */ | ||
1894 | return 0; | ||
1895 | } | ||
1624 | 1896 | ||
1625 | /*FIXME: I2C IR should be disconnected */ | 1897 | em28xx_info("Closing video extension"); |
1898 | |||
1899 | mutex_lock(&dev->lock); | ||
1900 | |||
1901 | v4l2_device_disconnect(&dev->v4l2_dev); | ||
1902 | |||
1903 | em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); | ||
1626 | 1904 | ||
1627 | if (dev->radio_dev) { | 1905 | if (dev->radio_dev) { |
1628 | if (video_is_registered(dev->radio_dev)) | 1906 | em28xx_info("V4L2 device %s deregistered\n", |
1629 | video_unregister_device(dev->radio_dev); | 1907 | video_device_node_name(dev->radio_dev)); |
1630 | else | 1908 | video_unregister_device(dev->radio_dev); |
1631 | video_device_release(dev->radio_dev); | ||
1632 | dev->radio_dev = NULL; | ||
1633 | } | 1909 | } |
1634 | if (dev->vbi_dev) { | 1910 | if (dev->vbi_dev) { |
1635 | em28xx_info("V4L2 device %s deregistered\n", | 1911 | em28xx_info("V4L2 device %s deregistered\n", |
1636 | video_device_node_name(dev->vbi_dev)); | 1912 | video_device_node_name(dev->vbi_dev)); |
1637 | if (video_is_registered(dev->vbi_dev)) | 1913 | video_unregister_device(dev->vbi_dev); |
1638 | video_unregister_device(dev->vbi_dev); | ||
1639 | else | ||
1640 | video_device_release(dev->vbi_dev); | ||
1641 | dev->vbi_dev = NULL; | ||
1642 | } | 1914 | } |
1643 | if (dev->vdev) { | 1915 | if (dev->vdev) { |
1644 | em28xx_info("V4L2 device %s deregistered\n", | 1916 | em28xx_info("V4L2 device %s deregistered\n", |
1645 | video_device_node_name(dev->vdev)); | 1917 | video_device_node_name(dev->vdev)); |
1646 | if (video_is_registered(dev->vdev)) | 1918 | video_unregister_device(dev->vdev); |
1647 | video_unregister_device(dev->vdev); | ||
1648 | else | ||
1649 | video_device_release(dev->vdev); | ||
1650 | dev->vdev = NULL; | ||
1651 | } | 1919 | } |
1920 | |||
1921 | if (dev->clk) { | ||
1922 | v4l2_clk_unregister_fixed(dev->clk); | ||
1923 | dev->clk = NULL; | ||
1924 | } | ||
1925 | |||
1926 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
1927 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1928 | |||
1929 | if (dev->users) | ||
1930 | em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n"); | ||
1931 | mutex_unlock(&dev->lock); | ||
1932 | |||
1933 | return 0; | ||
1652 | } | 1934 | } |
1653 | 1935 | ||
1654 | /* | 1936 | /* |
@@ -1668,14 +1950,10 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1668 | mutex_lock(&dev->lock); | 1950 | mutex_lock(&dev->lock); |
1669 | 1951 | ||
1670 | if (dev->users == 1) { | 1952 | if (dev->users == 1) { |
1671 | /* the device is already disconnect, | 1953 | /* free the remaining resources if device is disconnected */ |
1672 | free the remaining resources */ | ||
1673 | if (dev->disconnected) { | 1954 | if (dev->disconnected) { |
1674 | em28xx_release_resources(dev); | ||
1675 | kfree(dev->alt_max_pkt_size_isoc); | 1955 | kfree(dev->alt_max_pkt_size_isoc); |
1676 | mutex_unlock(&dev->lock); | 1956 | goto exit; |
1677 | kfree(dev); | ||
1678 | return 0; | ||
1679 | } | 1957 | } |
1680 | 1958 | ||
1681 | /* Save some power by putting tuner to sleep */ | 1959 | /* Save some power by putting tuner to sleep */ |
@@ -1694,11 +1972,29 @@ static int em28xx_v4l2_close(struct file *filp) | |||
1694 | } | 1972 | } |
1695 | } | 1973 | } |
1696 | 1974 | ||
1975 | exit: | ||
1697 | dev->users--; | 1976 | dev->users--; |
1698 | mutex_unlock(&dev->lock); | 1977 | mutex_unlock(&dev->lock); |
1699 | return 0; | 1978 | return 0; |
1700 | } | 1979 | } |
1701 | 1980 | ||
1981 | /* | ||
1982 | * em28xx_videodevice_release() | ||
1983 | * called when the last user of the video device exits and frees the memeory | ||
1984 | */ | ||
1985 | static void em28xx_videodevice_release(struct video_device *vdev) | ||
1986 | { | ||
1987 | struct em28xx *dev = video_get_drvdata(vdev); | ||
1988 | |||
1989 | video_device_release(vdev); | ||
1990 | if (vdev == dev->vdev) | ||
1991 | dev->vdev = NULL; | ||
1992 | else if (vdev == dev->vbi_dev) | ||
1993 | dev->vbi_dev = NULL; | ||
1994 | else if (vdev == dev->radio_dev) | ||
1995 | dev->radio_dev = NULL; | ||
1996 | } | ||
1997 | |||
1702 | static const struct v4l2_file_operations em28xx_v4l_fops = { | 1998 | static const struct v4l2_file_operations em28xx_v4l_fops = { |
1703 | .owner = THIS_MODULE, | 1999 | .owner = THIS_MODULE, |
1704 | .open = em28xx_v4l2_open, | 2000 | .open = em28xx_v4l2_open, |
@@ -1753,11 +2049,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1753 | }; | 2049 | }; |
1754 | 2050 | ||
1755 | static const struct video_device em28xx_video_template = { | 2051 | static const struct video_device em28xx_video_template = { |
1756 | .fops = &em28xx_v4l_fops, | 2052 | .fops = &em28xx_v4l_fops, |
1757 | .release = video_device_release_empty, | 2053 | .ioctl_ops = &video_ioctl_ops, |
1758 | .ioctl_ops = &video_ioctl_ops, | 2054 | .release = em28xx_videodevice_release, |
1759 | 2055 | .tvnorms = V4L2_STD_ALL, | |
1760 | .tvnorms = V4L2_STD_ALL, | ||
1761 | }; | 2056 | }; |
1762 | 2057 | ||
1763 | static const struct v4l2_file_operations radio_fops = { | 2058 | static const struct v4l2_file_operations radio_fops = { |
@@ -1783,14 +2078,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { | |||
1783 | }; | 2078 | }; |
1784 | 2079 | ||
1785 | static struct video_device em28xx_radio_template = { | 2080 | static struct video_device em28xx_radio_template = { |
1786 | .name = "em28xx-radio", | 2081 | .fops = &radio_fops, |
1787 | .fops = &radio_fops, | 2082 | .ioctl_ops = &radio_ioctl_ops, |
1788 | .ioctl_ops = &radio_ioctl_ops, | 2083 | .release = em28xx_videodevice_release, |
1789 | }; | 2084 | }; |
1790 | 2085 | ||
1791 | /******************************** usb interface ******************************/ | 2086 | /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ |
2087 | static unsigned short saa711x_addrs[] = { | ||
2088 | 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ | ||
2089 | 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ | ||
2090 | I2C_CLIENT_END }; | ||
1792 | 2091 | ||
2092 | static unsigned short tvp5150_addrs[] = { | ||
2093 | 0xb8 >> 1, | ||
2094 | 0xba >> 1, | ||
2095 | I2C_CLIENT_END | ||
2096 | }; | ||
1793 | 2097 | ||
2098 | static unsigned short msp3400_addrs[] = { | ||
2099 | 0x80 >> 1, | ||
2100 | 0x88 >> 1, | ||
2101 | I2C_CLIENT_END | ||
2102 | }; | ||
2103 | |||
2104 | /******************************** usb interface ******************************/ | ||
1794 | 2105 | ||
1795 | static struct video_device *em28xx_vdev_init(struct em28xx *dev, | 2106 | static struct video_device *em28xx_vdev_init(struct em28xx *dev, |
1796 | const struct video_device *template, | 2107 | const struct video_device *template, |
@@ -1817,14 +2128,198 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, | |||
1817 | return vfd; | 2128 | return vfd; |
1818 | } | 2129 | } |
1819 | 2130 | ||
1820 | int em28xx_register_analog_devices(struct em28xx *dev) | 2131 | static void em28xx_tuner_setup(struct em28xx *dev) |
2132 | { | ||
2133 | struct tuner_setup tun_setup; | ||
2134 | struct v4l2_frequency f; | ||
2135 | |||
2136 | if (dev->tuner_type == TUNER_ABSENT) | ||
2137 | return; | ||
2138 | |||
2139 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
2140 | |||
2141 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
2142 | tun_setup.tuner_callback = em28xx_tuner_callback; | ||
2143 | |||
2144 | if (dev->board.radio.type) { | ||
2145 | tun_setup.type = dev->board.radio.type; | ||
2146 | tun_setup.addr = dev->board.radio_addr; | ||
2147 | |||
2148 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2149 | } | ||
2150 | |||
2151 | if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { | ||
2152 | tun_setup.type = dev->tuner_type; | ||
2153 | tun_setup.addr = dev->tuner_addr; | ||
2154 | |||
2155 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); | ||
2156 | } | ||
2157 | |||
2158 | if (dev->tda9887_conf) { | ||
2159 | struct v4l2_priv_tun_config tda9887_cfg; | ||
2160 | |||
2161 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
2162 | tda9887_cfg.priv = &dev->tda9887_conf; | ||
2163 | |||
2164 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); | ||
2165 | } | ||
2166 | |||
2167 | if (dev->tuner_type == TUNER_XC2028) { | ||
2168 | struct v4l2_priv_tun_config xc2028_cfg; | ||
2169 | struct xc2028_ctrl ctl; | ||
2170 | |||
2171 | memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); | ||
2172 | memset(&ctl, 0, sizeof(ctl)); | ||
2173 | |||
2174 | em28xx_setup_xc3028(dev, &ctl); | ||
2175 | |||
2176 | xc2028_cfg.tuner = TUNER_XC2028; | ||
2177 | xc2028_cfg.priv = &ctl; | ||
2178 | |||
2179 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); | ||
2180 | } | ||
2181 | |||
2182 | /* configure tuner */ | ||
2183 | f.tuner = 0; | ||
2184 | f.type = V4L2_TUNER_ANALOG_TV; | ||
2185 | f.frequency = 9076; /* just a magic number */ | ||
2186 | dev->ctl_freq = f.frequency; | ||
2187 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); | ||
2188 | } | ||
2189 | |||
2190 | static int em28xx_v4l2_init(struct em28xx *dev) | ||
1821 | { | 2191 | { |
1822 | u8 val; | 2192 | u8 val; |
1823 | int ret; | 2193 | int ret; |
1824 | unsigned int maxw; | 2194 | unsigned int maxw; |
2195 | struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; | ||
2196 | |||
2197 | if (dev->is_audio_only) { | ||
2198 | /* Shouldn't initialize IR for this interface */ | ||
2199 | return 0; | ||
2200 | } | ||
2201 | |||
2202 | if (!dev->has_video) { | ||
2203 | /* This device does not support the v4l2 extension */ | ||
2204 | return 0; | ||
2205 | } | ||
2206 | |||
2207 | em28xx_info("Registering V4L2 extension\n"); | ||
2208 | |||
2209 | mutex_lock(&dev->lock); | ||
2210 | |||
2211 | ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); | ||
2212 | if (ret < 0) { | ||
2213 | em28xx_errdev("Call to v4l2_device_register() failed!\n"); | ||
2214 | goto err; | ||
2215 | } | ||
2216 | |||
2217 | v4l2_ctrl_handler_init(hdl, 8); | ||
2218 | dev->v4l2_dev.ctrl_handler = hdl; | ||
2219 | |||
2220 | /* | ||
2221 | * Default format, used for tvp5150 or saa711x output formats | ||
2222 | */ | ||
2223 | dev->vinmode = 0x10; | ||
2224 | dev->vinctl = EM28XX_VINCTRL_INTERLACED | | ||
2225 | EM28XX_VINCTRL_CCIR656_ENABLE; | ||
2226 | |||
2227 | /* request some modules */ | ||
2228 | |||
2229 | if (dev->board.has_msp34xx) | ||
2230 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2231 | "msp3400", 0, msp3400_addrs); | ||
2232 | |||
2233 | if (dev->board.decoder == EM28XX_SAA711X) | ||
2234 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2235 | "saa7115_auto", 0, saa711x_addrs); | ||
2236 | |||
2237 | if (dev->board.decoder == EM28XX_TVP5150) | ||
2238 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2239 | "tvp5150", 0, tvp5150_addrs); | ||
2240 | |||
2241 | if (dev->board.adecoder == EM28XX_TVAUDIO) | ||
2242 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2243 | "tvaudio", dev->board.tvaudio_addr, NULL); | ||
2244 | |||
2245 | /* Initialize tuner and camera */ | ||
2246 | |||
2247 | if (dev->board.tuner_type != TUNER_ABSENT) { | ||
2248 | int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); | ||
2249 | |||
2250 | if (dev->board.radio.type) | ||
2251 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2252 | "tuner", dev->board.radio_addr, NULL); | ||
2253 | |||
2254 | if (has_demod) | ||
2255 | v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2256 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2257 | 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); | ||
2258 | if (dev->tuner_addr == 0) { | ||
2259 | enum v4l2_i2c_tuner_type type = | ||
2260 | has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; | ||
2261 | struct v4l2_subdev *sd; | ||
2262 | |||
2263 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, | ||
2264 | &dev->i2c_adap[dev->def_i2c_bus], "tuner", | ||
2265 | 0, v4l2_i2c_tuner_addrs(type)); | ||
2266 | |||
2267 | if (sd) | ||
2268 | dev->tuner_addr = v4l2_i2c_subdev_addr(sd); | ||
2269 | } else { | ||
2270 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], | ||
2271 | "tuner", dev->tuner_addr, NULL); | ||
2272 | } | ||
2273 | } | ||
2274 | |||
2275 | em28xx_tuner_setup(dev); | ||
2276 | em28xx_init_camera(dev); | ||
2277 | |||
2278 | /* Configure audio */ | ||
2279 | ret = em28xx_audio_setup(dev); | ||
2280 | if (ret < 0) { | ||
2281 | em28xx_errdev("%s: Error while setting audio - error [%d]!\n", | ||
2282 | __func__, ret); | ||
2283 | goto unregister_dev; | ||
2284 | } | ||
2285 | if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { | ||
2286 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
2287 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
2288 | v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, | ||
2289 | V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f); | ||
2290 | } else { | ||
2291 | /* install the em28xx notify callback */ | ||
2292 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE), | ||
2293 | em28xx_ctrl_notify, dev); | ||
2294 | v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME), | ||
2295 | em28xx_ctrl_notify, dev); | ||
2296 | } | ||
2297 | |||
2298 | /* wake i2c devices */ | ||
2299 | em28xx_wake_i2c(dev); | ||
2300 | |||
2301 | /* init video dma queues */ | ||
2302 | INIT_LIST_HEAD(&dev->vidq.active); | ||
2303 | INIT_LIST_HEAD(&dev->vbiq.active); | ||
1825 | 2304 | ||
1826 | printk(KERN_INFO "%s: v4l2 driver version %s\n", | 2305 | if (dev->board.has_msp34xx) { |
1827 | dev->name, EM28XX_VERSION); | 2306 | /* Send a reset to other chips via gpio */ |
2307 | ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); | ||
2308 | if (ret < 0) { | ||
2309 | em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", | ||
2310 | __func__, ret); | ||
2311 | goto unregister_dev; | ||
2312 | } | ||
2313 | msleep(3); | ||
2314 | |||
2315 | ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); | ||
2316 | if (ret < 0) { | ||
2317 | em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", | ||
2318 | __func__, ret); | ||
2319 | goto unregister_dev; | ||
2320 | } | ||
2321 | msleep(3); | ||
2322 | } | ||
1828 | 2323 | ||
1829 | /* set default norm */ | 2324 | /* set default norm */ |
1830 | dev->norm = V4L2_STD_PAL; | 2325 | dev->norm = V4L2_STD_PAL; |
@@ -1888,14 +2383,16 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1888 | /* Reset image controls */ | 2383 | /* Reset image controls */ |
1889 | em28xx_colorlevels_set_default(dev); | 2384 | em28xx_colorlevels_set_default(dev); |
1890 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); | 2385 | v4l2_ctrl_handler_setup(&dev->ctrl_handler); |
1891 | if (dev->ctrl_handler.error) | 2386 | ret = dev->ctrl_handler.error; |
1892 | return dev->ctrl_handler.error; | 2387 | if (ret) |
2388 | goto unregister_dev; | ||
1893 | 2389 | ||
1894 | /* allocate and fill video video_device struct */ | 2390 | /* allocate and fill video video_device struct */ |
1895 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); | 2391 | dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); |
1896 | if (!dev->vdev) { | 2392 | if (!dev->vdev) { |
1897 | em28xx_errdev("cannot allocate video_device.\n"); | 2393 | em28xx_errdev("cannot allocate video_device.\n"); |
1898 | return -ENODEV; | 2394 | ret = -ENODEV; |
2395 | goto unregister_dev; | ||
1899 | } | 2396 | } |
1900 | dev->vdev->queue = &dev->vb_vidq; | 2397 | dev->vdev->queue = &dev->vb_vidq; |
1901 | dev->vdev->queue->lock = &dev->vb_queue_lock; | 2398 | dev->vdev->queue->lock = &dev->vb_queue_lock; |
@@ -1925,7 +2422,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1925 | if (ret) { | 2422 | if (ret) { |
1926 | em28xx_errdev("unable to register video device (error=%i).\n", | 2423 | em28xx_errdev("unable to register video device (error=%i).\n", |
1927 | ret); | 2424 | ret); |
1928 | return ret; | 2425 | goto unregister_dev; |
1929 | } | 2426 | } |
1930 | 2427 | ||
1931 | /* Allocate and fill vbi video_device struct */ | 2428 | /* Allocate and fill vbi video_device struct */ |
@@ -1954,7 +2451,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1954 | vbi_nr[dev->devno]); | 2451 | vbi_nr[dev->devno]); |
1955 | if (ret < 0) { | 2452 | if (ret < 0) { |
1956 | em28xx_errdev("unable to register vbi device\n"); | 2453 | em28xx_errdev("unable to register vbi device\n"); |
1957 | return ret; | 2454 | goto unregister_dev; |
1958 | } | 2455 | } |
1959 | } | 2456 | } |
1960 | 2457 | ||
@@ -1963,13 +2460,14 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1963 | "radio"); | 2460 | "radio"); |
1964 | if (!dev->radio_dev) { | 2461 | if (!dev->radio_dev) { |
1965 | em28xx_errdev("cannot allocate video_device.\n"); | 2462 | em28xx_errdev("cannot allocate video_device.\n"); |
1966 | return -ENODEV; | 2463 | ret = -ENODEV; |
2464 | goto unregister_dev; | ||
1967 | } | 2465 | } |
1968 | ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, | 2466 | ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, |
1969 | radio_nr[dev->devno]); | 2467 | radio_nr[dev->devno]); |
1970 | if (ret < 0) { | 2468 | if (ret < 0) { |
1971 | em28xx_errdev("can't register radio device\n"); | 2469 | em28xx_errdev("can't register radio device\n"); |
1972 | return ret; | 2470 | goto unregister_dev; |
1973 | } | 2471 | } |
1974 | em28xx_info("Registered radio device as %s\n", | 2472 | em28xx_info("Registered radio device as %s\n", |
1975 | video_device_node_name(dev->radio_dev)); | 2473 | video_device_node_name(dev->radio_dev)); |
@@ -1982,5 +2480,41 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
1982 | em28xx_info("V4L2 VBI device registered as %s\n", | 2480 | em28xx_info("V4L2 VBI device registered as %s\n", |
1983 | video_device_node_name(dev->vbi_dev)); | 2481 | video_device_node_name(dev->vbi_dev)); |
1984 | 2482 | ||
2483 | /* Save some power by putting tuner to sleep */ | ||
2484 | v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); | ||
2485 | |||
2486 | /* initialize videobuf2 stuff */ | ||
2487 | em28xx_vb2_setup(dev); | ||
2488 | |||
2489 | em28xx_info("V4L2 extension successfully initialized\n"); | ||
2490 | |||
2491 | mutex_unlock(&dev->lock); | ||
1985 | return 0; | 2492 | return 0; |
2493 | |||
2494 | unregister_dev: | ||
2495 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
2496 | v4l2_device_unregister(&dev->v4l2_dev); | ||
2497 | err: | ||
2498 | mutex_unlock(&dev->lock); | ||
2499 | return ret; | ||
2500 | } | ||
2501 | |||
2502 | static struct em28xx_ops v4l2_ops = { | ||
2503 | .id = EM28XX_V4L2, | ||
2504 | .name = "Em28xx v4l2 Extension", | ||
2505 | .init = em28xx_v4l2_init, | ||
2506 | .fini = em28xx_v4l2_fini, | ||
2507 | }; | ||
2508 | |||
2509 | static int __init em28xx_video_register(void) | ||
2510 | { | ||
2511 | return em28xx_register_extension(&v4l2_ops); | ||
2512 | } | ||
2513 | |||
2514 | static void __exit em28xx_video_unregister(void) | ||
2515 | { | ||
2516 | em28xx_unregister_extension(&v4l2_ops); | ||
1986 | } | 2517 | } |
2518 | |||
2519 | module_init(em28xx_video_register); | ||
2520 | module_exit(em28xx_video_unregister); | ||