Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[sfrench/cifs-2.6.git] / drivers / media / video / em28xx / em28xx-core.c
index d56484f204677105c9fd435fdeb7bf8aca30ed75..c1caaa855b99b16e9d09962a0000e5d48817bd5f 100644 (file)
@@ -72,7 +72,8 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
        const size_t imagesize = PAGE_ALIGN(dev->frame_size);   /*needs to be page aligned cause the buffers can be mapped individually! */
        void *buff = NULL;
        u32 i;
-       em28xx_coredbg("requested %i buffers with size %zi", count, imagesize);
+       em28xx_coredbg("requested %i buffers with size %zi\n",
+                       count, imagesize);
        if (count > EM28XX_NUM_FRAMES)
                count = EM28XX_NUM_FRAMES;
 
@@ -150,7 +151,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
        if (reg_debug){
                printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
                for (byte = 0; byte < len; byte++) {
-                       printk(" %02x", buf[byte]);
+                       printk(" %02x", (unsigned char)buf[byte]);
                }
                printk("\n");
        }
@@ -177,7 +178,8 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
                              0x0000, reg, &val, 1, HZ);
 
        if (reg_debug)
-               printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+               printk(ret < 0 ? " failed!\n" :
+                                "%02x\n", (unsigned char) val);
 
        if (ret < 0)
                return ret;
@@ -237,7 +239,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
  * sets only some bits (specified by bitmask) of a register, by first reading
  * the actual value
  */
