Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 357140
b: refs/heads/master
c: c647a91
h: refs/heads/master
v: v3
  • Loading branch information
Frank Schaefer authored and Mauro Carvalho Chehab committed Dec 22, 2012
1 parent a4522f4 commit e2a28bf
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 41 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c8e9d95b41f2a441b2af0a1899448dd45ad7632d
refs/heads/master: c647a91a2558c4031eddd013e5860ca5a41363a7
95 changes: 77 additions & 18 deletions trunk/drivers/media/usb/em28xx/em28xx-cards.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
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
Expand Down Expand Up @@ -3209,26 +3210,67 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (udev->speed == USB_SPEED_HIGH)
size = size * hb_mult(sizedescr);

if (usb_endpoint_xfer_isoc(e) &&
usb_endpoint_dir_in(e)) {
if (usb_endpoint_dir_in(e)) {
switch (e->bEndpointAddress) {
case EM28XX_EP_AUDIO:
has_audio = true;
break;
case EM28XX_EP_ANALOG:
case 0x82:
has_video = true;
dev->alt_max_pkt_size_isoc[i] = size;
if (usb_endpoint_xfer_isoc(e)) {
dev->analog_ep_isoc =
e->bEndpointAddress;
dev->alt_max_pkt_size_isoc[i] = size;
} else if (usb_endpoint_xfer_bulk(e)) {
dev->analog_ep_bulk =
e->bEndpointAddress;
}
break;
case 0x83:
if (usb_endpoint_xfer_isoc(e)) {
has_audio = true;
} else {
printk(KERN_INFO DRIVER_NAME
": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
}
break;
case EM28XX_EP_DIGITAL:
has_dvb = true;
if (size > dev->dvb_max_pkt_size_isoc) {
dev->dvb_max_pkt_size_isoc =
size;
dev->dvb_alt_isoc = i;
case 0x84:
if (has_video &&
(usb_endpoint_xfer_bulk(e))) {
dev->analog_ep_bulk =
e->bEndpointAddress;
} else {
has_dvb = true;
if (usb_endpoint_xfer_isoc(e)) {
dev->dvb_ep_isoc = e->bEndpointAddress;
if (size > dev->dvb_max_pkt_size_isoc) {
dev->dvb_max_pkt_size_isoc = size;
dev->dvb_alt_isoc = i;
}
} else {
dev->dvb_ep_bulk = e->bEndpointAddress;
}
}
break;
}
}
/* NOTE:
* Old logic with support for isoc transfers only was:
* 0x82 isoc => analog
* 0x83 isoc => audio
* 0x84 isoc => digital
*
* New logic with support for bulk transfers
* 0x82 isoc => analog
* 0x82 bulk => analog
* 0x83 isoc* => audio
* 0x84 isoc => digital
* 0x84 bulk => analog or digital**
* (*: audio should always be isoc)
* (**: analog, if ep 0x82 is isoc, otherwise digital)
*
* The new logic preserves backwards compatibility and
* reflects the endpoint configurations we have seen
* so far. But there might be devices for which this
* logic is not sufficient...
*/
}
}

Expand Down Expand Up @@ -3289,6 +3331,12 @@ static int em28xx_usb_probe(struct usb_interface *interface,
goto err_free;
}

/* Select USB transfer types to use */
if (has_video && !dev->analog_ep_isoc)
dev->analog_xfer_bulk = 1;
if (has_dvb && !dev->dvb_ep_isoc)
dev->dvb_xfer_bulk = 1;

snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
Expand Down Expand Up @@ -3323,12 +3371,23 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}

if (has_dvb) {
/* pre-allocate DVB isoc transfer buffers */
retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, 0,
EM28XX_DVB_NUM_BUFS,
dev->dvb_max_pkt_size_isoc,
EM28XX_DVB_NUM_ISOC_PACKETS);
/* pre-allocate DVB usb transfer buffers */
if (dev->dvb_xfer_bulk) {
retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
512,
EM28XX_DVB_BULK_PACKET_MULTIPLIER);
} else {
retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
dev->dvb_max_pkt_size_isoc,
EM28XX_DVB_NUM_ISOC_PACKETS);
}
if (retval) {
printk(DRIVER_NAME
": Failed to pre-allocate USB transfer buffers for DVB.\n");
goto unlock_and_free;
}
}
Expand Down
32 changes: 26 additions & 6 deletions trunk/drivers/media/usb/em28xx/em28xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,11 +847,13 @@ int em28xx_set_alternate(struct em28xx *dev)
if (dev->alt != prev_alt) {
if (dev->analog_xfer_bulk) {
dev->max_pkt_size = 512; /* USB 2.0 spec */
dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
} else { /* isoc */
em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
min_pkt_size, dev->alt);
dev->max_pkt_size =
dev->alt_max_pkt_size_isoc[dev->alt];
dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
}
em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
dev->alt, dev->max_pkt_size);
Expand Down Expand Up @@ -1054,10 +1056,28 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,

em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);

if (mode == EM28XX_DIGITAL_MODE)
/* Check mode and if we have an endpoint for the selected
transfer type, select buffer */
if (mode == EM28XX_DIGITAL_MODE) {
if ((xfer_bulk && !dev->dvb_ep_bulk) ||
(!xfer_bulk && !dev->dvb_ep_isoc)) {
em28xx_errdev("no endpoint for DVB mode and transfer type %d\n",
xfer_bulk > 0);
return -EINVAL;
}
usb_bufs = &dev->usb_ctl.digital_bufs;
else
} else if (mode == EM28XX_ANALOG_MODE) {
if ((xfer_bulk && !dev->analog_ep_bulk) ||
(!xfer_bulk && !dev->analog_ep_isoc)) {
em28xx_errdev("no endpoint for analog mode and transfer type %d\n",
xfer_bulk > 0);
return -EINVAL;
}
usb_bufs = &dev->usb_ctl.analog_bufs;
} else {
em28xx_errdev("invalid mode selected\n");
return -EINVAL;
}

