--- v2
+++ vrfc
@@ -1,17 +1,17 @@
-Signed-off-by: Yann Cantin <yann.cantin@laposte.net>
+Signed-off-by: Yann Cantin <yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>
---
- drivers/input/misc/Kconfig | 16 +
+ drivers/input/misc/Kconfig | 21 +
drivers/input/misc/Makefile | 1 +
- drivers/input/misc/ebeam.c | 760 +++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 777 insertions(+)
+ drivers/input/misc/ebeam.c | 895 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 917 insertions(+)
create mode 100644 drivers/input/misc/ebeam.c
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
-index 7c0f1ec..1e575e4 100644
+index 7faf4a7..0e798cb 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
-@@ -83,6 +83,22 @@ config INPUT_BMA150
+@@ -73,6 +73,27 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
@@ -31,14 +31,19 @@
+ To compile this driver as a module, choose M here: the
+ module will be called ebeam.
+
++config INPUT_EBEAM_USB_CLASSIC
++ bool "eBeam Classic Projection support"
++ depends on INPUT_EBEAM_USB
++ default y
++
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
-index 83fe6f5..2aa9813 100644
+index f55cdf4..4b5e4a9 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
-@@ -24,6 +24,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
+@@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
@@ -48,15 +53,15 @@
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
diff --git a/drivers/input/misc/ebeam.c b/drivers/input/misc/ebeam.c
new file mode 100644
-index 0000000..9c698a3
+index 0000000..a18615a
--- /dev/null
+++ b/drivers/input/misc/ebeam.c
-@@ -0,0 +1,760 @@
+@@ -0,0 +1,895 @@
+/******************************************************************************
+ *
+ * eBeam driver
+ *
-+ * Copyright (C) 2012 Yann Cantin (yann.cantin@laposte.net)
++ * Copyright (C) 2012 Yann Cantin (yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
@@ -65,11 +70,13 @@
+ *
+ * based on
+ *
-+ * usbtouchscreen.c by Daniel Ritz <daniel.ritz@gmx.ch>
-+ * aiptek.c (sysfs/settings) by Chris Atenasio <chris@crud.net>
-+ * Bryan W. Headley <bwheadley@earthlink.net>
++ * usbtouchscreen.c by Daniel Ritz <daniel.ritz-OI3hZJvNYWs@public.gmane.org>
++ * aiptek.c (sysfs/settings) by Chris Atenasio <chris-v4AJ0sPprEc@public.gmane.org>
++ * Bryan W. Headley <bwheadley-ihVZJaRskl1bRRN4PJnoQQ@public.gmane.org>
+ *
+ *****************************************************************************/
++
++#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
@@ -80,24 +87,57 @@
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
-+#define DRIVER_VERSION "v0.7"
-+#define DRIVER_AUTHOR "Yann Cantin <yann.cantin@laposte.net>"
-+#define DRIVER_DESC "USB eBeam Driver"
-+
-+/* Common values for eBeam devices */
-+#define REPT_SIZE 8 /* packet size */
-+#define MIN_X 0 /* raw coordinates ranges */
-+#define MAX_X 0xFFFF
-+#define MIN_Y 0
-+#define MAX_Y 0xFFFF
-+
++#define DRIVER_VERSION "v0.5"
++#define DRIVER_AUTHOR "Yann Cantin <yann.cantin-QFKgK+z4sOrR7s880joybQ@public.gmane.org>"
++#define DRIVER_DESC "USB eBeam Driver"
+
+#define USB_VENDOR_ID_EFI 0x2650 /* Electronics For Imaging, Inc */
+#define USB_DEVICE_ID_EFI_CLASSIC 0x1311 /* Classic projection "La banane" */
+
-+#define EBEAM_BTN_TIP 0x1 /* tip */
-+#define EBEAM_BTN_LIT 0x2 /* little */
-+#define EBEAM_BTN_BIG 0x4 /* big */
++#define EBEAM_BTN_TIP 0x1 /* tip */
++#define EBEAM_BTN_LIT 0x2 /* little */
++#define EBEAM_BTN_BIG 0x4 /* big */
++
++/* until KConfig */
++#define CONFIG_INPUT_EBEAM_USB_CLASSIC
++
++/* device specifc data/functions */
++struct ebeam_device;
++struct ebeam_device_info {
++ int min_X;
++ int max_X;
++ int min_Y;
++ int max_Y;
++
++ /*
++ * TODO : Check if it's really necessary, waiting for other device info.
++ * Always service the USB devices irq not just when the input device is
++ * open. This is useful when devices have a watchdog which prevents us
++ * from periodically polling the device. Leave this unset unless your
++ * ebeam device requires it, as it does consume more of the USB
++ * bandwidth.
++ */
++ bool irq_always;
++
++ int rept_size;
++
++ /* optional, generic exist */
++ void (*process_pkt) (struct ebeam_device *ebeam,
++ unsigned char *pkt,
++ int len);
++
++ /* mandatory, model-specific */
++ int (*read_data) (struct ebeam_device *ebeam,
++ unsigned char *pkt);
++ void (*setup_input) (struct ebeam_device *ebeam,
++ struct input_dev *input_dev);
++ void (*report_input) (struct ebeam_device *ebeam);
++
++ /* optional, model-specific */
++ int (*alloc) (struct ebeam_device *ebeam);
++ int (*init) (struct ebeam_device *ebeam);
++ void (*exit) (struct ebeam_device *ebeam);
++};
+
+/* ebeam settings */
+struct ebeam_settings {
@@ -127,17 +167,17 @@
+ struct urb *irq;
+ struct usb_interface *interface;
+ struct input_dev *input;
++ struct ebeam_device_info *type;
+ char name[128];
+ char phys[64];
+ void *priv;
+
+ struct ebeam_settings cursetting; /* device's current settings */
-+ struct ebeam_settings newsetting; /* ... and new ones */
-+
-+ bool calibrated; /* false : send raw */
-+ /* true : send computed */
-+
-+ u16 X, Y; /* raw coordinates */
++ struct ebeam_settings newsetting; /* ... and new ones */
++
++ bool calibrated; /* false : send raw
++ * true : send computed */
++ u16 X, Y; /* raw coordinates */
+ int x, y; /* computed coordinates */
+ int btn_map; /* internal buttons map */
+};
@@ -145,76 +185,17 @@
+
+/* device types */
+enum {
++ DEVTYPE_IGNORE = -1,
+ DEVTYPE_CLASSIC,
+};
+
+static const struct usb_device_id ebeam_devices[] = {
++#ifdef CONFIG_INPUT_EBEAM_USB_CLASSIC
+ {USB_DEVICE(USB_VENDOR_ID_EFI, USB_DEVICE_ID_EFI_CLASSIC),
+ .driver_info = DEVTYPE_CLASSIC},
++#endif
+ {}
+};
-+
-+static void ebeam_init_settings(struct ebeam_device *ebeam)
-+{
-+ ebeam->calibrated = false;
-+
-+ /* Init (x,y) min/max to raw ones */
-+ ebeam->cursetting.min_x = ebeam->newsetting.min_x = MIN_X;
-+ ebeam->cursetting.max_x = ebeam->newsetting.max_x = MAX_X;
-+ ebeam->cursetting.min_y = ebeam->newsetting.min_y = MIN_Y;
-+ ebeam->cursetting.max_y = ebeam->newsetting.max_y = MAX_Y;
-+
-+ /* Safe values for the H matrix (Identity) */
-+ ebeam->cursetting.h1 = ebeam->newsetting.h1 = 1;
-+ ebeam->cursetting.h2 = ebeam->newsetting.h2 = 0;
-+ ebeam->cursetting.h3 = ebeam->newsetting.h3 = 0;
-+
-+ ebeam->cursetting.h4 = ebeam->newsetting.h4 = 0;
-+ ebeam->cursetting.h5 = ebeam->newsetting.h5 = 1;
-+ ebeam->cursetting.h6 = ebeam->newsetting.h6 = 0;
-+
-+ ebeam->cursetting.h7 = ebeam->newsetting.h7 = 0;
-+ ebeam->cursetting.h8 = ebeam->newsetting.h8 = 0;
-+ ebeam->cursetting.h9 = ebeam->newsetting.h9 = 1;
-+}
-+
-+static void ebeam_setup_input(struct ebeam_device *ebeam,
-+ struct input_dev *input_dev)
-+{
-+ unsigned long flags;
-+
-+ /* Take event lock while modifying parameters */
-+ spin_lock_irqsave(&input_dev->event_lock, flags);
-+
-+ /* Properties */
-+ set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-+
-+ /* Events generated */
-+ set_bit(EV_KEY, input_dev->evbit);
-+ set_bit(EV_ABS, input_dev->evbit);
-+
-+ /* Keys */
-+ set_bit(BTN_LEFT, input_dev->keybit);
-+ set_bit(BTN_MIDDLE, input_dev->keybit);
-+ set_bit(BTN_RIGHT, input_dev->keybit);
-+
-+ /* Axis */
-+ if (!ebeam->calibrated) {
-+ ebeam->cursetting.min_x = MIN_X;
-+ ebeam->cursetting.max_x = MAX_X;
-+ ebeam->cursetting.min_y = MIN_Y;
-+ ebeam->cursetting.max_y = MAX_Y;
-+ }
-+
-+ input_set_abs_params(input_dev, ABS_X,
-+ ebeam->cursetting.min_x, ebeam->cursetting.max_x,
-+ 0, 0);
-+ input_set_abs_params(input_dev, ABS_Y,
-+ ebeam->cursetting.min_y, ebeam->cursetting.max_y,
-+ 0, 0);
-+
-+ spin_unlock_irqrestore(&input_dev->event_lock, flags);
-+}
+
+/*******************************************************************************
+ * sysfs part
@@ -329,12 +310,12 @@
+ memcpy(&ebeam->cursetting, &ebeam->newsetting,
+ sizeof(struct ebeam_settings));
+ ebeam->calibrated = true;
-+ ebeam_setup_input(ebeam, ebeam->input);
++ ebeam->type->setup_input(ebeam, ebeam->input);
+ } else {
+ memcpy(&ebeam->newsetting, &ebeam->cursetting,
+ sizeof(struct ebeam_settings));
+ ebeam->calibrated = false;
-+ ebeam_setup_input(ebeam, ebeam->input);
++ ebeam->type->setup_input(ebeam, ebeam->input);
+ }
+
+ return count;
@@ -365,8 +346,13 @@
+ .attrs = ebeam_attrs,
+};
+
++/*******************************************************************************
++ * classic projection Part
++ */
++
++#ifdef CONFIG_INPUT_EBEAM_USB_CLASSIC
+/* IRQ */
-+static int ebeam_read_data(struct ebeam_device *ebeam, unsigned char *pkt)
++static int classic_read_data(struct ebeam_device *ebeam, unsigned char *pkt)
+{
+
+/*
@@ -427,7 +413,7 @@
+}
+
+/* IRQ */
-+static void ebeam_report_input(struct ebeam_device *ebeam)
++static void classic_report_input(struct ebeam_device *ebeam)
+{
+ input_report_key(ebeam->input, BTN_LEFT,
+ (ebeam->btn_map & EBEAM_BTN_TIP));
@@ -440,6 +426,93 @@
+ input_report_abs(ebeam->input, ABS_Y, ebeam->y);
+
+ input_sync(ebeam->input);
++}
++
++static void classic_setup_input(struct ebeam_device *ebeam,
++ struct input_dev *input_dev)
++{
++ unsigned long flags;
++
++ /* Take event lock while modifying parameters */
++ spin_lock_irqsave(&input_dev->event_lock, flags);
++
++ /* Properties */
++ set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
++
++ /* Events generated */
++ set_bit(EV_KEY, input_dev->evbit);
++ set_bit(EV_ABS, input_dev->evbit);
++
++ /* Keys */
++ set_bit(BTN_LEFT, input_dev->keybit);
++ set_bit(BTN_MIDDLE, input_dev->keybit);
++ set_bit(BTN_RIGHT, input_dev->keybit);
++
++ /* Axis */
++ if (!ebeam->calibrated) {
++ ebeam->cursetting.min_x = ebeam->type->min_X;
++ ebeam->cursetting.max_x = ebeam->type->max_X;
++ ebeam->cursetting.min_y = ebeam->type->min_Y;
++ ebeam->cursetting.max_y = ebeam->type->max_Y;
++ }
++
++ input_set_abs_params(input_dev, ABS_X,
++ ebeam->cursetting.min_x, ebeam->cursetting.max_x,
++ 0, 0);
++ input_set_abs_params(input_dev, ABS_Y,
++ ebeam->cursetting.min_y, ebeam->cursetting.max_y,
++ 0, 0);
++
++ spin_unlock_irqrestore(&input_dev->event_lock, flags);
++}
++
++#endif
++
++/*****************************************************************************
++ * device descriptors
++ */
++static struct ebeam_device_info ebeam_dev_info[] = {
++#ifdef CONFIG_INPUT_EBEAM_USB_CLASSIC
++ [DEVTYPE_CLASSIC] = {
++ .min_X = 0,
++ .max_X = 65535,
++ .min_Y = 0,
++ .max_Y = 65535,
++ .rept_size = 8,
++ .read_data = classic_read_data,
++ .setup_input = classic_setup_input,
++ .report_input = classic_report_input,
++ },
++#endif
++};
++
++/*******************************************************************************
++ * Generic Part
++ * Nothing model-specific below this point
++ */
++
++static void ebeam_init_settings(struct ebeam_device *ebeam)
++{
++ ebeam->calibrated = false;
++
++ /* Init (x,y) min/max to raw ones */
++ ebeam->cursetting.min_x = ebeam->newsetting.min_x = ebeam->type->min_X;
++ ebeam->cursetting.max_x = ebeam->newsetting.max_x = ebeam->type->max_X;
++ ebeam->cursetting.min_y = ebeam->newsetting.min_y = ebeam->type->min_Y;
++ ebeam->cursetting.max_y = ebeam->newsetting.max_y = ebeam->type->max_Y;
++
++ /* Safe values for the H matrix (Identity) */
++ ebeam->cursetting.h1 = ebeam->newsetting.h1 = 1;
++ ebeam->cursetting.h2 = ebeam->newsetting.h2 = 0;
++ ebeam->cursetting.h3 = ebeam->newsetting.h3 = 0;
++
++ ebeam->cursetting.h4 = ebeam->newsetting.h4 = 0;
++ ebeam->cursetting.h5 = ebeam->newsetting.h5 = 1;
++ ebeam->cursetting.h6 = ebeam->newsetting.h6 = 0;
++
++ ebeam->cursetting.h7 = ebeam->newsetting.h7 = 0;
++ ebeam->cursetting.h8 = ebeam->newsetting.h8 = 0;
++ ebeam->cursetting.h9 = ebeam->newsetting.h9 = 1;
+}
+
+/*
@@ -492,16 +565,19 @@
+}
+
+/* IRQ */
++/* generic function, may be overloaded */
+static void ebeam_process_pkt(struct ebeam_device *ebeam,
+ unsigned char *pkt, int len)
+{
-+ if (!ebeam_read_data(ebeam, pkt))
++ struct ebeam_device_info *type = ebeam->type;
++
++ if (!type->read_data(ebeam, pkt))
+ return;
+
+ if (!ebeam_calculate_xy(ebeam))
+ return;
+
-+ ebeam_report_input(ebeam);
++ type->report_input(ebeam);
+}
+
+/* IRQ
@@ -536,7 +612,7 @@
+ goto exit;
+ }
+
-+ ebeam_process_pkt(ebeam, ebeam->data, urb->actual_length);
++ ebeam->type->process_pkt(ebeam, ebeam->data, urb->actual_length);
+
+exit:
+ usb_mark_last_busy(interface_to_usbdev(ebeam->interface));
@@ -557,9 +633,11 @@
+ if (r < 0)
+ goto out;
+
-+ if (usb_submit_urb(ebeam->irq, GFP_KERNEL)) {
-+ r = -EIO;
-+ goto out_put;
++ if (!ebeam->type->irq_always) {
++ if (usb_submit_urb(ebeam->irq, GFP_KERNEL)) {
++ r = -EIO;
++ goto out_put;
++ }
+ }
+
+ ebeam->interface->needs_remote_wakeup = 1;
@@ -574,7 +652,8 @@
+ struct ebeam_device *ebeam = input_get_drvdata(input);
+ int r;
+
-+ usb_kill_urb(ebeam->irq);
++ if (!ebeam->type->irq_always)
++ usb_kill_urb(ebeam->irq);
+
+ r = usb_autopm_get_interface(ebeam->interface);
+ ebeam->interface->needs_remote_wakeup = 0;
@@ -599,7 +678,7 @@
+ int result = 0;
+
+ mutex_lock(&input->mutex);
-+ if (input->users)
++ if (input->users || ebeam->type->irq_always)
+ result = usb_submit_urb(ebeam->irq, GFP_NOIO);
+ mutex_unlock(&input->mutex);
+
@@ -611,6 +690,17 @@
+ struct ebeam_device *ebeam = usb_get_intfdata(intf);
+ struct input_dev *input = ebeam->input;
+ int err = 0;
++
++ /* reinit the device */
++ if (ebeam->type->init) {
++ err = ebeam->type->init(ebeam);
++ if (err) {
++ dev_dbg(&intf->dev,
++ "%s - type->init() failed, err: %d\n",
++ __func__, err);
++ return err;
++ }
++ }
+
+ /* restart IO if needed */
+ mutex_lock(&input->mutex);
@@ -624,7 +714,7 @@
+static void ebeam_free_buffers(struct usb_device *udev,
+ struct ebeam_device *ebeam)
+{
-+ usb_free_coherent(udev, REPT_SIZE,
++ usb_free_coherent(udev, ebeam->type->rept_size,
+ ebeam->data, ebeam->data_dma);
+ kfree(ebeam->buffer);
+}
@@ -648,7 +738,12 @@
+ struct input_dev *input_dev;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = interface_to_usbdev(intf);
++ struct ebeam_device_info *type;
+ int err = -ENOMEM;
++
++ /* some devices are ignored */
++ if (id->driver_info == DEVTYPE_IGNORE)
++ return -ENODEV;
+
+ endpoint = ebeam_get_input_endpoint(intf->cur_altsetting);
+ if (!endpoint)
@@ -659,9 +754,14 @@
+ if (!ebeam || !input_dev)
+ goto out_free;
+
++ type = &ebeam_dev_info[id->driver_info];
++ ebeam->type = type;
+ ebeam_init_settings(ebeam);
+
-+ ebeam->data = usb_alloc_coherent(udev, REPT_SIZE,
++ if (!type->process_pkt)
++ type->process_pkt = ebeam_process_pkt;
++
++ ebeam->data = usb_alloc_coherent(udev, type->rept_size,
+ GFP_KERNEL, &ebeam->data_dma);
+ if (!ebeam->data)
+ goto out_free;
@@ -724,17 +824,39 @@
+ if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(ebeam->irq, udev,
+ usb_rcvintpipe(udev, endpoint->bEndpointAddress),
-+ ebeam->data, REPT_SIZE,
++ ebeam->data, type->rept_size,
+ ebeam_irq, ebeam, endpoint->bInterval);
+ else
+ usb_fill_bulk_urb(ebeam->irq, udev,
+ usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
-+ ebeam->data, REPT_SIZE,
++ ebeam->data, type->rept_size,
+ ebeam_irq, ebeam);
+
+ ebeam->irq->dev = udev;
+ ebeam->irq->transfer_dma = ebeam->data_dma;
+ ebeam->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++
++ /* device specific allocations */
++ if (type->alloc) {
++ err = type->alloc(ebeam);
++ if (err) {
++ dev_dbg(&intf->dev,
++ "%s - type->alloc() failed, err: %d\n",
++ __func__, err);
++ goto out_free_urb;
++ }
++ }
++
++ /* device specific initialisation */
++ if (type->init) {
++ err = type->init(ebeam);
++ if (err) {
++ dev_dbg(&intf->dev,
++ "%s - type->init() failed, err: %d\n",
++ __func__, err);
++ goto out_do_exit;
++ }
++ }
+
+ /* input final setup */
+ err = input_register_device(ebeam->input);
@@ -742,13 +864,26 @@
+ dev_dbg(&intf->dev,
+ "%s - input_register_device failed, err: %d\n",
+ __func__, err);
-+ goto out_free_urb;
-+ }
-+
-+ ebeam_setup_input(ebeam, input_dev);
++ goto out_do_exit;
++ }
++
++ type->setup_input(ebeam, input_dev);
+
+ /* usb final setup */
+ usb_set_intfdata(intf, ebeam);
++
++ if (ebeam->type->irq_always) {
++ /* this can't fail */
++ usb_autopm_get_interface(intf);
++ err = usb_submit_urb(ebeam->irq, GFP_KERNEL);
++ if (err) {
++ usb_autopm_put_interface(intf);
++ dev_err(&intf->dev,
++ "%s - usb_submit_urb failed with result: %d\n",
++ __func__, err);
++ goto out_unregister_input;
++ }
++ }
+
+ /* sysfs setup */
+ err = sysfs_create_group(&intf->dev.kobj, &ebeam_attr_group);
@@ -764,6 +899,9 @@
+out_unregister_input:
+ input_unregister_device(input_dev);
+ input_dev = NULL;
++out_do_exit:
++ if (type->exit)
++ type->exit(ebeam);
+out_free_urb:
+ usb_free_urb(ebeam->irq);
+out_free_buffers:
@@ -789,6 +927,8 @@
+ input_unregister_device(ebeam->input);
+ sysfs_remove_group(&intf->dev.kobj, &ebeam_attr_group);
+ usb_free_urb(ebeam->irq);
++ if (ebeam->type->exit)
++ ebeam->type->exit(ebeam);
+ ebeam_free_buffers(interface_to_usbdev(intf), ebeam);
+ kfree(ebeam);
+}
@@ -814,3 +954,8 @@
+
--
1.7.10
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-usb" in
+the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html