-int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
                                 u8 bitmask)
 {
        int oldval;
@@ -252,32 +254,122 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
  * em28xx_write_ac97()
  * write a 16 bit value to the specified AC97 address (LSB first!)
  */
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
 {
-       int ret;
+       int ret, i;
        u8 addr = reg & 0x7f;
        if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
                return ret;
        if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
                return ret;
-       if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
-               return ret;
-       else if (((u8) ret) & 0x01) {
-               em28xx_warn ("AC97 command still being executed: not handled properly!\n");
+
+       /* Wait up to 50 ms for AC97 command to complete */
+       for (i = 0; i < 10; i++) {
+               if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+                       return ret;
+               if (!(ret & 0x01))
+                       return 0;
+               msleep(5);
        }
+       em28xx_warn ("AC97 command still being executed: not handled properly!\n");
        return 0;
 }
 
+static int em28xx_set_audio_source(struct em28xx *dev)
+{
+       static char *enable  = "\x08\x08";
+       static char *disable = "\x08\x88";
+       char *video = enable, *line = disable;
+       int ret;
+       u8 input;
+
+       if (dev->is_em2800) {
+               if (dev->ctl_ainput)
+                       input = EM2800_AUDIO_SRC_LINE;
+               else
+                       input = EM2800_AUDIO_SRC_TUNER;
+
+               ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (dev->has_msp34xx)
+               input = EM28XX_AUDIO_SRC_TUNER;
+       else {
+               switch (dev->ctl_ainput) {
+               case EM28XX_AMUX_VIDEO:
+                       input = EM28XX_AUDIO_SRC_TUNER;
+                       break;
+               case EM28XX_AMUX_LINE_IN:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       break;
+               case EM28XX_AMUX_AC97_VIDEO:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       break;
+               case EM28XX_AMUX_AC97_LINE_IN:
+                       input = EM28XX_AUDIO_SRC_LINE;
+                       video = disable;
+                       line  = enable;
+                       break;
+               }
+       }
+
+       ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+       if (ret < 0)
+               return ret;
+       msleep(5);
+
+       /* Sets AC97 mixer registers
+          This is seems to be needed, even for non-ac97 configs
+        */
+       ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+
+       return ret;
+}
+
 int em28xx_audio_analog_set(struct em28xx *dev)
 {
+       int ret;
        char s[2] = { 0x00, 0x00 };
+       u8 xclk = 0x07;
+
        s[0] |= 0x1f - dev->volume;
        s[1] |= 0x1f - dev->volume;
-       if (dev->mute)
-               s[1] |= 0x80;
-       return em28xx_write_ac97(dev, MASTER_AC97, s);
-}
 
+       /* Mute */
+       s[1] |= 0x80;
+       ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+
+       if (ret < 0)
+               return ret;
+
+       if (dev->has_12mhz_i2s)
+               xclk |= 0x20;
+
+       if (!dev->mute)
+               xclk |= 0x80;
+
+       ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+       if (ret < 0)
+               return ret;
+       msleep(10);
+
+       /* Selects the proper audio input */
+       ret = em28xx_set_audio_source(dev);
+
+       /* Unmute device */
+       if (!dev->mute)
+               s[1] &= ~0x80;
+       ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
@@ -585,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb)
                                continue;
                        }
                        if (urb->iso_frame_desc[i].actual_length >
-                                                dev->max_pkt_size) {
+                           urb->iso_frame_desc[i].length) {
                                em28xx_isocdbg("packet bigger than packet size");
                                continue;
                        }
@@ -631,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev)
        for (i = 0; i < EM28XX_NUM_BUFS; i++) {
                if (dev->urb[i]) {
                        usb_kill_urb(dev->urb[i]);
-                       if (dev->transfer_buffer[i]){
-                               usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+                       if (dev->transfer_buffer[i]) {
+                               usb_buffer_free(dev->udev,
+                                               dev->urb[i]->transfer_buffer_length,
+                                               dev->transfer_buffer[i],
+                                               dev->urb[i]->transfer_dma);
                        }
                        usb_free_urb(dev->urb[i]);
                }
@@ -650,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev)
 {
        /* change interface to 3 which allows the biggest packet sizes */
        int i, errCode;
-       const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+       int sb_size;
+
+       em28xx_set_alternate(dev);
+       sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
 
        /* reset streaming vars */
        dev->frame_current = NULL;
@@ -659,7 +757,7 @@ int em28xx_init_isoc(struct em28xx *dev)
        /* allocate urbs */
        for (i = 0; i < EM28XX_NUM_BUFS; i++) {
                struct urb *urb;
-               int j, k;
+               int j;
                /* allocate transfer buffer */
                urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
                if (!urb){
@@ -667,7 +765,9 @@ int em28xx_init_isoc(struct em28xx *dev)
                        em28xx_uninit_isoc(dev);
                        return -ENOMEM;
                }
-               dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+               dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
+                                                          GFP_KERNEL,
+                                                          &urb->transfer_dma);
                if (!dev->transfer_buffer[i]) {
                        em28xx_errdev
                                        ("unable to allocate %i bytes for transfer buffer %i\n",
@@ -680,22 +780,22 @@ int em28xx_init_isoc(struct em28xx *dev)
                urb->dev = dev->udev;
                urb->context = dev;
                urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
-               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                urb->interval = 1;
                urb->transfer_buffer = dev->transfer_buffer[i];
                urb->complete = em28xx_isocIrq;
                urb->number_of_packets = EM28XX_NUM_PACKETS;
                urb->transfer_buffer_length = sb_size;
-               for (j = k = 0; j < EM28XX_NUM_PACKETS;
-                               j++, k += dev->max_pkt_size) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length =
-                               dev->max_pkt_size;
+               for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
+                       urb->iso_frame_desc[j].length = dev->max_pkt_size;
                }
                dev->urb[i] = urb;
        }
 
        /* submit urbs */
+       em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
+                      EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
        for (i = 0; i < EM28XX_NUM_BUFS; i++) {
                errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
                if (errCode) {
@@ -712,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev)
 int em28xx_set_alternate(struct em28xx *dev)
 {
        int errCode, prev_alt = dev->alt;
-       dev->alt = alt;
-       if (dev->alt == 0) {
-               int i;
-               for(i=0;i< dev->num_alt; i++)
-                       if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
-                               dev->alt=i;
-       }
+       int i;
+       unsigned int min_pkt_size = dev->bytesperline+4;
+
+       /* When image size is bigger than a ceirtain value,
+          the frame size should be increased, otherwise, only
+          green screen will be received.
+        */
+       if (dev->frame_size > 720*240*2)
+               min_pkt_size *= 2;
+
+       for (i = 0; i < dev->num_alt; i++)
+               if (dev->alt_max_pkt_size[i] >= min_pkt_size)
+                       break;
+       dev->alt = i;
 
        if (dev->alt != prev_alt) {
+               em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+                               min_pkt_size, dev->alt);
                dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
-               em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
-                      dev->max_pkt_size);
+               em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+                              dev->alt, dev->max_pkt_size);
                errCode = usb_set_interface(dev->udev, 0, dev->alt);
                if (errCode < 0) {
                        em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
-                                                       dev->alt, errCode);
+                                       dev->alt, errCode);
                        return errCode;
                }
        }