Re: [RFC 2/2] Input: phantom, add a new driver

2007-04-20 Thread Andrew Morton
On Tue, 17 Apr 2007 22:02:10 +0200 (CEST) Jiri Slaby [EMAIL PROTECTED] wrote:

 phantom, add a new driver
 
 Sensable Phantom is a up to 7DOF force feedback (up to 6DOF FF) device. It's
 atypical, so it's based on the new added FF_RAW effect.
 
 diff --git a/drivers/input/misc/phantom.c b/drivers/input/misc/phantom.c
 new file mode 100644
 index 000..58f55cd
 --- /dev/null
 +++ b/drivers/input/misc/phantom.c
 @@ -0,0 +1,387 @@
 +/*
 + *  Copyright (C) 2005-2007 Jiri Slaby [EMAIL PROTECTED]
 + *
 + *  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
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  You need an userspace library to cooperate with this driver. It (and 
 other
 + *  info) may be obtained here:
 + *  http://www.fi.muni.cz/~xslaby/phantom.html
 + */
 +
 +#include linux/kernel.h
 +#include linux/module.h
 +#include linux/device.h
 +#include linux/pci.h
 +#include linux/fs.h
 +#include linux/poll.h
 +#include linux/interrupt.h
 +#include linux/input.h
 +
 +#include asm/io.h
 +
 +#define PHANTOM_VERSION  n0.9.4

That's an impressive version number ;)

 +#define PHM_MAX_TORQUES  3
 +
 +#define PHN_CONTROL  0x6
 +#define PHN_CTL_AMP  0x1
 +#define PHN_CTL_BUT  0x2
 +#define PHN_CTL_IRQ  0x10
 +
 +#define PHN_IRQCTL   0x4c
 +
 +#define PHN_ZERO_FORCE   2048

wonders what all those do

 +#define PCI_ENCODER(dev, axis) ((0 - (int)ioread32((dev)-iaddr + (axis)))  
 \
 + 0x)

Is there any reason why this cannot be a lower-cased inline C function? 
Nicer to read, typesafe, etc.

 +#define PHB_RUNNING  1
 +#define PHB_RESET2
 +
 +static struct PH_CLASSTYPE *phantom_class;

