Misc: add sensable phantom driver
Subsystems (3)
PATCH 1/1 Misc: add sensable phantom driver
Hi,
I'm attaching the phantom driver -v2. Please drop
input-ff-add-ff_raw-effect.patch
input-phantom-add-a-new-driver.patch
before applying this patch. Thanks.
--
add sensable phantom driver
---
commit d8cb58f904b80e250383e68832204fafaf02da8b
tree f3d95c2a3b0283d651799a2db797d133263b5a95
parent 3947dc9399ee9a24d293bf2d7ab92e434e2756fb
author Jiri Slaby <[email protected]> Wed, 02 May 2007 17:52:50 +0200 committer Jiri Slaby <[email protected]> Wed, 02 May 2007 17:52:50 +0200
Documentation/ioctl-number.txt | 3 MAINTAINERS | 5 drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 drivers/misc/phantom.c | 459 ++++++++++++++++++++++++++++++++++++++++ include/linux/phantom.h | 42 ++++ 6 files changed, 518 insertions(+), 1 deletions(-)
Documentation/ioctl-number.txt +2 -1
@@ -138,7 +138,8 @@ Code Seq# Include File Comments 'm' 00-1F net/irda/irmod.h conflict! 'n' 00-7F linux/ncp_fs.h 'n' E0-FF video/matrox.h matroxfb -'p' 00-3F linux/mc146818rtc.h +'p' 00-0F linux/phantom.h conflict! (OpenHaptics needs this) +'p' 00-3F linux/mc146818rtc.h conflict! 'p' 40-7F linux/nvram.h 'p' 80-9F user-space parport <mailto:[email protected]>
MAINTAINERS +5 -0
@@ -3092,6 +3092,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]
drivers/misc/Kconfig +9 -0
@@ -186,5 +186,14 @@ config BLINK output something to the screen like kexec kernels to give the user a visual indication that the kernel is doing something. +config PHANTOM + tristate "Sensable PHANToM" + depends on PCI + 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. + endmenu
drivers/misc/Makefile +1 -0
@@ -14,3 +14,4 @@ obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o +obj-$(CONFIG_PHANTOM) += phantom.o
drivers/misc/phantom.c new file +459 -0
459 lines not on this page · raw message
include/linux/phantom.h new file +42 -0
42 lines not on this page · raw message
Quoted 1 line · On Wed, 2 May 2007 17:56:01 +0200 (CEST) Jiri Slaby <[email protected]>…
add sensable phantom driver
<googles>
Is that one of these?
http://www.est-kl.com/aufbau_general/index_hard_haptic.html?http://www.est-kl.com/hardware/haptic/sensable/phantom_omni.html
I don't think we've ever had a driver for a device like that before. I wonder how you designed the userspace interface to it.
drivers/misc/phantom.c line 73
Quoted 2 lines
drivers/misc/phantom.c new file +2
-0+static int phantom_ioctl (struct inode *inode,struct file *file,u_int cmd, +u_long arg)
Could we please use standard-looking types in this driver? u32 and u64 and things?
However in this case, as it's an ioctl handler it should be "int" and "unsigned long".
Does this driver require compat handling? (Seems not?)
Quoted 13 lines
static int
phantom_open(struct inode *inode, struct file *file){ struct phantom_device *dev = container_of(inode->i_cdev, struct phantom_device, cdev); if (mutex_lock_interruptible(&dev->open_lock)) return -ERESTARTSYS; if (dev->opened) { mutex_unlock(&dev->open_lock); return -EINVAL; }
Quoted 7 lines
file->private_data = dev; dev->opened++; mutex_unlock(&dev->open_lock); return 0; }
You should call nonseekable_open() in here.
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+static int phantom_release (struct inode *inode,struct file *file) +{ +struct phantom_device *dev = file->private_data; +
drivers/misc/phantom.c line 177
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+if (mutex_lock_interruptible (&dev->open_lock)) +return -ERESTARTSYS ; + + dev->opened =0 ; +phantom_status (dev, dev->status & ~PHB_RUNNING ); + +mutex_unlock (&dev->open_lock); + +return 0 ; +}
The mutex_lock_interruptible() is wrong, I think. This function is called when we do the final close(). If the signal _is_ taken then it's game
over: the device can no longer be opened.
Quoted 29 lines
drivers/misc/phantom.c new file +29
-0+static unsigned int phantom_poll (struct file *file,poll_table *wait) +{ +struct phantom_device *dev = file->private_data; +unsigned int mask =0 ; + +pr_debug ("phantom_poll: %u\n" , dev->counter); +poll_wait (file, &dev->wait, wait); +if (dev->counter) { + mask =POLLIN |POLLRDNORM ; + dev->counter--; + }else if ((dev->status &PHB_RUNNING ) ==0 ) + mask =POLLIN |POLLRDNORM |POLLERR ; +pr_debug ("phantom_poll end: %x/%u\n" , mask, dev->counter); + +return mask; +} + +static struct file_operations phantom_file_ops = { + .open = phantom_open, + .release = phantom_release, + .ioctl = phantom_ioctl, + .poll = phantom_poll, +}; + +static irqreturn_t phantom_isr (int irq,void *data) +{ +struct phantom_device *dev = data; + +if (!(ioread32 (dev->iaddr +PHN_CONTROL ) &PHN_CTL_IRQ ))
drivers/misc/phantom.c line 217
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+return IRQ_NONE ; + +iowrite32 (0 , dev->iaddr); +iowrite32 (0xc0 , dev->iaddr); + + dev->counter++; +wake_up_interruptible (&dev->wait); + +return IRQ_HANDLED ; +}
The access to dev->counter is racy even on non-preempt uniprocessor. An atomic_t would suit.
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+/* +* Init and deinit driver +*/ +
drivers/misc/phantom.c line 232
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+static unsigned int __devinit phantom_get_free (void ) +{ +unsigned int i; + +for (i =0 ; i <PHANTOM_MAX_MINORS ; i++) +if (phantom_devices[i] ==0 ) +break ; + +return i; +}
This function assumes that the phantom_devices[] array will never have any holes in it. But if phantom_remove() is called out-of-order, it _will_ have holes. Perhaps - I didn't look too hard.
Quoted 127 lines
drivers/misc/phantom.c new file +127
-0+static int __devinit phantom_probe (struct pci_dev *pdev, +const struct pci_device_id *pci_id) +{ +struct phantom_device *pht; +unsigned int minor; +int retval; + + retval =pci_enable_device (pdev); +if (retval) + goto err; + + minor =phantom_get_free (); +if (minor ==PHANTOM_MAX_MINORS ) { +dev_err (&pdev->dev,"too many devices found!\n" ); + retval = -EIO ; + goto err_dis; + } + + phantom_devices[minor] =1 ; + + retval =pci_request_regions (pdev,"phantom" ); +if (retval) + goto err_null; + + retval = -ENOMEM ; + pht =kzalloc (sizeof (*pht),GFP_KERNEL ); +if (pht ==NULL ) { +dev_err (&pdev->dev,"unable to allocate device\n" ); + goto err_reg; + } + + pht->caddr =pci_iomap (pdev,0 ,0 ); +if (pht->caddr ==NULL ) { +dev_err (&pdev->dev,"can't remap conf space\n" ); + goto err_fr; + } + pht->iaddr =pci_iomap (pdev,2 ,0 ); +if (pht->iaddr ==NULL ) { +dev_err (&pdev->dev,"can't remap input space\n" ); + goto err_unmc; + } + pht->oaddr =pci_iomap (pdev,3 ,0 ); +if (pht->oaddr ==NULL ) { +dev_err (&pdev->dev,"can't remap output space\n" ); + goto err_unmi; + } + +mutex_init (&pht->open_lock); +init_waitqueue_head (&pht->wait); +cdev_init (&pht->cdev, &phantom_file_ops); + pht->cdev.owner =THIS_MODULE ; + +iowrite32 (0 , pht->caddr +PHN_IRQCTL ); + retval =request_irq (pdev->irq, phantom_isr, +IRQF_SHARED |IRQF_DISABLED ,"phantom" , pht); +if (retval) { +dev_err (&pdev->dev,"can't establish ISR\n" ); + goto err_unmo; + } + + retval =cdev_add (&pht->cdev,MKDEV (phantom_major, minor),1 ); +if (retval) { +dev_err (&pdev->dev,"chardev registration failed\n" ); + goto err_irq; + } + +if (IS_ERR (device_create (phantom_class, &pdev->dev,MKDEV (phantom_major, + minor),"phantom%u" , minor))) +dev_err (&pdev->dev,"can't create device\n" ); + +pci_set_drvdata (pdev, pht); + +return 0 ; +err_irq: +free_irq (pdev->irq, pht); +err_unmo: +pci_iounmap (pdev, pht->oaddr); +err_unmi: +pci_iounmap (pdev, pht->iaddr); +err_unmc: +pci_iounmap (pdev, pht->caddr); +err_fr: +kfree (pht); +err_reg: +pci_release_regions (pdev); +err_null: + phantom_devices[minor] =0 ; +err_dis: +pci_disable_device (pdev); +err: +return retval; +} + +static void __devexit phantom_remove(struct pci_dev *pdev) +{ +struct phantom_device *pht =pci_get_drvdata (pdev); +unsigned int minor =MINOR (pht->cdev.dev); + +device_destroy (phantom_class,MKDEV (phantom_major, minor)); + +cdev_del (&pht->cdev); + +iowrite32 (0 , pht->caddr +PHN_IRQCTL ); +free_irq (pdev->irq, pht); + +pci_iounmap (pdev, pht->oaddr); +pci_iounmap (pdev, pht->iaddr); +pci_iounmap (pdev, pht->caddr); + +kfree (pht); + +pci_release_regions (pdev); + + phantom_devices[minor] =0 ; + +pci_disable_device (pdev); +} + +#ifdef CONFIG_PM +static int phantom_suspend (struct pci_dev *pdev,pm_message_t state) +{ +struct phantom_device *dev =pci_get_drvdata (pdev); + +iowrite32 (0 , dev->caddr +PHN_IRQCTL ); + +return 0 ; +}
drivers/misc/phantom.c line 370
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+ +static int phantom_resume (struct pci_dev *pdev) +{ +struct phantom_device *dev =pci_get_drvdata (pdev); + +iowrite32 (0 , dev->caddr +PHN_IRQCTL ); + +return 0 ; +} +#endif
It's conventional to do
#else
#define phantom_suspend NULL
#define phantom_resume NULL
#endif
Quoted 7 lines
drivers/misc/phantom.c new file +7
-0+static struct pci_device_id phantom_pci_tbl[]__devinitdata = { + {PCI_DEVICE (PCI_VENDOR_ID_PLX ,PCI_DEVICE_ID_PLX_9050 ), + .class =PCI_CLASS_BRIDGE_OTHER <<8 , .class_mask =0xffff00 }, + {0 , } +}; +MODULE_DEVICE_TABLE (pci, phantom_pci_tbl); +
drivers/misc/phantom.c line 388
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+static struct pci_driver phantom_pci_driver = { + .name ="phantom" , + .id_table = phantom_pci_tbl, + .probe = phantom_probe, + .remove =__devexit_p (phantom_remove), +#ifdef CONFIG_PM + .suspend = phantom_suspend, + .resume = phantom_resume +#endif +};
thus making these ifdefs unnecessary.
Quoted 20 lines
index 0000000..d3ebbfa
include/linux/phantom.h new file +16
-0@@ -0,0 +1,42 @@ +/* +* 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. +*/ + +#ifndef __PHANTOM_H +#define __PHANTOM_H + +#include <asm/types.h> + +/* PHN_(G/S)ET_REG param */ +struct phm_reg {
include/linux/phantom.h line 26
Quoted 10 lines
include/linux/phantom.h new file +10
-0+__u32 reg; +__u32 value; +}; + +/* PHN_(G/S)ET_REGS param */ +struct phm_regs { +__u32 count; +__u32 mask; +__u32 values[8 ]; +};
No, I guess it doesn't need compat handling.
Quoted 5 lines
include/linux/phantom.h new file +5
-0+#define PH_IOC_MAGIC 'p' +#define PHN_GET_REG _IOWR(PH_IOC_MAGIC, 0, struct phm_reg *) +#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *) +#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *) +#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
include/linux/phantom.h line 42
Quoted 10 lines
include/linux/phantom.h new file +10
-0+#define PH_IOC_MAXNR 3 + +#define PHN_CONTROL 0x6/* control byte in iaddr space */ +#define PHN_CTL_AMP 0x1/* switch after torques change */ +#define PHN_CTL_BUT 0x2/* is button switched */ +#define PHN_CTL_IRQ 0x10/* is irq enabled */ + +#define PHN_ZERO_FORCE 2048/* zero torque on motor */ + +#endif
Exported to userspace? If so, it'll need a mention in include/linux/Kbuild?
Andrew Morton napsal(a):
Quoted 8 lines · On Wed, 2 May 2007 17:56:01 +0200 (CEST) Jiri Slaby <[email protected]>…
Quoted 2 lines
add sensable phantom driver
<googles>
Is that one of these?
http://www.est-kl.com/aufbau_general/index_hard_haptic.html?http://www.est-kl.com/hardware/haptic/sensable/phantom_omni.html
Omni is a small ieee1394 device. This is much bigger phantom premium pci version:
http://www.sensable.com/haptic-phantom-premium-6dof.htm
Quoted 2 lines
I don't think we've ever had a driver for a device like that before. I wonder how you designed the userspace interface to it.
I used the userspace libs that worked on 2.4 linux and rewrote them a little bit. However this is the old way, obsoleted I think, but it's still used in our human-computer interaction lab.
The other one is through supported OpenHaptics suite, which was added in this version -- that is the original Sensable (the device manufacturer) product, but they provide 2.4 linux drivers only with it.
Quoted 5 lines
drivers/misc/phantom.c line 73
Quoted 2 lines
drivers/misc/phantom.c new file +2
-0+static int phantom_ioctl (struct inode *inode,struct file *file,u_int cmd, +u_long arg)Could we please use standard-looking types in this driver? u32 and u64 and things?
Huh, wonders how this got there, thanks!
Quoted 16 lines
However in this case, as it's an ioctl handler it should be "int" and "unsigned long".
Does this driver require compat handling? (Seems not?)
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+static int phantom_release (struct inode *inode,struct file *file) +{ +struct phantom_device *dev = file->private_data; + +if (mutex_lock_interruptible (&dev->open_lock)) +return -ERESTARTSYS ; + + dev->opened =0 ; +phantom_status (dev, dev->status & ~PHB_RUNNING ); +
Quoted 8 lines
drivers/misc/phantom.c line 162
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+mutex_unlock (&dev->open_lock); + +return 0 ; +}The
mutex_lock_interruptible()is wrong, I think. This function is called when we do the finalclose(). If the signal _is_ taken then it's game
over: the device can no longer be opened.
Yes, starving at sys_close, I think so.
<fast searching in drivers/*>
Wouldn't this be a problem here too:drivers/media/dvb/cinergyT2/cinergyT2.c drivers/usb/misc/auerswald.c
at least that the device won't be stopped or something like that?
Quoted 10 lines
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+/* +* Init and deinit driver +*/ + +static unsigned int __devinit phantom_get_free (void ) +{ +unsigned int i; + +for (i =0 ; i <PHANTOM_MAX_MINORS ; i++) +if (phantom_devices[i] ==0 )
Quoted 8 lines
drivers/misc/phantom.c line 232
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+break ; + +return i; +}This function assumes that the phantom_devices[] array will never have any holes in it. But if
phantom_remove()is called out-of-order, it _will_ have holes. Perhaps - I didn't look too hard.
I'm afraid I didn't get this. It goes through all phantom_devices and returns first free index. If a hole is present it will return "i" which corresponds to the hole, because phantom_devices[i] is 0. Note that it is unsigned char array.
thanks for the clues,
Signature · 4 lines
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
Quoted 19 lines · On Thu, 03 May 2007 14:40:01 +0200 Jiri Slaby <[email protected]> wrote:
Quoted 10 lines
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+static int phantom_release (struct inode *inode,struct file *file) +{ +struct phantom_device *dev = file->private_data; + +if (mutex_lock_interruptible (&dev->open_lock)) +return -ERESTARTSYS ; + + dev->opened =0 ; +phantom_status (dev, dev->status & ~PHB_RUNNING ); +Quoted 8 lines
drivers/misc/phantom.c line 162
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+mutex_unlock (&dev->open_lock); + +return 0 ; +}The
mutex_lock_interruptible()is wrong, I think. This function is called when we do the finalclose(). If the signal _is_ taken then it's game
over: the device can no longer be opened.
Quoted 8 lines
Yes, starving at
sys_close, I think so.<fast searching in
drivers/*>Wouldn't this be a problem here too:
drivers/media/dvb/cinergyT2/cinergyT2.cdrivers/usb/misc/auerswald.c
at least that the device won't be stopped or something like that?
Yes, those drivers appear to have the same problem. I'll fix 'em.
Quoted 19 lines
Quoted 10 lines
Quoted 10 lines
drivers/misc/phantom.c new file +10
-0+/* +* Init and deinit driver +*/ + +static unsigned int __devinit phantom_get_free (void ) +{ +unsigned int i; + +for (i =0 ; i <PHANTOM_MAX_MINORS ; i++) +if (phantom_devices[i] ==0 )Quoted 8 lines
drivers/misc/phantom.c line 232
Quoted 4 lines
drivers/misc/phantom.c new file +4
-0+break ; + +return i; +}This function assumes that the phantom_devices[] array will never have any holes in it. But if
phantom_remove()is called out-of-order, it _will_ have holes. Perhaps - I didn't look too hard.
Quoted 5 lines
I'm afraid I didn't get this. It goes through all
phantom_devicesand returns first free index. If a hole is present it will return "i" which corresponds to the hole, because phantom_devices[i] is 0. Note that it is unsigned char array.
I guess I must have misread the code.
Andrew Morton napsal(a):
Quoted 8 lines
drivers/misc/phantom.c line 73
Quoted 2 lines
drivers/misc/phantom.c new file +2
-0+static int phantom_ioctl (struct inode *inode,struct file *file,u_int cmd, +u_long arg)Could we please use standard-looking types in this driver? u32 and u64 and things?
However in this case, as it's an ioctl handler it should be "int" and "unsigned long".
actually, according to file_operations struct:
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
"*unsigned* int" and "unsigned long" are correct types...
regards,
Signature · 4 lines
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