/* De-allocates all pending stuff */
em28xx_uninit_usb_xfer(dev, mode);
Expand Down Expand Up @@ -1113,17 +1133,17 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
if (xfer_bulk) { /* bulk */
pipe = usb_rcvbulkpipe(dev->udev,
mode == EM28XX_ANALOG_MODE ?
EM28XX_EP_ANALOG :
EM28XX_EP_DIGITAL);
dev->analog_ep_bulk :
dev->dvb_ep_bulk);
usb_fill_bulk_urb(urb, dev->udev, pipe,
usb_bufs->transfer_buffer[i], sb_size,
em28xx_irq_callback, dev);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
} else { /* isoc */
pipe = usb_rcvisocpipe(dev->udev,
mode == EM28XX_ANALOG_MODE ?
EM28XX_EP_ANALOG :
EM28XX_EP_DIGITAL);
dev->analog_ep_isoc :
dev->dvb_ep_isoc);
usb_fill_int_urb(urb, dev->udev, pipe,
usb_bufs->transfer_buffer[i], sb_size,
em28xx_irq_callback, dev, 1);
Expand Down
34 changes: 24 additions & 10 deletions trunk/drivers/media/usb/em28xx/em28xx-dvb.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,25 +176,39 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
{
int rc;
struct em28xx *dev = dvb->adapter.priv;
int max_dvb_packet_size;
int dvb_max_packet_size, packet_multiplier, dvb_alt;

if (dev->dvb_xfer_bulk) {
if (!dev->dvb_ep_bulk)
return -ENODEV;
dvb_max_packet_size = 512; /* USB 2.0 spec */
packet_multiplier = EM28XX_DVB_BULK_PACKET_MULTIPLIER;
dvb_alt = 0;
} else { /* isoc */
if (!dev->dvb_ep_isoc)
return -ENODEV;
dvb_max_packet_size = dev->dvb_max_pkt_size_isoc;
if (dvb_max_packet_size < 0)
return dvb_max_packet_size;
packet_multiplier = EM28XX_DVB_NUM_ISOC_PACKETS;
dvb_alt = dev->dvb_alt_isoc;
}

usb_set_interface(dev->udev, 0, dev->dvb_alt_isoc);
usb_set_interface(dev->udev, 0, dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;

max_dvb_packet_size = dev->dvb_max_pkt_size_isoc;
if (max_dvb_packet_size < 0)
return max_dvb_packet_size;
dprintk(1, "Using %d buffers each with %d x %d bytes\n",
EM28XX_DVB_NUM_BUFS,
EM28XX_DVB_NUM_ISOC_PACKETS,
max_dvb_packet_size);
packet_multiplier,
dvb_max_packet_size);

return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE, 0,
return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
max_dvb_packet_size,
EM28XX_DVB_NUM_ISOC_PACKETS,
dvb_max_packet_size,
packet_multiplier,
em28xx_dvb_urb_data_copy);
}

Expand Down
4 changes: 2 additions & 2 deletions trunk/drivers/media/usb/em28xx/em28xx-reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#define EM_GPO_3 (1 << 3)

/* em28xx endpoints */
#define EM28XX_EP_ANALOG 0x82
/* 0x82: (always ?) analog */
#define EM28XX_EP_AUDIO 0x83
#define EM28XX_EP_DIGITAL 0x84
/* 0x84: digital or analog */

/* em2800 registers */
#define EM2800_R08_AUDIOSRC 0x08
Expand Down
10 changes: 6 additions & 4 deletions trunk/drivers/media/usb/em28xx/em28xx-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,16 +788,18 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,

if (urb_init) {
if (em28xx_vbi_supported(dev) == 1)
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE, 0,
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
dev->analog_xfer_bulk,
EM28XX_NUM_BUFS,
dev->max_pkt_size,
EM28XX_NUM_ISOC_PACKETS,
dev->packet_multiplier,
em28xx_urb_data_copy_vbi);
else
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE, 0,
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
dev->analog_xfer_bulk,
EM28XX_NUM_BUFS,
dev->max_pkt_size,
EM28XX_NUM_ISOC_PACKETS,
dev->packet_multiplier,
em28xx_urb_data_copy);
if (rc < 0)
goto fail;
Expand Down
12 changes: 12 additions & 0 deletions trunk/drivers/media/usb/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@
#define EM28XX_NUM_ISOC_PACKETS 64
#define EM28XX_DVB_NUM_ISOC_PACKETS 64

/* bulk transfers: transfer buffer size = packet size * packet multiplier
USB 2.0 spec says bulk packet size is always 512 bytes
*/
#define EM28XX_BULK_PACKET_MULTIPLIER 384
#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384

#define EM28XX_INTERLACED_DEFAULT 1

/*
Expand Down Expand Up @@ -584,8 +590,14 @@ struct em28xx {

/* usb transfer */
struct usb_device *udev; /* the usb device */
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
u8 dvb_ep_bulk; /* address of bulk endpoint for DVC */
int alt; /* alternate setting */
int max_pkt_size; /* max packet size of the selected ep at alt */
int packet_multiplier; /* multiplier for wMaxPacketSize, used for
URB buffer size definition */
int num_alt; /* number of alternative settings */
unsigned int *alt_max_pkt_size_isoc; /* array of isoc wMaxPacketSize */
unsigned int analog_xfer_bulk:1; /* use bulk instead of isoc
Expand Down

0 comments on commit e2a28bf

Please sign in to comment.