I guess that PH_CLASSTYPE is some protect-me-from-gregkh compatibility
thing.  But there isn't such a macro in the tree.  I switched this to plain
old `class'.

 +struct phantom_device {
 + void __iomem *caddr;
 + u32 __iomem *iaddr;
 + u32 __iomem *oaddr;
 + u32 amp_bit;
 + s16 torques[PHM_MAX_TORQUES];
 + unsigned long status;
 +
 + struct input_dev *idev;
 +};
 +
 +static int phantom_status(struct phantom_device *dev, unsigned long newstat)
 +{
 + pr_debug(phantom_status %lx %lx\n, dev-status, newstat);
 +
 + if (!(dev-status  PHB_RUNNING)  (newstat  PHB_RUNNING)) {
 + iowrite32(PHN_CTL_IRQ | PHN_CTL_AMP, dev-iaddr + PHN_CONTROL);
 + dev-amp_bit = PHN_CTL_IRQ;
 + iowrite32(0x43, dev-caddr + PHN_IRQCTL);
 + } else if ((dev-status  PHB_RUNNING)  !(newstat  PHB_RUNNING))
 + iowrite32(0, dev-caddr + PHN_IRQCTL);
 +
 + dev-status = newstat;
 +
 + return 0;
 +}
 +
 +static void phantom_close(struct input_dev *idev)
 +{
 + struct phantom_device *dev = idev-private;
 +
 + phantom_status(dev, dev-status  ~PHB_RUNNING);
 +}
 +
 +static void phantom_reset(struct phantom_device *dev)
 +{
 + pr_debug(resetting\n);
 +
 + iowrite32(~0x1f, dev-iaddr);
 + wmb();
 + iowrite32(0x1f, dev-iaddr);
 + dev-status |= PHB_RESET;
 +}

Does the wmb here actually do anything useful?  If so, a comment is needed
because it isn't possible to work out why that statement is there by
reading the code.

 ...

 +
 +static irqreturn_t phantom_isr(int irq, void *data)
 +{
 + struct phantom_device *dev = data;
 + struct input_dev *idev = dev-idev;
 + unsigned int a, hw_status;
 +
 + hw_status = ioread32(dev-iaddr + PHN_CONTROL);
 + if (!(hw_status  PHN_CTL_IRQ))
 + return IRQ_NONE;
 +
 + iowrite32(0, dev-iaddr);
 + wmb();
 + iowrite32(0xc0, dev-iaddr);

there too.

 + if (unlikely(idev == NULL))
 + return IRQ_HANDLED;

Can this happen?  If so, a comment explaining why would be nice.

 + input_report_abs(idev, ABS_X, PCI_ENCODER(dev, 0));
 + input_report_abs(idev, ABS_Y, PCI_ENCODER(dev, 1));
 + input_report_abs(idev, ABS_Z, PCI_ENCODER(dev, 2));
 + input_report_abs(idev, ABS_RX, PCI_ENCODER(dev, 3));
 + input_report_abs(idev, ABS_RY, PCI_ENCODER(dev, 4));
 + input_report_abs(idev, ABS_RZ, PCI_ENCODER(dev, 5));
 + input_report_key(idev, BTN_0, !!(hw_status  PHN_CTL_BUT));
 + input_sync(idev);
 + input_event(idev, EV_SYN, SYN_CONFIG, 0);
 +
 + for (a = 0; a  PHM_MAX_TORQUES; a++)
 + iowrite32(dev-torques[a] + PHN_ZERO_FORCE, dev-oaddr + a);
 + iowrite32(dev-amp_bit, dev-iaddr + PHN_CONTROL);
 + dev-amp_bit ^= PHN_CTL_AMP;
 +
 + return IRQ_HANDLED;
 +}
 +
 +/**

A plain old

/*
 * Init and deinit driver
 */

is sufficient and typical.

But this is not actually the most useful of comments anyway ;)

 + * Init and deinit 

Re: [RFC 2/2] Input: phantom, add a new driver

2007-04-20 Thread Jiri Slaby
Andrew Morton napsal(a):
 On Tue, 17 Apr 2007 22:02:10 +0200 (CEST) Jiri Slaby [EMAIL PROTECTED] 
 wrote:
 
 phantom, add a new driver
[...]
 +#define PHANTOM_VERSION n0.9.4
 
 That's an impressive version number ;)

fork of 0.8 or so 2.4 linux driver - the n in the meaning of new :)

 +#define PHM_MAX_TORQUES 3
 +
 +#define PHN_CONTROL 0x6
 +#define PHN_CTL_AMP 0x1
 +#define PHN_CTL_BUT 0x2
 +#define PHN_CTL_IRQ 0x10
 +
 +#define PHN_IRQCTL  0x4c
 +
 +#define PHN_ZERO_FORCE  2048
 
 wonders what all those do

I have no clue too, cutpaste from sensable 2.4 driver. But I'll document as
much as possible.

 +#define PCI_ENCODER(dev, axis) ((0 - (int)ioread32((dev)-iaddr + (axis))) 
  \
 +0x)
 
 Is there any reason why this cannot be a lower-cased inline C function? 
 Nicer to read, typesafe, etc.

yes, I'll switch it.

 +#define PHB_RUNNING 1
 +#define PHB_RESET   2
 +
 +static struct PH_CLASSTYPE *phantom_class;
 
 I guess that PH_CLASSTYPE is some protect-me-from-gregkh compatibility
 thing.  But there isn't such a macro in the tree.  I switched this to plain
 old `class'.

Yes, my bad.

 +
 +static irqreturn_t phantom_isr(int irq, void *data)
 +{
 +struct phantom_device *dev = data;
 +struct input_dev *idev = dev-idev;
 +unsigned int a, hw_status;
 +
 +hw_status = ioread32(dev-iaddr + PHN_CONTROL);
 +if (!(hw_status  PHN_CTL_IRQ))
 +return IRQ_NONE;
 +
 +iowrite32(0, dev-iaddr);
 +wmb();
 +iowrite32(0xc0, dev-iaddr);
 
 there too.

Seems reasonable, it can't be reordered. (I hope this holds on all archs.)

 +if (unlikely(idev == NULL))
 +return IRQ_HANDLED;
 
 Can this happen?  If so, a comment explaining why would be nice.

In the case of DEBUG_SHIRQ=y. Comment will be added or better -- devinit code
reordered.

thanks for notes,
-- 
http://www.fi.muni.cz/~xslaby/Jiri Slaby
faculty of informatics, masaryk university, brno, cz
e-mail: jirislaby gmail com, gpg pubkey fingerprint:
B674 9967 0407 CE62 ACC8  22A0 32CC 55C3 39D4 7A7E


[RFC 2/2] Input: phantom, add a new driver

2007-04-17 Thread Jiri Slaby
phantom, add a new driver

Sensable Phantom is a up to 7DOF force feedback (up to 6DOF FF) device. It's
atypical, so it's based on the new added FF_RAW effect.

Signed-off-by: Jiri Slaby [EMAIL PROTECTED]

---
commit 73621a789a0482299242ea61c971af6b5f8b828a
tree 365ba8113af9aaf468415d67238378767efad092
parent 759e7f172031959f49e5d3a7282379e7d73621b3
author Jiri Slaby [EMAIL PROTECTED] Tue, 17 Apr 2007 21:58:27 +0200
committer Jiri Slaby [EMAIL PROTECTED] Tue, 17 Apr 2007 21:58:27 +0200

 MAINTAINERS  |5 +
 drivers/input/misc/Kconfig   |9 +
 drivers/input/misc/Makefile  |1 
 drivers/input/misc/phantom.c |  387 ++
 4 files changed, 402 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8a68712..86a8417 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3112,6 +3112,11 @@ L:   [EMAIL PROTECTED] (subscribers-only, general 
discussion)
 W: http://www.nsa.gov/selinux
 S: Supported
 
+SENSABLE PHANTOM
+P: Jiri Slaby
+M: [EMAIL PROTECTED]
+S: Maintained
+
 SERIAL ATA (SATA) SUBSYSTEM:
 P: Jeff Garzik
 M: [EMAIL PROTECTED]
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 5694115..6e432b0 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -98,4 +98,13 @@ config HP_SDC_RTC
  Say Y here if you want to support the built-in real time clock
  of the HP SDC controller.
 
+config PHANTOM
+   tristate Sensable PHANToM
+   depends on PCI  INPUT_FF_MEMLESS
+   help
+ Say Y here if you want to build a driver for Sensable PHANToM device.
+
+ If you choose to build module, its name will be phantom. If unsure,
+ say N here.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 9f08f27..3ab3cc2 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS)  += wistron_btns.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
 obj-$(CONFIG_HP_SDC_RTC)   += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)  += ixp4xx-beeper.o
