linux/drivers/media/usb/tlg2300/pd-main.c
<<
>>
Prefs
   1/*
   2 * device driver for Telegent tlg2300 based TV cards
   3 *
   4 * Author :
   5 *      Kang Yong       <kangyong@telegent.com>
   6 *      Zhang Xiaobing  <xbzhang@telegent.com>
   7 *      Huang Shijie    <zyziii@telegent.com> or <shijie8@gmail.com>
   8 *
   9 *      (c) 2009 Telegent Systems
  10 *      (c) 2010 Telegent Systems
  11 *
  12 *  This program is free software; you can redistribute it and/or modify
  13 *  it under the terms of the GNU General Public License as published by
  14 *  the Free Software Foundation; either version 2 of the License, or
  15 *  (at your option) any later version.
  16 *
  17 *  This program is distributed in the hope that it will be useful,
  18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 *  GNU General Public License for more details.
  21 *
  22 *  You should have received a copy of the GNU General Public License
  23 *  along with this program; if not, write to the Free Software
  24 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25 */
  26
  27#include <linux/kernel.h>
  28#include <linux/errno.h>
  29#include <linux/init.h>
  30#include <linux/slab.h>
  31#include <linux/module.h>
  32#include <linux/kref.h>
  33#include <linux/suspend.h>
  34#include <linux/usb/quirks.h>
  35#include <linux/ctype.h>
  36#include <linux/string.h>
  37#include <linux/types.h>
  38#include <linux/firmware.h>
  39
  40#include "vendorcmds.h"
  41#include "pd-common.h"
  42
  43#define VENDOR_ID       0x1B24
  44#define PRODUCT_ID      0x4001
  45static struct usb_device_id id_table[] = {
  46        { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) },
  47        { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) },
  48        { },
  49};
  50MODULE_DEVICE_TABLE(usb, id_table);
  51
  52int debug_mode;
  53module_param(debug_mode, int, 0644);
  54MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
  55
  56#define TLG2300_FIRMWARE "tlg2300_firmware.bin"
  57static const char *firmware_name = TLG2300_FIRMWARE;
  58static LIST_HEAD(pd_device_list);
  59
  60/*
  61 * send set request to USB firmware.
  62 */
  63s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status)
  64{
  65        s32 ret;
  66        s8  data[32] = {};
  67        u16 lower_16, upper_16;
  68
  69        if (pd->state & POSEIDON_STATE_DISCONNECT)
  70                return -ENODEV;
  71
  72        mdelay(30);
  73
  74        if (param == 0) {
  75                upper_16 = lower_16 = 0;
  76        } else {
  77                /* send 32 bit param as  two 16 bit param,little endian */
  78                lower_16 = (unsigned short)(param & 0xffff);
  79                upper_16 = (unsigned short)((param >> 16) & 0xffff);
  80        }
  81        ret = usb_control_msg(pd->udev,
  82                         usb_rcvctrlpipe(pd->udev, 0),
  83                         REQ_SET_CMD | cmdid,
  84                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
  85                         lower_16,
  86                         upper_16,
  87                         &data,
  88                         sizeof(*cmd_status),
  89                         USB_CTRL_GET_TIMEOUT);
  90
  91        if (!ret) {
  92                return -ENXIO;
  93        } else {
  94                /*  1st 4 bytes into cmd_status   */
  95                memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status));
  96        }
  97        return 0;
  98}
  99
 100/*
 101 * send get request to Poseidon firmware.
 102 */
 103s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param,
 104                        void *buf, s32 *cmd_status, s32 datalen)
 105{
 106        s32 ret;
 107        s8 data[128] = {};
 108        u16 lower_16, upper_16;
 109
 110        if (pd->state & POSEIDON_STATE_DISCONNECT)
 111                return -ENODEV;
 112
 113        mdelay(30);
 114        if (param == 0) {
 115                upper_16 = lower_16 = 0;
 116        } else {
 117                /*send 32 bit param as two 16 bit param, little endian */
 118                lower_16 = (unsigned short)(param & 0xffff);
 119                upper_16 = (unsigned short)((param >> 16) & 0xffff);
 120        }
 121        ret = usb_control_msg(pd->udev,
 122                         usb_rcvctrlpipe(pd->udev, 0),
 123                         REQ_GET_CMD | cmdid,
 124                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 125                         lower_16,
 126                         upper_16,
 127                         &data,
 128                         (datalen + sizeof(*cmd_status)),
 129                         USB_CTRL_GET_TIMEOUT);
 130
 131        if (ret < 0) {
 132                return -ENXIO;
 133        } else {
 134                /* 1st 4 bytes into cmd_status, remaining data into cmd_data */
 135                memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status));
 136                memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen);
 137        }
 138        return 0;
 139}
 140
 141static int pm_notifier_block(struct notifier_block *nb,
 142                                unsigned long event, void *dummy)
 143{
 144        struct poseidon *pd = NULL;
 145        struct list_head *node, *next;
 146
 147        switch (event) {
 148        case PM_POST_HIBERNATION:
 149                list_for_each_safe(node, next, &pd_device_list) {
 150                        struct usb_device *udev;
 151                        struct usb_interface *iface;
 152                        int rc = 0;
 153
 154                        pd = container_of(node, struct poseidon, device_list);
 155                        udev = pd->udev;
 156                        iface = pd->interface;
 157
 158                        /* It will cause the system to reload the firmware */
 159                        rc = usb_lock_device_for_reset(udev, iface);
 160                        if (rc >= 0) {
 161                                usb_reset_device(udev);
 162                                usb_unlock_device(udev);
 163                        }
 164                }
 165                break;
 166        default:
 167                break;
 168        }
 169        log("event :%ld\n", event);
 170        return 0;
 171}
 172
 173static struct notifier_block pm_notifer = {
 174        .notifier_call = pm_notifier_block,
 175};
 176
 177int set_tuner_mode(struct poseidon *pd, unsigned char mode)
 178{
 179        s32 ret, cmd_status;
 180
 181        if (pd->state & POSEIDON_STATE_DISCONNECT)
 182                return -ENODEV;
 183
 184        ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status);
 185        if (ret || cmd_status)
 186                return -ENXIO;
 187        return 0;
 188}
 189
 190void poseidon_delete(struct kref *kref)
 191{
 192        struct poseidon *pd = container_of(kref, struct poseidon, kref);
 193
 194        if (!pd)
 195                return;
 196        list_del_init(&pd->device_list);
 197
 198        pd_dvb_usb_device_cleanup(pd);
 199        /* clean_audio_data(&pd->audio_data);*/
 200
 201        if (pd->udev) {
 202                usb_put_dev(pd->udev);
 203                pd->udev = NULL;
 204        }
 205        if (pd->interface) {
 206                usb_put_intf(pd->interface);
 207                pd->interface = NULL;
 208        }
 209        kfree(pd);
 210        log();
 211}
 212
 213static int firmware_download(struct usb_device *udev)
 214{
 215        int ret = 0, actual_length;
 216        const struct firmware *fw = NULL;
 217        void *fwbuf = NULL;
 218        size_t fwlength = 0, offset;
 219        size_t max_packet_size;
 220
 221        ret = request_firmware(&fw, firmware_name, &udev->dev);
 222        if (ret) {
 223                log("download err : %d", ret);
 224                return ret;
 225        }
 226
 227        fwlength = fw->size;
 228
 229        fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
 230        if (!fwbuf) {
 231                ret = -ENOMEM;
 232                goto out;
 233        }
 234
 235        max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize);
 236        log("\t\t download size : %d", (int)max_packet_size);
 237
 238        for (offset = 0; offset < fwlength; offset += max_packet_size) {
 239                actual_length = 0;
 240                ret = usb_bulk_msg(udev,
 241                                usb_sndbulkpipe(udev, 0x01), /* ep 1 */
 242                                fwbuf + offset,
 243                                min(max_packet_size, fwlength - offset),
 244                                &actual_length,
 245                                HZ * 10);
 246                if (ret)
 247                        break;
 248        }
 249        kfree(fwbuf);
 250out:
 251        release_firmware(fw);
 252        return ret;
 253}
 254
 255static inline struct poseidon *get_pd(struct usb_interface *intf)
 256{
 257        return usb_get_intfdata(intf);
 258}
 259
 260#ifdef CONFIG_PM
 261/* one-to-one map : poseidon{} <----> usb_device{}'s port */
 262static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
 263{
 264        pd->portnum = udev->portnum;
 265}
 266
 267static inline int get_autopm_ref(struct poseidon *pd)
 268{
 269        return  pd->video_data.users + pd->vbi_data.users + pd->audio.users
 270                + atomic_read(&pd->dvb_data.users) +
 271                !list_empty(&pd->radio_data.fm_dev.fh_list);
 272}
 273
 274/* fixup something for poseidon */
 275static inline struct poseidon *fixup(struct poseidon *pd)
 276{
 277        int count;
 278
 279        /* old udev and interface have gone, so put back reference . */
 280        count = get_autopm_ref(pd);
 281        log("count : %d, ref count : %d", count, get_pm_count(pd));
 282        while (count--)
 283                usb_autopm_put_interface(pd->interface);
 284        /*usb_autopm_set_interface(pd->interface); */
 285
 286        usb_put_dev(pd->udev);
 287        usb_put_intf(pd->interface);
 288        log("event : %d\n", pd->msg.event);
 289        return pd;
 290}
 291
 292static struct poseidon *find_old_poseidon(struct usb_device *udev)
 293{
 294        struct poseidon *pd;
 295
 296        list_for_each_entry(pd, &pd_device_list, device_list) {
 297                if (pd->portnum == udev->portnum && in_hibernation(pd))
 298                        return fixup(pd);
 299        }
 300        return NULL;
 301}
 302
 303/* Is the card working now ? */
 304static inline int is_working(struct poseidon *pd)
 305{
 306        return get_pm_count(pd) > 0;
 307}
 308
 309static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg)
 310{
 311        struct poseidon *pd = get_pd(intf);
 312
 313        if (!pd)
 314                return 0;
 315        if (!is_working(pd)) {
 316                if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) {
 317                        pd->msg.event = PM_EVENT_AUTO_SUSPEND;
 318                        pd->pm_resume = NULL; /*  a good guard */
 319                        printk(KERN_DEBUG "TLG2300 auto suspend\n");
 320                }
 321                return 0;
 322        }
 323        pd->msg = msg; /* save it here */
 324        logpm(pd);
 325        return pd->pm_suspend ? pd->pm_suspend(pd) : 0;
 326}
 327
 328static int poseidon_resume(struct usb_interface *intf)
 329{
 330        struct poseidon *pd = get_pd(intf);
 331
 332        if (!pd)
 333                return 0;
 334        printk(KERN_DEBUG "TLG2300 resume\n");
 335
 336        if (!is_working(pd)) {
 337                if (PM_EVENT_AUTO_SUSPEND == pd->msg.event)
 338                        pd->msg = PMSG_ON;
 339                return 0;
 340        }
 341        if (in_hibernation(pd)) {
 342                logpm(pd);
 343                return 0;
 344        }
 345        logpm(pd);
 346        return pd->pm_resume ? pd->pm_resume(pd) : 0;
 347}
 348
 349static void hibernation_resume(struct work_struct *w)
 350{
 351        struct poseidon *pd = container_of(w, struct poseidon, pm_work);
 352        int count;
 353
 354        pd->msg.event = 0; /* clear it here */
 355        pd->state &= ~POSEIDON_STATE_DISCONNECT;
 356
 357        /* set the new interface's reference */
 358        count = get_autopm_ref(pd);
 359        while (count--)
 360                usb_autopm_get_interface(pd->interface);
 361
 362        /* resume the context */
 363        logpm(pd);
 364        if (pd->pm_resume)
 365                pd->pm_resume(pd);
 366}
 367#else /* CONFIG_PM is not enabled: */
 368static inline struct poseidon *find_old_poseidon(struct usb_device *udev)
 369{
 370        return NULL;
 371}
 372
 373static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
 374{
 375}
 376#endif
 377
 378static int check_firmware(struct usb_device *udev)
 379{
 380        void *buf;
 381        int ret;
 382        struct cmd_firmware_vers_s *cmd_firm;
 383
 384        buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL);
 385        if (!buf)
 386                return -ENOMEM;
 387        ret = usb_control_msg(udev,
 388                         usb_rcvctrlpipe(udev, 0),
 389                         REQ_GET_CMD | GET_FW_ID,
 390                         USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 391                         0,
 392                         0,
 393                         buf,
 394                         sizeof(*cmd_firm) + sizeof(u32),
 395                         USB_CTRL_GET_TIMEOUT);
 396        kfree(buf);
 397
 398        if (ret < 0)
 399                return firmware_download(udev);
 400        return 0;
 401}
 402
 403static int poseidon_probe(struct usb_interface *interface,
 404                                const struct usb_device_id *id)
 405{
 406        struct usb_device *udev = interface_to_usbdev(interface);
 407        struct poseidon *pd = NULL;
 408        int ret = 0;
 409        int new_one = 0;
 410
 411        /* download firmware */
 412        ret = check_firmware(udev);
 413        if (ret)
 414                return ret;
 415
 416        /* Do I recovery from the hibernate ? */
 417        pd = find_old_poseidon(udev);
 418        if (!pd) {
 419                pd = kzalloc(sizeof(*pd), GFP_KERNEL);
 420                if (!pd)
 421                        return -ENOMEM;
 422                kref_init(&pd->kref);
 423                set_map_flags(pd, udev);
 424                new_one = 1;
 425        }
 426
 427        pd->udev        = usb_get_dev(udev);
 428        pd->interface   = usb_get_intf(interface);
 429        usb_set_intfdata(interface, pd);
 430
 431        if (new_one) {
 432                logpm(pd);
 433                mutex_init(&pd->lock);
 434
 435                /* register v4l2 device */
 436                ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev);
 437                if (ret)
 438                        goto err_v4l2;
 439
 440                /* register devices in directory /dev */
 441                ret = pd_video_init(pd);
 442                if (ret)
 443                        goto err_video;
 444                ret = poseidon_audio_init(pd);
 445                if (ret)
 446                        goto err_audio;
 447                ret = poseidon_fm_init(pd);
 448                if (ret)
 449                        goto err_fm;
 450                ret = pd_dvb_usb_device_init(pd);
 451                if (ret)
 452                        goto err_dvb;
 453
 454                INIT_LIST_HEAD(&pd->device_list);
 455                list_add_tail(&pd->device_list, &pd_device_list);
 456        }
 457
 458        device_init_wakeup(&udev->dev, 1);
 459#ifdef CONFIG_PM
 460        pm_runtime_set_autosuspend_delay(&pd->udev->dev,
 461                        1000 * PM_SUSPEND_DELAY);
 462        usb_enable_autosuspend(pd->udev);
 463
 464        if (in_hibernation(pd)) {
 465                INIT_WORK(&pd->pm_work, hibernation_resume);
 466                schedule_work(&pd->pm_work);
 467        }
 468#endif
 469        return 0;
 470err_dvb:
 471        poseidon_fm_exit(pd);
 472err_fm:
 473        poseidon_audio_free(pd);
 474err_audio:
 475        pd_video_exit(pd);
 476err_video:
 477        v4l2_device_unregister(&pd->v4l2_dev);
 478err_v4l2:
 479        kfree(pd);
 480        return ret;
 481}
 482
 483static void poseidon_disconnect(struct usb_interface *interface)
 484{
 485        struct poseidon *pd = get_pd(interface);
 486
 487        if (!pd)
 488                return;
 489        logpm(pd);
 490        if (in_hibernation(pd))
 491                return;
 492
 493        mutex_lock(&pd->lock);
 494        pd->state |= POSEIDON_STATE_DISCONNECT;
 495        mutex_unlock(&pd->lock);
 496
 497        /* stop urb transferring */
 498        stop_all_video_stream(pd);
 499        dvb_stop_streaming(&pd->dvb_data);
 500
 501        /*unregister v4l2 device */
 502        v4l2_device_unregister(&pd->v4l2_dev);
 503
 504        pd_dvb_usb_device_exit(pd);
 505        poseidon_fm_exit(pd);
 506
 507        poseidon_audio_free(pd);
 508        pd_video_exit(pd);
 509
 510        usb_set_intfdata(interface, NULL);
 511        kref_put(&pd->kref, poseidon_delete);
 512}
 513
 514static struct usb_driver poseidon_driver = {
 515        .name           = "poseidon",
 516        .probe          = poseidon_probe,
 517        .disconnect     = poseidon_disconnect,
 518        .id_table       = id_table,
 519#ifdef CONFIG_PM
 520        .suspend        = poseidon_suspend,
 521        .resume         = poseidon_resume,
 522#endif
 523        .supports_autosuspend = 1,
 524};
 525
 526static int __init poseidon_init(void)
 527{
 528        int ret;
 529
 530        ret = usb_register(&poseidon_driver);
 531        if (ret)
 532                return ret;
 533        register_pm_notifier(&pm_notifer);
 534        return ret;
 535}
 536
 537static void __exit poseidon_exit(void)
 538{
 539        log();
 540        unregister_pm_notifier(&pm_notifer);
 541        usb_deregister(&poseidon_driver);
 542}
 543
 544module_init(poseidon_init);
 545module_exit(poseidon_exit);
 546
 547MODULE_AUTHOR("Telegent Systems");
 548MODULE_DESCRIPTION("For tlg2300-based USB device");
 549MODULE_LICENSE("GPL");
 550MODULE_VERSION("0.0.2");
 551MODULE_FIRMWARE(TLG2300_FIRMWARE);
 552