Re: [RFC PATCH 3/6] [media] rc: lirc bridge should not be a raw decoder

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em Thu, 19 Mar 2015 21:50:14 +0000
Sean Young <sean@xxxxxxxx> escreveu:

> The lirc bridge exists as a raw decoder. We would like to make the bridge
> to also work for scancode drivers in further commits, so it cannot be
> a raw decoder.
> 
> Note that rc-code, lirc_dev, ir-lirc-codec are now calling functions of
> each other, so they've been merged into one module rc-core to avoid
> circular dependencies.
> 
> Signed-off-by: Sean Young <sean@xxxxxxxx>
> ---
>  drivers/media/rc/Kconfig         |  15 +++--
>  drivers/media/rc/Makefile        |   6 +-
>  drivers/media/rc/ir-lirc-codec.c | 117 ++++++++++++---------------------------
>  drivers/media/rc/lirc_dev.c      |  18 +-----
>  drivers/media/rc/rc-core-priv.h  |  38 ++++++-------
>  drivers/media/rc/rc-ir-raw.c     |   4 +-
>  drivers/media/rc/rc-main.c       |  21 +++++--
>  include/media/rc-core.h          |   7 +++
>  8 files changed, 92 insertions(+), 134 deletions(-)
> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index ddfab25..efdd6f7 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -6,14 +6,8 @@ config RC_CORE
>  
>  source "drivers/media/rc/keymaps/Kconfig"
>  
> -menuconfig RC_DECODERS
> -        bool "Remote controller decoders"
> -	depends on RC_CORE
> -	default y
> -
> -if RC_DECODERS
>  config LIRC
> -	tristate "LIRC interface driver"
> +	bool "LIRC interface driver"
>  	depends on RC_CORE
>  
>  	---help---
> @@ -24,7 +18,7 @@ config LIRC
>  	   encoding for IR transmitting (aka "blasting").
>  
>  config IR_LIRC_CODEC
> -	tristate "Enable IR to LIRC bridge"
> +	bool "Enable IR to LIRC bridge"
>  	depends on RC_CORE
>  	depends on LIRC
>  	default y
> @@ -33,7 +27,12 @@ config IR_LIRC_CODEC
>  	   Enable this option to pass raw IR to and from userspace via
>  	   the LIRC interface.
>  
> +menuconfig RC_DECODERS
> +	bool "Remote controller decoders"
> +	depends on RC_CORE
> +	default y
>  
> +if RC_DECODERS
>  config IR_NEC_DECODER
>  	tristate "Enable IR raw decoder for the NEC protocol"
>  	depends on RC_CORE
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index 379a5c0..c8e7b38 100644
> --- a/drivers/media/rc/Makefile
> +++ b/drivers/media/rc/Makefile
> @@ -1,9 +1,10 @@
> -rc-core-objs	:= rc-main.o rc-ir-raw.o
>  
>  obj-y += keymaps/
>  
>  obj-$(CONFIG_RC_CORE) += rc-core.o
> -obj-$(CONFIG_LIRC) += lirc_dev.o
> +rc-core-y := rc-main.o rc-ir-raw.o
> +rc-core-$(CONFIG_LIRC) += lirc_dev.o
> +rc-core-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o

It seems OK to me to not consider LIRC as a decoder, but I wouldn't add
it inside RC core. The best seems to convert lirc dev to be a 
separate module.

Thanks!
Mauro