+obj-$(CONFIG_PHANTOM)  += phantom.o
diff --git a/drivers/input/misc/phantom.c b/drivers/input/misc/phantom.c
new file mode 100644
index 000..58f55cd
--- /dev/null
+++ b/drivers/input/misc/phantom.c
@@ -0,0 +1,387 @@
+/*
+ *  Copyright (C) 2005-2007 Jiri Slaby [EMAIL PROTECTED]
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  You need an userspace library to cooperate with this driver. It (and other
+ *  info) may be obtained here:
+ *  http://www.fi.muni.cz/~xslaby/phantom.html
+ */
+
+#include linux/kernel.h
+#include linux/module.h
+#include linux/device.h
+#include linux/pci.h
+#include linux/fs.h
+#include linux/poll.h
+#include linux/interrupt.h
+#include linux/input.h
+
+#include asm/io.h
+
+#define PHANTOM_VERSIONn0.9.4
+
+#define PHM_MAX_TORQUES3
+
+#define PHN_CONTROL0x6
+#define PHN_CTL_AMP0x1
+#define PHN_CTL_BUT0x2
+#define PHN_CTL_IRQ0x10
+
+#define PHN_IRQCTL 0x4c
+
+#define PHN_ZERO_FORCE 2048
+
+#define PCI_ENCODER(dev, axis) ((0 - (int)ioread32((dev)-iaddr + (axis)))  \
+   0x)
+
+#define PHB_RUNNING1
+#define PHB_RESET  2
+
+static struct PH_CLASSTYPE *phantom_class;
+
+struct phantom_device {
+   void __iomem *caddr;
+   u32 __iomem *iaddr;
+   u32 __iomem *oaddr;
+   u32 amp_bit;
+   s16 torques[PHM_MAX_TORQUES];
+   unsigned long status;
+
+   struct input_dev *idev;
+};
+
+static int phantom_status(struct phantom_device *dev, unsigned long newstat)
+{
+   pr_debug(phantom_status %lx %lx\n, dev-status, newstat);
+
+   if (!(dev-status  PHB_RUNNING)  (newstat  PHB_RUNNING)) {
+   iowrite32(PHN_CTL_IRQ | PHN_CTL_AMP, dev-iaddr + PHN_CONTROL);
+   dev-amp_bit = PHN_CTL_IRQ;
+   iowrite32(0x43, dev-caddr + PHN_IRQCTL);
+   } else if ((dev-status  PHB_RUNNING)  !(newstat  PHB_RUNNING))
+   iowrite32(0, dev-caddr + PHN_IRQCTL);
+
+   dev-status = newstat;
+
+   return 0;
+}
+
+static void phantom_close(struct input_dev *idev)
+{
+   struct phantom_device *dev = idev-private;
+
+   phantom_status(dev, dev-status  ~PHB_RUNNING);
+}
+
+static void phantom_reset(struct phantom_device *dev)
+{
+   pr_debug(resetting\n);
+
+   iowrite32(~0x1f, dev-iaddr);
+   wmb();
+   iowrite32(0x1f, dev-iaddr);
+   dev-status |= PHB_RESET;
+}
+
+static void phantom_autocenter(struct input_dev *idev, u16 magnitude)
+{
+