ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
- if (!down_interruptible(&dec->pes2ts_sem)) {
dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
ttusb_dec_av_pes2ts_cb, dec->demux.feed);
dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
ttusb_dec_av_pes2ts_cb, dec->demux.feed);
-
- up(&dec->pes2ts_sem);
- }
}
static int ttusb_dec_i2c_master_xfer(struct dvb_i2c_bus *i2c,
memcpy(&dec->v_pes[dec->v_pes_length],
&av_pes[12], prebytes);
- if (!down_interruptible(&dec->pes2ts_sem)) {
- dvb_filter_pes2ts(&dec->v_pes2ts,
- dec->v_pes,
- dec->v_pes_length +
- prebytes);
-
- up(&dec->pes2ts_sem);
- }
+ dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
+ dec->v_pes_length + prebytes);
}
if (av_pes[5] & 0x10) {
postbytes);
memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
- if (postbytes == 0) {
- if (!down_interruptible(&dec->pes2ts_sem)) {
- dvb_filter_pes2ts(&dec->v_pes2ts,
- dec->v_pes,
+ if (postbytes == 0)
+ dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
dec->v_pes_length);
- up(&dec->pes2ts_sem);
- }
- }
-
break;
}
}
}
+static void ttusb_dec_process_urb_frame_list(unsigned long data)
+{
+ struct ttusb_dec *dec = (struct ttusb_dec *)data;
+ struct list_head *item;
+ struct urb_frame *frame;
+ unsigned long flags;
+
+ while (1) {
+ spin_lock_irqsave(&dec->urb_frame_list_lock, flags);
+ if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
+ frame = list_entry(item, struct urb_frame,
+ urb_frame_list);
+ list_del(&frame->urb_frame_list);
+ } else {
+ spin_unlock_irqrestore(&dec->urb_frame_list_lock,
+ flags);
+ return;
+ }
+ spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags);
+
+ ttusb_dec_process_urb_frame(dec, frame->data, frame->length);
+ kfree(frame);
+ }
+}
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void ttusb_dec_process_urb(struct urb *urb)
#else
struct usb_iso_packet_descriptor *d;
u8 *b;
int length;
+ struct urb_frame *frame;
d = &urb->iso_frame_desc[i];
b = urb->transfer_buffer + d->offset;
length = d->actual_length;
- ttusb_dec_process_urb_frame(dec, b, length);
+ if ((frame = kmalloc(sizeof(struct urb_frame),
+ GFP_ATOMIC))) {
+ unsigned long flags;
+
+ memcpy(frame->data, b, length);
+ frame->length = length;
+
+ spin_lock_irqsave(&dec->urb_frame_list_lock,
+ flags);
+ list_add_tail(&frame->urb_frame_list,
+ &dec->urb_frame_list);
+ spin_unlock_irqrestore(&dec->urb_frame_list_lock,
+ flags);
+
+ tasklet_schedule(&dec->urb_tasklet);
+ }
}
} else {
/* -ENOENT is expected when unlinking urbs */
return 0;
}
+static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
+{
+ dec->urb_frame_list_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&dec->urb_frame_list);
+ tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list,
+ (unsigned long)dec);
+}
+
static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
{
dprintk("%s\n", __FUNCTION__);
return result;
}
- sema_init(&dec->pes2ts_sem, 1);
-
dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx);
return 0;
ttusb_dec_free_iso_urbs(dec);
}
+static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
+{
+ struct list_head *item;
+ struct urb_frame *frame;
+
+ tasklet_kill(&dec->urb_tasklet);
+
+ while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
+ frame = list_entry(item, struct urb_frame, urb_frame_list);
+ list_del(&frame->urb_frame_list);
+ kfree(frame);
+ }
+}
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static void *ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum,
const struct usb_device_id *id)
ttusb_dec_init_stb(dec);
ttusb_dec_init_dvb(dec);
ttusb_dec_init_v_pes(dec);
+ ttusb_dec_init_tasklet(dec);
return (void *)dec;
}
ttusb_dec_init_stb(dec);
ttusb_dec_init_dvb(dec);
ttusb_dec_init_v_pes(dec);
+ ttusb_dec_init_tasklet(dec);
usb_set_intfdata(intf, (void *)dec);
ttusb_dec_set_streaming_interface(dec);
dprintk("%s\n", __FUNCTION__);
+ ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_usb(dec);
ttusb_dec_exit_dvb(dec);