diff options
Diffstat (limited to 'drivers/media/usb/au0828/au0828-core.c')
| -rw-r--r-- | drivers/media/usb/au0828/au0828-core.c | 676 |
1 files changed, 603 insertions, 73 deletions
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index bd9d19a73efd..1e246b47766d 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -1,41 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for the Auvitek USB bridge * * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" +#include "au8522.h" + #include <linux/module.h> #include <linux/slab.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <linux/mutex.h> -#include "au0828.h" +/* Due to enum tuner_pad_index */ +#include <media/tuner.h> /* * 1 = General debug messages * 2 = USB handling * 4 = I2C related * 8 = Bridge related + * 16 = IR related */ int au0828_debug; module_param_named(debug, au0828_debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); +MODULE_PARM_DESC(debug, + "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR"); static unsigned int disable_usb_speed_check; module_param(disable_usb_speed_check, int, 0444); @@ -88,7 +80,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed sending control message, error %d.\n", + pr_err("%s() Failed sending control message, error %d.\n", __func__, status); } @@ -113,7 +105,7 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", + pr_err("%s() Failed receiving control message, error %d.\n", __func__, status); } @@ -125,25 +117,48 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, return status; } -static void au0828_usb_release(struct au0828_dev *dev) +#ifdef CONFIG_MEDIA_CONTROLLER +static void au0828_media_graph_notify(struct media_entity *new, + void *notify_data); +#endif + +static void au0828_unregister_media_device(struct au0828_dev *dev) { - /* I2C */ - au0828_i2c_unregister(dev); +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev = dev->media_dev; + struct media_entity_notify *notify, *nextp; - kfree(dev); + if (!mdev || !media_devnode_is_registered(mdev->devnode)) + return; + + /* Remove au0828 entity_notify callbacks */ + list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) { + if (notify->notify != au0828_media_graph_notify) + continue; + media_device_unregister_entity_notify(mdev, notify); + } + + /* clear enable_source, disable_source */ + mutex_lock(&mdev->graph_mutex); + dev->media_dev->source_priv = NULL; + dev->media_dev->enable_source = NULL; + dev->media_dev->disable_source = NULL; + mutex_unlock(&mdev->graph_mutex); + + media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE); + dev->media_dev = NULL; +#endif } -#ifdef CONFIG_VIDEO_AU0828_V4L2 -static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev) +void au0828_usb_release(struct au0828_dev *dev) { - struct au0828_dev *dev = - container_of(v4l2_dev, struct au0828_dev, v4l2_dev); + au0828_unregister_media_device(dev); - v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl); - v4l2_device_unregister(&dev->v4l2_dev); - au0828_usb_release(dev); + /* I2C */ + au0828_i2c_unregister(dev); + + kfree(dev); } -#endif static void au0828_usb_disconnect(struct usb_interface *interface) { @@ -151,6 +166,15 @@ static void au0828_usb_disconnect(struct usb_interface *interface) dprintk(1, "%s()\n", __func__); + /* there is a small window after disconnect, before + dev->usbdev is NULL, for poll (e.g: IR) try to access + the device and fill the dmesg with error messages. + Set the status so poll routines can check and avoid + access after disconnect. + */ + set_bit(DEV_DISCONNECTED, &dev->dev_state); + + au0828_rc_unregister(dev); /* Digital TV */ au0828_dvb_unregister(dev); @@ -158,24 +182,470 @@ static void au0828_usb_disconnect(struct usb_interface *interface) mutex_lock(&dev->mutex); dev->usbdev = NULL; mutex_unlock(&dev->mutex); -#ifdef CONFIG_VIDEO_AU0828_V4L2 - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) { - au0828_analog_unregister(dev); - v4l2_device_disconnect(&dev->v4l2_dev); - v4l2_device_put(&dev->v4l2_dev); + if (au0828_analog_unregister(dev)) { + /* + * No need to call au0828_usb_release() if V4L2 is enabled, + * as this is already called via au0828_usb_v4l2_release() + */ return; } -#endif au0828_usb_release(dev); } +static int au0828_media_device_init(struct au0828_dev *dev, + struct usb_device *udev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev; + + mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE); + if (IS_ERR(mdev)) + return PTR_ERR(mdev); + + dev->media_dev = mdev; +#endif + return 0; +} + +#ifdef CONFIG_MEDIA_CONTROLLER +static void au0828_media_graph_notify(struct media_entity *new, + void *notify_data) +{ + struct au0828_dev *dev = notify_data; + int ret; + struct media_entity *entity, *mixer = NULL, *decoder = NULL; + + if (!new) { + /* + * Called during au0828 probe time to connect + * entities that were created prior to registering + * the notify handler. Find mixer and decoder. + */ + media_device_for_each_entity(entity, dev->media_dev) { + if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) + mixer = entity; + else if (entity->function == MEDIA_ENT_F_ATV_DECODER) + decoder = entity; + } + goto create_link; + } + + switch (new->function) { + case MEDIA_ENT_F_AUDIO_MIXER: + mixer = new; + if (dev->decoder) + decoder = dev->decoder; + break; + case MEDIA_ENT_F_ATV_DECODER: + /* In case, Mixer is added first, find mixer and create link */ + media_device_for_each_entity(entity, dev->media_dev) { + if (entity->function == MEDIA_ENT_F_AUDIO_MIXER) + mixer = entity; + } + decoder = new; + break; + default: + break; + } + +create_link: + if (decoder && mixer) { + ret = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE, + PAD_SIGNAL_AUDIO); + if (ret >= 0) + ret = media_create_pad_link(decoder, ret, + mixer, 0, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + dev_err(&dev->usbdev->dev, + "Mixer Pad Link Create Error: %d\n", ret); + } +} + +static bool au0828_is_link_shareable(struct media_entity *owner, + struct media_entity *entity) +{ + bool shareable = false; + + /* Tuner link can be shared by audio, video, and VBI */ + switch (owner->function) { + case MEDIA_ENT_F_IO_V4L: + case MEDIA_ENT_F_AUDIO_CAPTURE: + case MEDIA_ENT_F_IO_VBI: + if (entity->function == MEDIA_ENT_F_IO_V4L || + entity->function == MEDIA_ENT_F_AUDIO_CAPTURE || + entity->function == MEDIA_ENT_F_IO_VBI) + shareable = true; + break; + case MEDIA_ENT_F_DTV_DEMOD: + default: + break; + } + return shareable; +} + +/* Callers should hold graph_mutex */ +static int au0828_enable_source(struct media_entity *entity, + struct media_pipeline *pipe) +{ + struct media_entity *source, *find_source; + struct media_entity *sink; + struct media_link *link, *found_link = NULL; + int ret = 0; + struct media_device *mdev = entity->graph_obj.mdev; + struct au0828_dev *dev; + + if (!mdev) + return -ENODEV; + + dev = mdev->source_priv; + + /* + * For Audio and V4L2 entity, find the link to which decoder + * is the sink. Look for an active link between decoder and + * source (tuner/s-video/Composite), if one exists, nothing + * to do. If not, look for any active links between source + * and any other entity. If one exists, source is busy. If + * source is free, setup link and start pipeline from source. + * For DVB FE entity, the source for the link is the tuner. + * Check if tuner is available and setup link and start + * pipeline. + */ + if (entity->function == MEDIA_ENT_F_DTV_DEMOD) { + sink = entity; + find_source = dev->tuner; + } else { + /* Analog isn't configured or register failed */ + if (!dev->decoder) { + ret = -ENODEV; + goto end; + } + + sink = dev->decoder; + + /* + * Default input is tuner and default input_type + * is AU0828_VMUX_TELEVISION. + * + * There is a problem when s_input is called to + * change the default input. s_input will try to + * enable_source before attempting to change the + * input on the device, and will end up enabling + * default source which is tuner. + * + * Additional logic is necessary in au0828 to detect + * that the input has changed and enable the right + * source. au0828 handles this case in its s_input. + * It will disable the old source and enable the new + * source. + * + */ + if (dev->input_type == AU0828_VMUX_TELEVISION) + find_source = dev->tuner; + else if (dev->input_type == AU0828_VMUX_SVIDEO || + dev->input_type == AU0828_VMUX_COMPOSITE) + find_source = &dev->input_ent[dev->input_type]; + else { + /* unknown input - let user select input */ + ret = 0; + goto end; + } + } + + /* Is there an active link between sink and source */ + if (dev->active_link) { + if (dev->active_link_owner == entity) { + /* This check is necessary to handle multiple + * enable_source calls from v4l_ioctls during + * the course of video/vbi application run-time. + */ + pr_debug("%s already owns the tuner\n", entity->name); + ret = 0; + goto end; + } else if (au0828_is_link_shareable(dev->active_link_owner, + entity)) { + /* Either ALSA or Video own tuner. Sink is the same + * for both. Allow sharing the active link between + * their common source (tuner) and sink (decoder). + * Starting pipeline between sharing entity and sink + * will fail with pipe mismatch, while owner has an + * active pipeline. Switch pipeline ownership from + * user to owner when owner disables the source. + */ + dev->active_link_shared = true; + /* save the user info to use from disable */ + dev->active_link_user = entity; + dev->active_link_user_pipe = pipe; + pr_debug("%s owns the tuner %s can share!\n", + dev->active_link_owner->name, + entity->name); + ret = 0; + goto end; + } else { + ret = -EBUSY; + goto end; + } + } + + list_for_each_entry(link, &sink->links, list) { + /* Check sink, and source */ + if (link->sink->entity == sink && + link->source->entity == find_source) { + found_link = link; + break; + } + } + + if (!found_link) { + ret = -ENODEV; + goto end; + } + + /* activate link between source and sink and start pipeline */ + source = found_link->source->entity; + ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED); + if (ret) { + pr_err("Activate link from %s->%s. Error %d\n", + source->name, sink->name, ret); + goto end; + } + + ret = __media_pipeline_start(entity->pads, pipe); + if (ret) { + pr_err("Start Pipeline: %s->%s Error %d\n", + source->name, entity->name, ret); + ret = __media_entity_setup_link(found_link, 0); + if (ret) + pr_err("Deactivate link Error %d\n", ret); + goto end; + } + + /* save link state to allow audio and video share the link + * and not disable the link while the other is using it. + * active_link_owner is used to deactivate the link. + */ + dev->active_link = found_link; + dev->active_link_owner = entity; + dev->active_source = source; + dev->active_sink = sink; + + pr_info("Enabled Source: %s->%s->%s Ret %d\n", + dev->active_source->name, dev->active_sink->name, + dev->active_link_owner->name, ret); +end: + pr_debug("%s end: ent:%s fnc:%d ret %d\n", + __func__, entity->name, entity->function, ret); + return ret; +} + +/* Callers should hold graph_mutex */ +static void au0828_disable_source(struct media_entity *entity) +{ + int ret = 0; + struct media_device *mdev = entity->graph_obj.mdev; + struct au0828_dev *dev; + + if (!mdev) + return; + + dev = mdev->source_priv; + + if (!dev->active_link) + return; + + /* link is active - stop pipeline from source + * (tuner/s-video/Composite) to the entity + * When DVB/s-video/Composite owns tuner, it won't be in + * shared state. + */ + if (dev->active_link->sink->entity == dev->active_sink && + dev->active_link->source->entity == dev->active_source) { + /* + * Prevent video from deactivating link when audio + * has active pipeline and vice versa. In addition + * handle the case when more than one video/vbi + * application is sharing the link. + */ + bool owner_is_audio = false; + + if (dev->active_link_owner->function == + MEDIA_ENT_F_AUDIO_CAPTURE) + owner_is_audio = true; + + if (dev->active_link_shared) { + pr_debug("Shared link owner %s user %s %d\n", + dev->active_link_owner->name, + entity->name, dev->users); + + /* Handle video device users > 1 + * When audio owns the shared link with + * more than one video users, avoid + * disabling the source and/or switching + * the owner until the last disable_source + * call from video _close(). Use dev->users to + * determine when to switch/disable. + */ + if (dev->active_link_owner != entity) { + /* video device has users > 1 */ + if (owner_is_audio && dev->users > 1) + return; + + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + return; + } + + /* video owns the link and has users > 1 */ + if (!owner_is_audio && dev->users > 1) + return; + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner->pads); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + + ret = __media_pipeline_start( + dev->active_link_user->pads, + dev->active_link_user_pipe); + if (ret) { + pr_err("Start Pipeline: %s->%s %d\n", + dev->active_source->name, + dev->active_link_user->name, + ret); + goto deactivate_link; + } + /* link user is now the owner */ + dev->active_link_owner = dev->active_link_user; + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + + pr_debug("Pipeline started for %s\n", + dev->active_link_owner->name); + return; + } else if (!owner_is_audio && dev->users > 1) + /* video/vbi owns the link and has users > 1 */ + return; + + if (dev->active_link_owner != entity) + return; + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner->pads); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + +deactivate_link: + ret = __media_entity_setup_link(dev->active_link, 0); + if (ret) + pr_err("Deactivate link Error %d\n", ret); + + pr_info("Disabled Source: %s->%s->%s Ret %d\n", + dev->active_source->name, dev->active_sink->name, + dev->active_link_owner->name, ret); + + dev->active_link = NULL; + dev->active_link_owner = NULL; + dev->active_source = NULL; + dev->active_sink = NULL; + dev->active_link_shared = false; + dev->active_link_user = NULL; + } +} +#endif + +static int au0828_media_device_register(struct au0828_dev *dev, + struct usb_device *udev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + int ret; + struct media_entity *entity, *demod = NULL; + struct media_link *link; + + if (!dev->media_dev) + return 0; + + if (!media_devnode_is_registered(dev->media_dev->devnode)) { + + /* register media device */ + ret = media_device_register(dev->media_dev); + if (ret) { + media_device_delete(dev->media_dev, KBUILD_MODNAME, + THIS_MODULE); + dev->media_dev = NULL; + dev_err(&udev->dev, + "Media Device Register Error: %d\n", ret); + return ret; + } + } else { + /* + * Call au0828_media_graph_notify() to connect + * audio graph to our graph. In this case, audio + * driver registered the device and there is no + * entity_notify to be called when new entities + * are added. Invoke it now. + */ + au0828_media_graph_notify(NULL, (void *) dev); + } + + /* + * Find tuner, decoder and demod. + * + * The tuner and decoder should be cached, as they'll be used by + * au0828_enable_source. + * + * It also needs to disable the link between tuner and + * decoder/demod, to avoid disable step when tuner is requested + * by video or audio. Note that this step can't be done until dvb + * graph is created during dvb register. + */ + media_device_for_each_entity(entity, dev->media_dev) { + switch (entity->function) { + case MEDIA_ENT_F_TUNER: + dev->tuner = entity; + break; + case MEDIA_ENT_F_ATV_DECODER: + dev->decoder = entity; + break; + case MEDIA_ENT_F_DTV_DEMOD: + demod = entity; + break; + } + } + + /* Disable link between tuner->demod and/or tuner->decoder */ + if (dev->tuner) { + list_for_each_entry(link, &dev->tuner->links, list) { + if (demod && link->sink->entity == demod) + media_entity_setup_link(link, 0); + if (dev->decoder && link->sink->entity == dev->decoder) + media_entity_setup_link(link, 0); + } + } + + /* register entity_notify callback */ + dev->entity_notify.notify_data = (void *) dev; + dev->entity_notify.notify = (void *) au0828_media_graph_notify; + media_device_register_entity_notify(dev->media_dev, + &dev->entity_notify); + + /* set enable_source */ + mutex_lock(&dev->media_dev->graph_mutex); + dev->media_dev->source_priv = (void *) dev; + dev->media_dev->enable_source = au0828_enable_source; + dev->media_dev->disable_source = au0828_disable_source; + mutex_unlock(&dev->media_dev->graph_mutex); +#endif + return 0; +} + static int au0828_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { int ifnum; -#ifdef CONFIG_VIDEO_AU0828_V4L2 - int retval; -#endif + int retval = 0; + struct au0828_dev *dev; struct usb_device *usbdev = interface_to_usbdev(interface); @@ -195,15 +665,14 @@ static int au0828_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(KERN_ERR "au0828: Device initialization failed.\n"); - printk(KERN_ERR "au0828: Device must be connected to a " - "high-speed USB 2.0 port.\n"); + pr_err("au0828: Device initialization failed.\n"); + pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); return -ENODEV; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); + pr_err("%s() Unable to allocate memory\n", __func__); return -ENOMEM; } @@ -213,30 +682,25 @@ static int au0828_usb_probe(struct usb_interface *interface, mutex_init(&dev->dvb.lock); dev->usbdev = usbdev; dev->boardnr = id->driver_info; + dev->board = au0828_boards[dev->boardnr]; -#ifdef CONFIG_VIDEO_AU0828_V4L2 - dev->v4l2_dev.release = au0828_usb_v4l2_release; - - /* Create the v4l2_device */ - retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); + /* Initialize the media controller */ + retval = au0828_media_device_init(dev, usbdev); if (retval) { - pr_err("%s() v4l2_device_register failed\n", + pr_err("%s() au0828_media_device_init failed\n", __func__); mutex_unlock(&dev->lock); kfree(dev); return retval; } - /* This control handler will inherit the controls from au8522 */ - retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4); + + retval = au0828_v4l2_device_register(interface, dev); if (retval) { - pr_err("%s() v4l2_ctrl_handler_init failed\n", - __func__); + au0828_usb_v4l2_media_release(dev); mutex_unlock(&dev->lock); kfree(dev); return retval; } - dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl; -#endif /* Power Up the bridge */ au0828_write(dev, REG_600, 1 << 4); @@ -250,32 +714,94 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Setup */ au0828_card_setup(dev); -#ifdef CONFIG_VIDEO_AU0828_V4L2 + /* + * Store the pointer to the au0828_dev so it can be accessed in + * au0828_usb_disconnect + */ + usb_set_intfdata(interface, dev); + /* Analog TV */ - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) - au0828_analog_register(dev, interface); -#endif + retval = au0828_analog_register(dev, interface); + if (retval) { + pr_err("%s() au0828_analog_register failed to register on V4L2\n", + __func__); + mutex_unlock(&dev->lock); + goto done; + } /* Digital TV */ - au0828_dvb_register(dev); + retval = au0828_dvb_register(dev); + if (retval) + pr_err("%s() au0828_dvb_register failed\n", + __func__); - /* Store the pointer to the au0828_dev so it can be accessed in - au0828_usb_disconnect */ - usb_set_intfdata(interface, dev); + /* Remote controller */ + au0828_rc_register(dev); - printk(KERN_INFO "Registered device AU0828 [%s]\n", + pr_info("Registered device AU0828 [%s]\n", dev->board.name == NULL ? "Unset" : dev->board.name); mutex_unlock(&dev->lock); + retval = au0828_media_device_register(dev, usbdev); + +done: + if (retval < 0) + au0828_usb_disconnect(interface); + + return retval; +} + +static int au0828_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + if (!dev) + return 0; + + pr_info("Suspend\n"); + + au0828_rc_suspend(dev); + au0828_v4l2_suspend(dev); + au0828_dvb_suspend(dev); + + /* FIXME: should suspend also ATV/DTV */ + + return 0; +} + +static int au0828_resume(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + if (!dev) + return 0; + + pr_info("Resume\n"); + + /* Power Up the bridge */ + au0828_write(dev, REG_600, 1 << 4); + + /* Bring up the GPIO's and supporting devices */ + au0828_gpio_setup(dev); + + au0828_rc_resume(dev); + au0828_v4l2_resume(dev); + au0828_dvb_resume(dev); + + /* FIXME: should resume also ATV/DTV */ + return 0; } static struct usb_driver au0828_usb_driver = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = au0828_usb_probe, .disconnect = au0828_usb_disconnect, .id_table = au0828_usb_id_table, + .suspend = au0828_suspend, + .resume = au0828_resume, + .reset_resume = au0828_resume, }; static int __init au0828_init(void) @@ -283,23 +809,27 @@ static int __init au0828_init(void) int ret; if (au0828_debug & 1) - printk(KERN_INFO "%s() Debugging is enabled\n", __func__); + pr_info("%s() Debugging is enabled\n", __func__); if (au0828_debug & 2) - printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); + pr_info("%s() USB Debugging is enabled\n", __func__); if (au0828_debug & 4) - printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); + pr_info("%s() I2C Debugging is enabled\n", __func__); if (au0828_debug & 8) - printk(KERN_INFO "%s() Bridge Debugging is enabled\n", + pr_info("%s() Bridge Debugging is enabled\n", + __func__); + + if (au0828_debug & 16) + pr_info("%s() IR Debugging is enabled\n", __func__); - printk(KERN_INFO "au0828 driver loaded\n"); + pr_info("au0828 driver loaded\n"); ret = usb_register(&au0828_usb_driver); if (ret) - printk(KERN_ERR "usb_register failed, error = %d\n", ret); + pr_err("usb_register failed, error = %d\n", ret); return ret; } @@ -315,4 +845,4 @@ module_exit(au0828_exit); MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.0.2"); +MODULE_VERSION("0.0.3"); |