>  obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
>  obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
>  obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
> @@ -12,7 +13,6 @@ obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
>  obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
>  obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
>  obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
> -obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
>  obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
>  
>  # stand-alone IR receivers/transmitters
> diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
> index 17fd956..475f6af 100644
> --- a/drivers/media/rc/ir-lirc-codec.c
> +++ b/drivers/media/rc/ir-lirc-codec.c
> @@ -14,7 +14,6 @@
>  
>  #include <linux/sched.h>
>  #include <linux/wait.h>
> -#include <linux/module.h>
>  #include <media/lirc.h>
>  #include <media/lirc_dev.h>
>  #include <media/rc-core.h>
> @@ -30,15 +29,12 @@
>   *
>   * This function returns -EINVAL if the lirc interfaces aren't wired up.
>   */
> -static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  {
> -	struct lirc_codec *lirc = &dev->raw->lirc;
> +	struct lirc_driver *lirc = dev->lirc;
>  	int sample;
>  
> -	if (!(dev->enabled_protocols & RC_BIT_LIRC))
> -		return 0;
> -
> -	if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
> +	if (!lirc || !lirc->rbuf)
>  		return -EINVAL;
>  
>  	/* Packet start */
> @@ -59,14 +55,14 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	/* Packet end */
>  	} else if (ev.timeout) {
>  
> -		if (lirc->gap)
> +		if (dev->gap)
>  			return 0;
>  
> -		lirc->gap_start = ktime_get();
> -		lirc->gap = true;
> -		lirc->gap_duration = ev.duration;
> +		dev->gap_start = ktime_get();
> +		dev->gap = true;
> +		dev->gap_duration = ev.duration;
>  
> -		if (!lirc->send_timeout_reports)
> +		if (!dev->send_timeout_reports)
>  			return 0;
>  
>  		sample = LIRC_TIMEOUT(ev.duration / 1000);
> @@ -75,21 +71,21 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  	/* Normal sample */
>  	} else {
>  
> -		if (lirc->gap) {
> +		if (dev->gap) {
>  			int gap_sample;
>  
> -			lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
> -				lirc->gap_start));
> +			dev->gap_duration += ktime_to_ns(
> +				ktime_sub(ktime_get(), dev->gap_start));
>  
>  			/* Convert to ms and cap by LIRC_VALUE_MASK */
> -			do_div(lirc->gap_duration, 1000);
> -			lirc->gap_duration = min(lirc->gap_duration,
> -							(u64)LIRC_VALUE_MASK);
> +			do_div(dev->gap_duration, 1000);
> +			dev->gap_duration = min_t(u64, dev->gap_duration,
> +							LIRC_VALUE_MASK);
>  
> -			gap_sample = LIRC_SPACE(lirc->gap_duration);
> -			lirc_buffer_write(dev->raw->lirc.drv->rbuf,
> +			gap_sample = LIRC_SPACE(dev->gap_duration);
> +			lirc_buffer_write(lirc->rbuf,
>  						(unsigned char *) &gap_sample);
> -			lirc->gap = false;
> +			dev->gap = false;
>  		}
>  
>  		sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
> @@ -98,9 +94,9 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  			   TO_US(ev.duration), TO_STR(ev.pulse));
>  	}
>  
> -	lirc_buffer_write(dev->raw->lirc.drv->rbuf,
> +	lirc_buffer_write(lirc->rbuf,
>  			  (unsigned char *) &sample);
> -	wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
> +	wake_up(&lirc->rbuf->wait_poll);
>  
>  	return 0;
>  }
> @@ -108,7 +104,6 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
>  static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>  				   size_t n, loff_t *ppos)
>  {
> -	struct lirc_codec *lirc;
>  	struct rc_dev *dev;
>  	unsigned int *txbuf; /* buffer with values to transmit */
>  	ssize_t ret = -EINVAL;
> @@ -120,8 +115,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>  
>  	start = ktime_get();
>  
> -	lirc = lirc_get_pdata(file);
> -	if (!lirc)
> +	dev = lirc_get_pdata(file);
> +	if (!dev || !dev->lirc)
>  		return -EFAULT;
>  
>  	if (n < sizeof(unsigned) || n % sizeof(unsigned))
> @@ -135,12 +130,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
>  	if (IS_ERR(txbuf))
>  		return PTR_ERR(txbuf);
>  
> -	dev = lirc->dev;
> -	if (!dev) {
> -		ret = -EFAULT;
> -		goto out;
> -	}
> -
>  	if (!dev->tx_ir) {
>  		ret = -ENOSYS;
>  		goto out;
> @@ -183,18 +172,13 @@ out:
>  static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
>  			unsigned long arg)
>  {
> -	struct lirc_codec *lirc;
>  	struct rc_dev *dev;
>  	u32 __user *argp = (u32 __user *)(arg);
>  	int ret = 0;
>  	__u32 val = 0, tmp;
>  
> -	lirc = lirc_get_pdata(filep);
> -	if (!lirc)
> -		return -EFAULT;
> -
> -	dev = lirc->dev;
> -	if (!dev)
> +	dev  = lirc_get_pdata(filep);
> +	if (!dev || !dev->lirc)
>  		return -EFAULT;
>  
>  	if (_IOC_DIR(cmd) & _IOC_WRITE) {
> @@ -253,14 +237,14 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
>  			return -EINVAL;
>  
>  		return dev->s_rx_carrier_range(dev,
> -					       dev->raw->lirc.carrier_low,
> +					       dev->carrier_low,
>  					       val);
>  
>  	case LIRC_SET_REC_CARRIER_RANGE:
>  		if (val <= 0)
>  			return -EINVAL;
>  
> -		dev->raw->lirc.carrier_low = val;
> +		dev->carrier_low = val;
>  		return 0;
>  
>  	case LIRC_GET_REC_RESOLUTION:
> @@ -306,7 +290,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
>  		break;
>  
>  	case LIRC_SET_REC_TIMEOUT_REPORTS:
> -		lirc->send_timeout_reports = !!val;
> +		dev->send_timeout_reports = !!val;
>  		break;
>  
>  	default:
> @@ -343,7 +327,7 @@ static const struct file_operations lirc_fops = {
>  	.llseek		= no_llseek,
>  };
>  
> -static int ir_lirc_register(struct rc_dev *dev)
> +int ir_lirc_register(struct rc_dev *dev)
>  {
>  	struct lirc_driver *drv;
>  	struct lirc_buffer *rbuf;
> @@ -390,7 +374,7 @@ static int ir_lirc_register(struct rc_dev *dev)
>  		 dev->driver_name);
>  	drv->minor = -1;
>  	drv->features = features;
> -	drv->data = &dev->raw->lirc;
> +	drv->data = dev;
>  	drv->rbuf = rbuf;
>  	drv->set_use_inc = &ir_lirc_open;
>  	drv->set_use_dec = &ir_lirc_close;
> @@ -406,8 +390,7 @@ static int ir_lirc_register(struct rc_dev *dev)
>  		goto lirc_register_failed;
>  	}
>  
> -	dev->raw->lirc.drv = drv;
> -	dev->raw->lirc.dev = dev;
> +	dev->lirc = drv;
>  	return 0;
>  
>  lirc_register_failed:
> @@ -419,41 +402,11 @@ rbuf_alloc_failed:
>  	return rc;
>  }
>  
> -static int ir_lirc_unregister(struct rc_dev *dev)
> +void ir_lirc_unregister(struct rc_dev *dev)
>  {
> -	struct lirc_codec *lirc = &dev->raw->lirc;
> -
> -	lirc_unregister_driver(lirc->drv->minor);
> -	lirc_buffer_free(lirc->drv->rbuf);
> -	kfree(lirc->drv);
> -
> -	return 0;
> -}
> -
> -static struct ir_raw_handler lirc_handler = {
> -	.protocols	= RC_BIT_LIRC,
> -	.decode		= ir_lirc_decode,
> -	.raw_register	= ir_lirc_register,
> -	.raw_unregister	= ir_lirc_unregister,
> -};
> -
> -static int __init ir_lirc_codec_init(void)
> -{
> -	ir_raw_handler_register(&lirc_handler);
> -
> -	printk(KERN_INFO "IR LIRC bridge handler initialized\n");
> -	return 0;
> -}
> -
> -static void __exit ir_lirc_codec_exit(void)
> -{
> -	ir_raw_handler_unregister(&lirc_handler);
> +	if (dev->lirc) {
> +		lirc_unregister_driver(dev->lirc->minor);
> +		lirc_buffer_free(dev->lirc->rbuf);
> +		kfree(dev->lirc);
> +	}
>  }
> -
> -module_init(ir_lirc_codec_init);
> -module_exit(ir_lirc_codec_exit);
> -
> -MODULE_LICENSE("GPL");
> -MODULE_AUTHOR("Jarod Wilson <jarod@xxxxxxxxxx>");
> -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
> -MODULE_DESCRIPTION("LIRC IR handler bridge");
> diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
> index 4de0e85..44a61e81 100644
> --- a/drivers/media/rc/lirc_dev.c
> +++ b/drivers/media/rc/lirc_dev.c
> @@ -39,8 +39,6 @@
>  #include <media/lirc.h>
>  #include <media/lirc_dev.h>
>  
> -static bool debug;
> -
>  #define IRCTL_DEV_NAME	"BaseRemoteCtl"
>  #define NOPLUG		-1
>  #define LOGHEAD		"lirc_dev (%s[%d]): "
> @@ -785,8 +783,7 @@ ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
>  }
>  EXPORT_SYMBOL(lirc_dev_fop_write);
>  
> -
> -static int __init lirc_dev_init(void)
> +int __init lirc_dev_init(void)
>  {
>  	int retval;
>  
> @@ -813,21 +810,10 @@ error:
>  	return retval;
>  }
>  
> -
> -
> -static void __exit lirc_dev_exit(void)
> +void __exit lirc_dev_exit(void)
>  {
>  	class_destroy(lirc_class);
>  	unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
>  	printk(KERN_INFO "lirc_dev: module unloaded\n");
>  }
>  
> -module_init(lirc_dev_init);
> -module_exit(lirc_dev_exit);
> -
> -MODULE_DESCRIPTION("LIRC base driver module");
> -MODULE_AUTHOR("Artur Lipowski");
> -MODULE_LICENSE("GPL");
> -
> -module_param(debug, bool, S_IRUGO | S_IWUSR);
> -MODULE_PARM_DESC(debug, "Enable debugging messages");
> diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
> index b68d4f76..732479d 100644
> --- a/drivers/media/rc/rc-core-priv.h
> +++ b/drivers/media/rc/rc-core-priv.h
> @@ -26,7 +26,7 @@ struct ir_raw_handler {
>  	u64 protocols; /* which are handled by this handler */
>  	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
>  
> -	/* These two should only be used by the lirc decoder */
> +	/* These two should only be used by the mce kbd decoder */
>  	int (*raw_register)(struct rc_dev *dev);
>  	int (*raw_unregister)(struct rc_dev *dev);
>  };
> @@ -99,17 +99,6 @@ struct ir_raw_event_ctrl {
>  		unsigned count;
>  		unsigned wanted_bits;
>  	} mce_kbd;
> -	struct lirc_codec {
> -		struct rc_dev *dev;
> -		struct lirc_driver *drv;
> -		int carrier_low;
> -
> -		ktime_t gap_start;
> -		u64 gap_duration;
> -		bool gap;
> -		bool send_timeout_reports;
> -
> -	} lirc;
>  	struct xmp_dec {
>  		int state;
>  		unsigned count;
> @@ -223,13 +212,6 @@ static inline void load_sharp_decode(void) { }
>  static inline void load_mce_kbd_decode(void) { }
>  #endif
>  
> -/* from ir-lirc-codec.c */
> -#ifdef CONFIG_IR_LIRC_CODEC_MODULE
> -#define load_lirc_codec()	request_module_nowait("ir-lirc-codec")
> -#else
> -static inline void load_lirc_codec(void) { }
> -#endif
> -
>  /* from ir-xmp-decoder.c */
>  #ifdef CONFIG_IR_XMP_DECODER_MODULE
>  #define load_xmp_decode()      request_module_nowait("ir-xmp-decoder")
> @@ -237,5 +219,23 @@ static inline void load_lirc_codec(void) { }
>  static inline void load_xmp_decode(void) { }
>  #endif
>  
> +#ifdef CONFIG_IR_LIRC_CODEC
> +void ir_lirc_unregister(struct rc_dev *dev);
> +int ir_lirc_register(struct rc_dev *dev);
> +int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev);
> +#else
> +static inline void ir_lirc_unregister(struct rc_dev *dev) {}
> +static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
> +static inline int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
> +								{ return 0; }
> +#endif
> +
> +#ifdef CONFIG_LIRC
> +int __init lirc_dev_init(void);
> +void __exit lirc_dev_exit(void);
> +#else
> +int __init lirc_dev_init(void) { return 0; }
> +void __exit lirc_dev_exit(void) {}
> +#endif
>  
>  #endif /* _RC_CORE_PRIV */
> diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
> index b732ac6..d298be7 100644
> --- a/drivers/media/rc/rc-ir-raw.c
> +++ b/drivers/media/rc/rc-ir-raw.c
> @@ -57,6 +57,9 @@ static int ir_raw_event_thread(void *data)
>  		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
>  		spin_unlock_irq(&raw->lock);
>  
> +		if (raw->dev->lirc)
> +			ir_lirc_decode(raw->dev, ev);
> +
>  		mutex_lock(&ir_raw_handler_lock);
>  		list_for_each_entry(handler, &ir_raw_handler_list, list)
>  			handler->decode(raw->dev, ev);
> @@ -360,7 +363,6 @@ void ir_raw_init(void)
>  	load_sanyo_decode();
>  	load_sharp_decode();
>  	load_mce_kbd_decode();
> -	load_lirc_codec();
>  	load_xmp_decode();
>  
>  	/* If needed, we may later add some init code. In this case,
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index f8c5e47..128909c 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -732,7 +732,6 @@ int rc_open(struct rc_dev *rdev)
>  
>  	return rval;
>  }
> -EXPORT_SYMBOL_GPL(rc_open);
>  
>  static int ir_open(struct input_dev *idev)
>  {
> @@ -752,7 +751,6 @@ void rc_close(struct rc_dev *rdev)
>  		mutex_unlock(&rdev->lock);
>  	}
>  }
> -EXPORT_SYMBOL_GPL(rc_close);
>  
>  static void ir_close(struct input_dev *idev)
>  {
> @@ -1419,15 +1417,17 @@ int rc_register_device(struct rc_dev *dev)
>  		mutex_lock(&dev->lock);
>  		if (rc < 0)
>  			goto out_input;
> +
> +		rc = ir_lirc_register(dev);
> +		if (rc < 0)
> +			goto out_raw;
>  	}
>  
>  	if (dev->change_protocol) {
>  		u64 rc_type = (1ll << rc_map->rc_type);
> -		if (dev->driver_type == RC_DRIVER_IR_RAW)
> -			rc_type |= RC_BIT_LIRC;
>  		rc = dev->change_protocol(dev, &rc_type);
>  		if (rc < 0)
> -			goto out_raw;
> +			goto out_lirc;
>  		dev->enabled_protocols = rc_type;
>  	}
>  
> @@ -1441,6 +1441,8 @@ int rc_register_device(struct rc_dev *dev)
>  
>  	return 0;
>  
> +out_lirc:
> +	ir_lirc_unregister(dev);
>  out_raw:
>  	if (dev->driver_type == RC_DRIVER_IR_RAW)
>  		ir_raw_event_unregister(dev);
> @@ -1470,6 +1472,8 @@ void rc_unregister_device(struct rc_dev *dev)
>  	if (dev->driver_type == RC_DRIVER_IR_RAW)
>  		ir_raw_event_unregister(dev);
>  
> +	ir_lirc_unregister(dev);
> +
>  	/* Freeing the table should also call the stop callback */
>  	ir_free_table(&dev->rc_map);
>  	IR_dprintk(1, "Freed keycode table\n");
> @@ -1495,6 +1499,12 @@ static int __init rc_core_init(void)
>  		printk(KERN_ERR "rc_core: unable to register rc class\n");
>  		return rc;
>  	}
> +	rc = lirc_dev_init();
> +	if (rc) {
> +		class_unregister(&rc_class);
> +		printk(KERN_ERR "rc_core: unable to register lirc class\n");
> +		return rc;
> +	}
>  
>  	led_trigger_register_simple("rc-feedback", &led_feedback);
>  	rc_map_register(&empty_map);
> @@ -1507,6 +1517,7 @@ static void __exit rc_core_exit(void)
>  	class_unregister(&rc_class);
>  	led_trigger_unregister_simple(led_feedback);
>  	rc_map_unregister(&empty_map);
> +	lirc_dev_exit();
>  }
>  
>  subsys_initcall(rc_core_init);
> diff --git a/include/media/rc-core.h b/include/media/rc-core.h
> index 2c7fbca..e3f217c 100644
> --- a/include/media/rc-core.h
> +++ b/include/media/rc-core.h
> @@ -156,6 +156,13 @@ struct rc_dev {
>  	u32				max_timeout;
>  	u32				rx_resolution;
>  	u32				tx_resolution;
> +	/* lirc state */
> +	struct lirc_driver		*lirc;
> +	int				carrier_low;
> +	ktime_t				gap_start;
> +	u64				gap_duration;
> +	bool				gap;
> +	bool				send_timeout_reports;
>  	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	int				(*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
>  	int				(*open)(struct rc_dev *dev);
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux