1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Driver for the Auvitek USB bridge |
4 | * |
5 | * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> |
6 | */ |
7 | |
8 | #include "au0828.h" |
9 | #include "au8522.h" |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/videodev2.h> |
14 | #include <media/v4l2-common.h> |
15 | #include <linux/mutex.h> |
16 | |
17 | /* Due to enum tuner_pad_index */ |
18 | #include <media/tuner.h> |
19 | |
20 | /* |
21 | * 1 = General debug messages |
22 | * 2 = USB handling |
23 | * 4 = I2C related |
24 | * 8 = Bridge related |
25 | * 16 = IR related |
26 | */ |
27 | int au0828_debug; |
28 | module_param_named(debug, au0828_debug, int, 0644); |
29 | MODULE_PARM_DESC(debug, |
30 | "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR" ); |
31 | |
32 | static unsigned int disable_usb_speed_check; |
33 | module_param(disable_usb_speed_check, int, 0444); |
34 | MODULE_PARM_DESC(disable_usb_speed_check, |
35 | "override min bandwidth requirement of 480M bps" ); |
36 | |
37 | #define _AU0828_BULKPIPE 0x03 |
38 | #define _BULKPIPESIZE 0xffff |
39 | |
40 | static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, |
41 | u16 index); |
42 | static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, |
43 | u16 index, unsigned char *cp, u16 size); |
44 | |
45 | /* USB Direction */ |
46 | #define CMD_REQUEST_IN 0x00 |
47 | #define CMD_REQUEST_OUT 0x01 |
48 | |
49 | u32 au0828_readreg(struct au0828_dev *dev, u16 reg) |
50 | { |
51 | u8 result = 0; |
52 | |
53 | recv_control_msg(dev, CMD_REQUEST_IN, value: 0, index: reg, cp: &result, size: 1); |
54 | dprintk(8, "%s(0x%04x) = 0x%02x\n" , __func__, reg, result); |
55 | |
56 | return result; |
57 | } |
58 | |
59 | u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val) |
60 | { |
61 | dprintk(8, "%s(0x%04x, 0x%02x)\n" , __func__, reg, val); |
62 | return send_control_msg(dev, CMD_REQUEST_OUT, value: val, index: reg); |
63 | } |
64 | |
65 | static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, |
66 | u16 index) |
67 | { |
68 | int status = -ENODEV; |
69 | |
70 | if (dev->usbdev) { |
71 | |
72 | /* cp must be memory that has been allocated by kmalloc */ |
73 | status = usb_control_msg(dev: dev->usbdev, |
74 | usb_sndctrlpipe(dev->usbdev, 0), |
75 | request, |
76 | USB_DIR_OUT | USB_TYPE_VENDOR | |
77 | USB_RECIP_DEVICE, |
78 | value, index, NULL, size: 0, timeout: 1000); |
79 | |
80 | status = min(status, 0); |
81 | |
82 | if (status < 0) { |
83 | pr_err("%s() Failed sending control message, error %d.\n" , |
84 | __func__, status); |
85 | } |
86 | |
87 | } |
88 | |
89 | return status; |
90 | } |
91 | |
92 | static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, |
93 | u16 index, unsigned char *cp, u16 size) |
94 | { |
95 | int status = -ENODEV; |
96 | mutex_lock(&dev->mutex); |
97 | if (dev->usbdev) { |
98 | status = usb_control_msg(dev: dev->usbdev, |
99 | usb_rcvctrlpipe(dev->usbdev, 0), |
100 | request, |
101 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
102 | value, index, |
103 | data: dev->ctrlmsg, size, timeout: 1000); |
104 | |
105 | status = min(status, 0); |
106 | |
107 | if (status < 0) { |
108 | pr_err("%s() Failed receiving control message, error %d.\n" , |
109 | __func__, status); |
110 | } |
111 | |
112 | /* the host controller requires heap allocated memory, which |
113 | is why we didn't just pass "cp" into usb_control_msg */ |
114 | memcpy(cp, dev->ctrlmsg, size); |
115 | } |
116 | mutex_unlock(lock: &dev->mutex); |
117 | return status; |
118 | } |
119 | |
120 | #ifdef CONFIG_MEDIA_CONTROLLER |
121 | static void au0828_media_graph_notify(struct media_entity *new, |
122 | void *notify_data); |
123 | #endif |
124 | |
125 | static void au0828_unregister_media_device(struct au0828_dev *dev) |
126 | { |
127 | #ifdef CONFIG_MEDIA_CONTROLLER |
128 | struct media_device *mdev = dev->media_dev; |
129 | struct media_entity_notify *notify, *nextp; |
130 | |
131 | if (!mdev || !media_devnode_is_registered(devnode: mdev->devnode)) |
132 | return; |
133 | |
134 | /* Remove au0828 entity_notify callbacks */ |
135 | list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) { |
136 | if (notify->notify != au0828_media_graph_notify) |
137 | continue; |
138 | media_device_unregister_entity_notify(mdev, nptr: notify); |
139 | } |
140 | |
141 | /* clear enable_source, disable_source */ |
142 | mutex_lock(&mdev->graph_mutex); |
143 | dev->media_dev->source_priv = NULL; |
144 | dev->media_dev->enable_source = NULL; |
145 | dev->media_dev->disable_source = NULL; |
146 | mutex_unlock(lock: &mdev->graph_mutex); |
147 | |
148 | media_device_delete(mdev: dev->media_dev, KBUILD_MODNAME, THIS_MODULE); |
149 | dev->media_dev = NULL; |
150 | #endif |
151 | } |
152 | |
153 | void au0828_usb_release(struct au0828_dev *dev) |
154 | { |
155 | au0828_unregister_media_device(dev); |
156 | |
157 | /* I2C */ |
158 | au0828_i2c_unregister(dev); |
159 | |
160 | kfree(objp: dev); |
161 | } |
162 | |
163 | static void au0828_usb_disconnect(struct usb_interface *interface) |
164 | { |
165 | struct au0828_dev *dev = usb_get_intfdata(intf: interface); |
166 | |
167 | dprintk(1, "%s()\n" , __func__); |
168 | |
169 | /* there is a small window after disconnect, before |
170 | dev->usbdev is NULL, for poll (e.g: IR) try to access |
171 | the device and fill the dmesg with error messages. |
172 | Set the status so poll routines can check and avoid |
173 | access after disconnect. |
174 | */ |
175 | set_bit(nr: DEV_DISCONNECTED, addr: &dev->dev_state); |
176 | |
177 | au0828_rc_unregister(dev); |
178 | /* Digital TV */ |
179 | au0828_dvb_unregister(dev); |
180 | |
181 | usb_set_intfdata(intf: interface, NULL); |
182 | mutex_lock(&dev->mutex); |
183 | dev->usbdev = NULL; |
184 | mutex_unlock(lock: &dev->mutex); |
185 | if (au0828_analog_unregister(dev)) { |
186 | /* |
187 | * No need to call au0828_usb_release() if V4L2 is enabled, |
188 | * as this is already called via au0828_usb_v4l2_release() |
189 | */ |
190 | return; |
191 | } |
192 | au0828_usb_release(dev); |
193 | } |
194 | |
195 | static int au0828_media_device_init(struct au0828_dev *dev, |
196 | struct usb_device *udev) |
197 | { |
198 | #ifdef CONFIG_MEDIA_CONTROLLER |
199 | struct media_device *mdev; |
200 | |
201 | mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE); |
202 | if (IS_ERR(ptr: mdev)) |
203 | return PTR_ERR(ptr: mdev); |
204 | |
205 | dev->media_dev = mdev; |
206 | #endif |
207 | return 0; |
208 | } |
209 | |
210 | #ifdef CONFIG_MEDIA_CONTROLLER |
211 | static void au0828_media_graph_notify(struct media_entity *new, |
212 | void *notify_data) |
213 | { |
214 | struct au0828_dev *dev = notify_data; |
215 | int ret; |
216 | struct media_entity *entity, *mixer = NULL, *decoder = NULL; |
217 | |
218 | if (!new) { |
219 | /* |
220 | * Called during au0828 probe time to connect |
221 | * entities that were created prior to registering |
222 | * the notify handler. Find mixer and decoder. |
223 | */ |
224 | media_device_for_each_entity(entity, dev->media_dev) { |
225 | if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) |
226 | mixer = entity; |
227 | else if (entity->function == MEDIA_ENT_F_ATV_DECODER) |
228 | decoder = entity; |
229 | } |
230 | goto create_link; |
231 | } |
232 | |
233 | switch (new->function) { |
234 | case MEDIA_ENT_F_AUDIO_MIXER: |
235 | mixer = new; |
236 | if (dev->decoder) |
237 | decoder = dev->decoder; |
238 | break; |
239 | case MEDIA_ENT_F_ATV_DECODER: |
240 | /* In case, Mixer is added first, find mixer and create link */ |
241 | media_device_for_each_entity(entity, dev->media_dev) { |
242 | if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) |
243 | mixer = entity; |
244 | } |
245 | decoder = new; |
246 | break; |
247 | default: |
248 | break; |
249 | } |
250 | |
251 | create_link: |
252 | if (decoder && mixer) { |
253 | ret = media_get_pad_index(entity: decoder, MEDIA_PAD_FL_SOURCE, |
254 | sig_type: PAD_SIGNAL_AUDIO); |
255 | if (ret >= 0) |
256 | ret = media_create_pad_link(source: decoder, source_pad: ret, |
257 | sink: mixer, sink_pad: 0, |
258 | MEDIA_LNK_FL_ENABLED); |
259 | if (ret < 0) |
260 | dev_err(&dev->usbdev->dev, |
261 | "Mixer Pad Link Create Error: %d\n" , ret); |
262 | } |
263 | } |
264 | |
265 | static bool au0828_is_link_shareable(struct media_entity *owner, |
266 | struct media_entity *entity) |
267 | { |
268 | bool shareable = false; |
269 | |
270 | /* Tuner link can be shared by audio, video, and VBI */ |
271 | switch (owner->function) { |
272 | case MEDIA_ENT_F_IO_V4L: |
273 | case MEDIA_ENT_F_AUDIO_CAPTURE: |
274 | case MEDIA_ENT_F_IO_VBI: |
275 | if (entity->function == MEDIA_ENT_F_IO_V4L || |
276 | entity->function == MEDIA_ENT_F_AUDIO_CAPTURE || |
277 | entity->function == MEDIA_ENT_F_IO_VBI) |
278 | shareable = true; |
279 | break; |
280 | case MEDIA_ENT_F_DTV_DEMOD: |
281 | default: |
282 | break; |
283 | } |
284 | return shareable; |
285 | } |
286 | |
287 | /* Callers should hold graph_mutex */ |
288 | static int au0828_enable_source(struct media_entity *entity, |
289 | struct media_pipeline *pipe) |
290 | { |
291 | struct media_entity *source, *find_source; |
292 | struct media_entity *sink; |
293 | struct media_link *link, *found_link = NULL; |
294 | int ret = 0; |
295 | struct media_device *mdev = entity->graph_obj.mdev; |
296 | struct au0828_dev *dev; |
297 | |
298 | if (!mdev) |
299 | return -ENODEV; |
300 | |
301 | dev = mdev->source_priv; |
302 | |
303 | /* |
304 | * For Audio and V4L2 entity, find the link to which decoder |
305 | * is the sink. Look for an active link between decoder and |
306 | * source (tuner/s-video/Composite), if one exists, nothing |
307 | * to do. If not, look for any active links between source |
308 | * and any other entity. If one exists, source is busy. If |
309 | * source is free, setup link and start pipeline from source. |
310 | * For DVB FE entity, the source for the link is the tuner. |
311 | * Check if tuner is available and setup link and start |
312 | * pipeline. |
313 | */ |
314 | if (entity->function == MEDIA_ENT_F_DTV_DEMOD) { |
315 | sink = entity; |
316 | find_source = dev->tuner; |
317 | } else { |
318 | /* Analog isn't configured or register failed */ |
319 | if (!dev->decoder) { |
320 | ret = -ENODEV; |
321 | goto end; |
322 | } |
323 | |
324 | sink = dev->decoder; |
325 | |
326 | /* |
327 | * Default input is tuner and default input_type |
328 | * is AU0828_VMUX_TELEVISION. |
329 | * |
330 | * There is a problem when s_input is called to |
331 | * change the default input. s_input will try to |
332 | * enable_source before attempting to change the |
333 | * input on the device, and will end up enabling |
334 | * default source which is tuner. |
335 | * |
336 | * Additional logic is necessary in au0828 to detect |
337 | * that the input has changed and enable the right |
338 | * source. au0828 handles this case in its s_input. |
339 | * It will disable the old source and enable the new |
340 | * source. |
341 | * |
342 | */ |
343 | if (dev->input_type == AU0828_VMUX_TELEVISION) |
344 | find_source = dev->tuner; |
345 | else if (dev->input_type == AU0828_VMUX_SVIDEO || |
346 | dev->input_type == AU0828_VMUX_COMPOSITE) |
347 | find_source = &dev->input_ent[dev->input_type]; |
348 | else { |
349 | /* unknown input - let user select input */ |
350 | ret = 0; |
351 | goto end; |
352 | } |
353 | } |
354 | |
355 | /* Is there an active link between sink and source */ |
356 | if (dev->active_link) { |
357 | if (dev->active_link_owner == entity) { |
358 | /* This check is necessary to handle multiple |
359 | * enable_source calls from v4l_ioctls during |
360 | * the course of video/vbi application run-time. |
361 | */ |
362 | pr_debug("%s already owns the tuner\n" , entity->name); |
363 | ret = 0; |
364 | goto end; |
365 | } else if (au0828_is_link_shareable(owner: dev->active_link_owner, |
366 | entity)) { |
367 | /* Either ALSA or Video own tuner. Sink is the same |
368 | * for both. Allow sharing the active link between |
369 | * their common source (tuner) and sink (decoder). |
370 | * Starting pipeline between sharing entity and sink |
371 | * will fail with pipe mismatch, while owner has an |
372 | * active pipeline. Switch pipeline ownership from |
373 | * user to owner when owner disables the source. |
374 | */ |
375 | dev->active_link_shared = true; |
376 | /* save the user info to use from disable */ |
377 | dev->active_link_user = entity; |
378 | dev->active_link_user_pipe = pipe; |
379 | pr_debug("%s owns the tuner %s can share!\n" , |
380 | dev->active_link_owner->name, |
381 | entity->name); |
382 | ret = 0; |
383 | goto end; |
384 | } else { |
385 | ret = -EBUSY; |
386 | goto end; |
387 | } |
388 | } |
389 | |
390 | list_for_each_entry(link, &sink->links, list) { |
391 | /* Check sink, and source */ |
392 | if (link->sink->entity == sink && |
393 | link->source->entity == find_source) { |
394 | found_link = link; |
395 | break; |
396 | } |
397 | } |
398 | |
399 | if (!found_link) { |
400 | ret = -ENODEV; |
401 | goto end; |
402 | } |
403 | |
404 | /* activate link between source and sink and start pipeline */ |
405 | source = found_link->source->entity; |
406 | ret = __media_entity_setup_link(link: found_link, MEDIA_LNK_FL_ENABLED); |
407 | if (ret) { |
408 | pr_err("Activate link from %s->%s. Error %d\n" , |
409 | source->name, sink->name, ret); |
410 | goto end; |
411 | } |
412 | |
413 | ret = __media_pipeline_start(pad: entity->pads, pipe); |
414 | if (ret) { |
415 | pr_err("Start Pipeline: %s->%s Error %d\n" , |
416 | source->name, entity->name, ret); |
417 | ret = __media_entity_setup_link(link: found_link, flags: 0); |
418 | if (ret) |
419 | pr_err("Deactivate link Error %d\n" , ret); |
420 | goto end; |
421 | } |
422 | |
423 | /* save link state to allow audio and video share the link |
424 | * and not disable the link while the other is using it. |
425 | * active_link_owner is used to deactivate the link. |
426 | */ |
427 | dev->active_link = found_link; |
428 | dev->active_link_owner = entity; |
429 | dev->active_source = source; |
430 | dev->active_sink = sink; |
431 | |
432 | pr_info("Enabled Source: %s->%s->%s Ret %d\n" , |
433 | dev->active_source->name, dev->active_sink->name, |
434 | dev->active_link_owner->name, ret); |
435 | end: |
436 | pr_debug("%s end: ent:%s fnc:%d ret %d\n" , |
437 | __func__, entity->name, entity->function, ret); |
438 | return ret; |
439 | } |
440 | |
441 | /* Callers should hold graph_mutex */ |
442 | static void au0828_disable_source(struct media_entity *entity) |
443 | { |
444 | int ret = 0; |
445 | struct media_device *mdev = entity->graph_obj.mdev; |
446 | struct au0828_dev *dev; |
447 | |
448 | if (!mdev) |
449 | return; |
450 | |
451 | dev = mdev->source_priv; |
452 | |
453 | if (!dev->active_link) |
454 | return; |
455 | |
456 | /* link is active - stop pipeline from source |
457 | * (tuner/s-video/Composite) to the entity |
458 | * When DVB/s-video/Composite owns tuner, it won't be in |
459 | * shared state. |
460 | */ |
461 | if (dev->active_link->sink->entity == dev->active_sink && |
462 | dev->active_link->source->entity == dev->active_source) { |
463 | /* |
464 | * Prevent video from deactivating link when audio |
465 | * has active pipeline and vice versa. In addition |
466 | * handle the case when more than one video/vbi |
467 | * application is sharing the link. |
468 | */ |
469 | bool owner_is_audio = false; |
470 | |
471 | if (dev->active_link_owner->function == |
472 | MEDIA_ENT_F_AUDIO_CAPTURE) |
473 | owner_is_audio = true; |
474 | |
475 | if (dev->active_link_shared) { |
476 | pr_debug("Shared link owner %s user %s %d\n" , |
477 | dev->active_link_owner->name, |
478 | entity->name, dev->users); |
479 | |
480 | /* Handle video device users > 1 |
481 | * When audio owns the shared link with |
482 | * more than one video users, avoid |
483 | * disabling the source and/or switching |
484 | * the owner until the last disable_source |
485 | * call from video _close(). Use dev->users to |
486 | * determine when to switch/disable. |
487 | */ |
488 | if (dev->active_link_owner != entity) { |
489 | /* video device has users > 1 */ |
490 | if (owner_is_audio && dev->users > 1) |
491 | return; |
492 | |
493 | dev->active_link_user = NULL; |
494 | dev->active_link_user_pipe = NULL; |
495 | dev->active_link_shared = false; |
496 | return; |
497 | } |
498 | |
499 | /* video owns the link and has users > 1 */ |
500 | if (!owner_is_audio && dev->users > 1) |
501 | return; |
502 | |
503 | /* stop pipeline */ |
504 | __media_pipeline_stop(pad: dev->active_link_owner->pads); |
505 | pr_debug("Pipeline stop for %s\n" , |
506 | dev->active_link_owner->name); |
507 | |
508 | ret = __media_pipeline_start( |
509 | pad: dev->active_link_user->pads, |
510 | pipe: dev->active_link_user_pipe); |
511 | if (ret) { |
512 | pr_err("Start Pipeline: %s->%s %d\n" , |
513 | dev->active_source->name, |
514 | dev->active_link_user->name, |
515 | ret); |
516 | goto deactivate_link; |
517 | } |
518 | /* link user is now the owner */ |
519 | dev->active_link_owner = dev->active_link_user; |
520 | dev->active_link_user = NULL; |
521 | dev->active_link_user_pipe = NULL; |
522 | dev->active_link_shared = false; |
523 | |
524 | pr_debug("Pipeline started for %s\n" , |
525 | dev->active_link_owner->name); |
526 | return; |
527 | } else if (!owner_is_audio && dev->users > 1) |
528 | /* video/vbi owns the link and has users > 1 */ |
529 | return; |
530 | |
531 | if (dev->active_link_owner != entity) |
532 | return; |
533 | |
534 | /* stop pipeline */ |
535 | __media_pipeline_stop(pad: dev->active_link_owner->pads); |
536 | pr_debug("Pipeline stop for %s\n" , |
537 | dev->active_link_owner->name); |
538 | |
539 | deactivate_link: |
540 | ret = __media_entity_setup_link(link: dev->active_link, flags: 0); |
541 | if (ret) |
542 | pr_err("Deactivate link Error %d\n" , ret); |
543 | |
544 | pr_info("Disabled Source: %s->%s->%s Ret %d\n" , |
545 | dev->active_source->name, dev->active_sink->name, |
546 | dev->active_link_owner->name, ret); |
547 | |
548 | dev->active_link = NULL; |
549 | dev->active_link_owner = NULL; |
550 | dev->active_source = NULL; |
551 | dev->active_sink = NULL; |
552 | dev->active_link_shared = false; |
553 | dev->active_link_user = NULL; |
554 | } |
555 | } |
556 | #endif |
557 | |
558 | static int au0828_media_device_register(struct au0828_dev *dev, |
559 | struct usb_device *udev) |
560 | { |
561 | #ifdef CONFIG_MEDIA_CONTROLLER |
562 | int ret; |
563 | struct media_entity *entity, *demod = NULL; |
564 | struct media_link *link; |
565 | |
566 | if (!dev->media_dev) |
567 | return 0; |
568 | |
569 | if (!media_devnode_is_registered(devnode: dev->media_dev->devnode)) { |
570 | |
571 | /* register media device */ |
572 | ret = media_device_register(dev->media_dev); |
573 | if (ret) { |
574 | media_device_delete(mdev: dev->media_dev, KBUILD_MODNAME, |
575 | THIS_MODULE); |
576 | dev->media_dev = NULL; |
577 | dev_err(&udev->dev, |
578 | "Media Device Register Error: %d\n" , ret); |
579 | return ret; |
580 | } |
581 | } else { |
582 | /* |
583 | * Call au0828_media_graph_notify() to connect |
584 | * audio graph to our graph. In this case, audio |
585 | * driver registered the device and there is no |
586 | * entity_notify to be called when new entities |
587 | * are added. Invoke it now. |
588 | */ |
589 | au0828_media_graph_notify(NULL, notify_data: (void *) dev); |
590 | } |
591 | |
592 | /* |
593 | * Find tuner, decoder and demod. |
594 | * |
595 | * The tuner and decoder should be cached, as they'll be used by |
596 | * au0828_enable_source. |
597 | * |
598 | * It also needs to disable the link between tuner and |
599 | * decoder/demod, to avoid disable step when tuner is requested |
600 | * by video or audio. Note that this step can't be done until dvb |
601 | * graph is created during dvb register. |
602 | */ |
603 | media_device_for_each_entity(entity, dev->media_dev) { |
604 | switch (entity->function) { |
605 | case MEDIA_ENT_F_TUNER: |
606 | dev->tuner = entity; |
607 | break; |
608 | case MEDIA_ENT_F_ATV_DECODER: |
609 | dev->decoder = entity; |
610 | break; |
611 | case MEDIA_ENT_F_DTV_DEMOD: |
612 | demod = entity; |
613 | break; |
614 | } |
615 | } |
616 | |
617 | /* Disable link between tuner->demod and/or tuner->decoder */ |
618 | if (dev->tuner) { |
619 | list_for_each_entry(link, &dev->tuner->links, list) { |
620 | if (demod && link->sink->entity == demod) |
621 | media_entity_setup_link(link, flags: 0); |
622 | if (dev->decoder && link->sink->entity == dev->decoder) |
623 | media_entity_setup_link(link, flags: 0); |
624 | } |
625 | } |
626 | |
627 | /* register entity_notify callback */ |
628 | dev->entity_notify.notify_data = (void *) dev; |
629 | dev->entity_notify.notify = (void *) au0828_media_graph_notify; |
630 | media_device_register_entity_notify(mdev: dev->media_dev, |
631 | nptr: &dev->entity_notify); |
632 | |
633 | /* set enable_source */ |
634 | mutex_lock(&dev->media_dev->graph_mutex); |
635 | dev->media_dev->source_priv = (void *) dev; |
636 | dev->media_dev->enable_source = au0828_enable_source; |
637 | dev->media_dev->disable_source = au0828_disable_source; |
638 | mutex_unlock(lock: &dev->media_dev->graph_mutex); |
639 | #endif |
640 | return 0; |
641 | } |
642 | |
643 | static int au0828_usb_probe(struct usb_interface *interface, |
644 | const struct usb_device_id *id) |
645 | { |
646 | int ifnum; |
647 | int retval = 0; |
648 | |
649 | struct au0828_dev *dev; |
650 | struct usb_device *usbdev = interface_to_usbdev(interface); |
651 | |
652 | ifnum = interface->altsetting->desc.bInterfaceNumber; |
653 | |
654 | if (ifnum != 0) |
655 | return -ENODEV; |
656 | |
657 | dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n" , __func__, |
658 | le16_to_cpu(usbdev->descriptor.idVendor), |
659 | le16_to_cpu(usbdev->descriptor.idProduct), |
660 | ifnum); |
661 | |
662 | /* |
663 | * Make sure we have 480 Mbps of bandwidth, otherwise things like |
664 | * video stream wouldn't likely work, since 12 Mbps is generally |
665 | * not enough even for most Digital TV streams. |
666 | */ |
667 | if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { |
668 | pr_err("au0828: Device initialization failed.\n" ); |
669 | pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n" ); |
670 | return -ENODEV; |
671 | } |
672 | |
673 | dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
674 | if (dev == NULL) { |
675 | pr_err("%s() Unable to allocate memory\n" , __func__); |
676 | return -ENOMEM; |
677 | } |
678 | |
679 | mutex_init(&dev->lock); |
680 | mutex_lock(&dev->lock); |
681 | mutex_init(&dev->mutex); |
682 | mutex_init(&dev->dvb.lock); |
683 | dev->usbdev = usbdev; |
684 | dev->boardnr = id->driver_info; |
685 | dev->board = au0828_boards[dev->boardnr]; |
686 | |
687 | /* Initialize the media controller */ |
688 | retval = au0828_media_device_init(dev, udev: usbdev); |
689 | if (retval) { |
690 | pr_err("%s() au0828_media_device_init failed\n" , |
691 | __func__); |
692 | mutex_unlock(lock: &dev->lock); |
693 | kfree(objp: dev); |
694 | return retval; |
695 | } |
696 | |
697 | retval = au0828_v4l2_device_register(interface, dev); |
698 | if (retval) { |
699 | au0828_usb_v4l2_media_release(dev); |
700 | mutex_unlock(lock: &dev->lock); |
701 | kfree(objp: dev); |
702 | return retval; |
703 | } |
704 | |
705 | /* Power Up the bridge */ |
706 | au0828_write(dev, REG_600, 1 << 4); |
707 | |
708 | /* Bring up the GPIO's and supporting devices */ |
709 | au0828_gpio_setup(dev); |
710 | |
711 | /* I2C */ |
712 | au0828_i2c_register(dev); |
713 | |
714 | /* Setup */ |
715 | au0828_card_setup(dev); |
716 | |
717 | /* |
718 | * Store the pointer to the au0828_dev so it can be accessed in |
719 | * au0828_usb_disconnect |
720 | */ |
721 | usb_set_intfdata(intf: interface, data: dev); |
722 | |
723 | /* Analog TV */ |
724 | retval = au0828_analog_register(dev, interface); |
725 | if (retval) { |
726 | pr_err("%s() au0828_analog_register failed to register on V4L2\n" , |
727 | __func__); |
728 | mutex_unlock(lock: &dev->lock); |
729 | goto done; |
730 | } |
731 | |
732 | /* Digital TV */ |
733 | retval = au0828_dvb_register(dev); |
734 | if (retval) |
735 | pr_err("%s() au0828_dvb_register failed\n" , |
736 | __func__); |
737 | |
738 | /* Remote controller */ |
739 | au0828_rc_register(dev); |
740 | |
741 | pr_info("Registered device AU0828 [%s]\n" , |
742 | dev->board.name == NULL ? "Unset" : dev->board.name); |
743 | |
744 | mutex_unlock(lock: &dev->lock); |
745 | |
746 | retval = au0828_media_device_register(dev, udev: usbdev); |
747 | |
748 | done: |
749 | if (retval < 0) |
750 | au0828_usb_disconnect(interface); |
751 | |
752 | return retval; |
753 | } |
754 | |
755 | static int au0828_suspend(struct usb_interface *interface, |
756 | pm_message_t message) |
757 | { |
758 | struct au0828_dev *dev = usb_get_intfdata(intf: interface); |
759 | |
760 | if (!dev) |
761 | return 0; |
762 | |
763 | pr_info("Suspend\n" ); |
764 | |
765 | au0828_rc_suspend(dev); |
766 | au0828_v4l2_suspend(dev); |
767 | au0828_dvb_suspend(dev); |
768 | |
769 | /* FIXME: should suspend also ATV/DTV */ |
770 | |
771 | return 0; |
772 | } |
773 | |
774 | static int au0828_resume(struct usb_interface *interface) |
775 | { |
776 | struct au0828_dev *dev = usb_get_intfdata(intf: interface); |
777 | if (!dev) |
778 | return 0; |
779 | |
780 | pr_info("Resume\n" ); |
781 | |
782 | /* Power Up the bridge */ |
783 | au0828_write(dev, REG_600, 1 << 4); |
784 | |
785 | /* Bring up the GPIO's and supporting devices */ |
786 | au0828_gpio_setup(dev); |
787 | |
788 | au0828_rc_resume(dev); |
789 | au0828_v4l2_resume(dev); |
790 | au0828_dvb_resume(dev); |
791 | |
792 | /* FIXME: should resume also ATV/DTV */ |
793 | |
794 | return 0; |
795 | } |
796 | |
797 | static struct usb_driver au0828_usb_driver = { |
798 | .name = KBUILD_MODNAME, |
799 | .probe = au0828_usb_probe, |
800 | .disconnect = au0828_usb_disconnect, |
801 | .id_table = au0828_usb_id_table, |
802 | .suspend = au0828_suspend, |
803 | .resume = au0828_resume, |
804 | .reset_resume = au0828_resume, |
805 | }; |
806 | |
807 | static int __init au0828_init(void) |
808 | { |
809 | int ret; |
810 | |
811 | if (au0828_debug & 1) |
812 | pr_info("%s() Debugging is enabled\n" , __func__); |
813 | |
814 | if (au0828_debug & 2) |
815 | pr_info("%s() USB Debugging is enabled\n" , __func__); |
816 | |
817 | if (au0828_debug & 4) |
818 | pr_info("%s() I2C Debugging is enabled\n" , __func__); |
819 | |
820 | if (au0828_debug & 8) |
821 | pr_info("%s() Bridge Debugging is enabled\n" , |
822 | __func__); |
823 | |
824 | if (au0828_debug & 16) |
825 | pr_info("%s() IR Debugging is enabled\n" , |
826 | __func__); |
827 | |
828 | pr_info("au0828 driver loaded\n" ); |
829 | |
830 | ret = usb_register(&au0828_usb_driver); |
831 | if (ret) |
832 | pr_err("usb_register failed, error = %d\n" , ret); |
833 | |
834 | return ret; |
835 | } |
836 | |
837 | static void __exit au0828_exit(void) |
838 | { |
839 | usb_deregister(&au0828_usb_driver); |
840 | } |
841 | |
842 | module_init(au0828_init); |
843 | module_exit(au0828_exit); |
844 | |
845 | MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products" ); |
846 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>" ); |
847 | MODULE_LICENSE("GPL" ); |
848 | MODULE_VERSION("0.0.3" ); |
849 | |