diff options
Diffstat (limited to 'drivers/usb/misc/phidgetservo.c')
| -rw-r--r-- | drivers/usb/misc/phidgetservo.c | 71 | 
1 files changed, 44 insertions, 27 deletions
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index c0df79c9653..66be9513fd6 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -15,14 +15,6 @@   *   * CAUTION: Generally you should use 0 < degrees < 180 as anything else   * is probably beyond the range of your servo and may damage it. - * - * Jun 16, 2004: Sean Young <sean@mess.org> - *  - cleanups - *  - was using memory after kfree() - * Aug 8, 2004: Sean Young <sean@mess.org> - *  - set the highest angle as high as the hardware allows, there are  - *    some odd servos out there - *   */  #include <linux/kernel.h> @@ -32,6 +24,8 @@  #include <linux/module.h>  #include <linux/usb.h> +#include "phidget.h" +  #define DRIVER_AUTHOR "Sean Young <sean@mess.org>"  #define DRIVER_DESC "USB PhidgetServo Driver" @@ -70,8 +64,12 @@ static struct usb_device_id id_table[] = {  MODULE_DEVICE_TABLE(usb, id_table); +static int unsigned long device_no; +  struct phidget_servo {  	struct usb_device *udev; +	struct device *dev; +	int dev_no;  	ulong type;  	int pulse[4];  	int degrees[4]; @@ -203,16 +201,16 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,  }  #define show_set(value)	\ -static ssize_t set_servo##value (struct device *dev, struct device_attribute *attr,			\ +static ssize_t set_servo##value (struct device *dev, 			\ +					struct device_attribute *attr,	\  					const char *buf, size_t count)	\  {									\  	int degrees, minutes, retval;					\ -	struct usb_interface *intf = to_usb_interface (dev);		\ -	struct phidget_servo *servo = usb_get_intfdata (intf);		\ +	struct phidget_servo *servo = dev_get_drvdata(dev);		\  									\  	minutes = 0;							\  	/* must at least convert degrees */				\ -	if (sscanf (buf, "%d.%d", °rees, &minutes) < 1) {		\ +	if (sscanf(buf, "%d.%d", °rees, &minutes) < 1) {		\  		return -EINVAL;						\  	}								\  									\ @@ -220,21 +218,22 @@ static ssize_t set_servo##value (struct device *dev, struct device_attribute *at  		return -EINVAL;						\  									\  	if (servo->type & SERVO_VERSION_30)				\ -		retval = change_position_v30 (servo, value, degrees, 	\ +		retval = change_position_v30(servo, value, degrees, 	\  							minutes);	\  	else 								\ -		retval = change_position_v20 (servo, value, degrees, 	\ +		retval = change_position_v20(servo, value, degrees, 	\  							minutes);	\  									\  	return retval < 0 ? retval : count;				\  }									\  									\ -static ssize_t show_servo##value (struct device *dev, struct device_attribute *attr, char *buf) 	\ +static ssize_t show_servo##value (struct device *dev,			\ +					struct device_attribute *attr,	\ +					char *buf) 			\  {									\ -	struct usb_interface *intf = to_usb_interface (dev);		\ -	struct phidget_servo *servo = usb_get_intfdata (intf);		\ +	struct phidget_servo *servo = dev_get_drvdata(dev);		\  									\ -	return sprintf (buf, "%d.%02d\n", servo->degrees[value],	\ +	return sprintf(buf, "%d.%02d\n", servo->degrees[value],		\  				servo->minutes[value]);			\  }									\  static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO,			\ @@ -250,6 +249,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)  {  	struct usb_device *udev = interface_to_usbdev(interface);  	struct phidget_servo *dev; +	int bit, value;  	dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);  	if (dev == NULL) { @@ -261,18 +261,33 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)  	dev->type = id->driver_info;  	usb_set_intfdata(interface, dev); -	device_create_file(&interface->dev, &dev_attr_servo0); +        do { +                bit = find_first_zero_bit(&device_no, sizeof(device_no)); +                value = test_and_set_bit(bit, &device_no); +        } while(value); +	dev->dev_no = bit; + +	dev->dev = device_create(phidget_class, &dev->udev->dev, 0, +				 "servo%d", dev->dev_no); +	if (IS_ERR(dev->dev)) { +		int rc = PTR_ERR(dev->dev); +		clear_bit(dev->dev_no, &device_no); +		kfree(dev); +		return rc; +	} + +	device_create_file(dev->dev, &dev_attr_servo0);  	if (dev->type & SERVO_COUNT_QUAD) { -		device_create_file(&interface->dev, &dev_attr_servo1); -		device_create_file(&interface->dev, &dev_attr_servo2); -		device_create_file(&interface->dev, &dev_attr_servo3); +		device_create_file(dev->dev, &dev_attr_servo1); +		device_create_file(dev->dev, &dev_attr_servo2); +		device_create_file(dev->dev, &dev_attr_servo3);  	}  	dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",  		dev->type & SERVO_COUNT_QUAD ? 4 : 1,  		dev->type & SERVO_VERSION_30 ? 3 : 2); -	if(!(dev->type & SERVO_VERSION_30)) +	if (!(dev->type & SERVO_VERSION_30))  		dev_info(&interface->dev,  			 "WARNING: v2.0 not tested! Please report if it works.\n"); @@ -287,19 +302,21 @@ servo_disconnect(struct usb_interface *interface)  	dev = usb_get_intfdata(interface);  	usb_set_intfdata(interface, NULL); -	device_remove_file(&interface->dev, &dev_attr_servo0); +	device_remove_file(dev->dev, &dev_attr_servo0);  	if (dev->type & SERVO_COUNT_QUAD) { -		device_remove_file(&interface->dev, &dev_attr_servo1); -		device_remove_file(&interface->dev, &dev_attr_servo2); -		device_remove_file(&interface->dev, &dev_attr_servo3); +		device_remove_file(dev->dev, &dev_attr_servo1); +		device_remove_file(dev->dev, &dev_attr_servo2); +		device_remove_file(dev->dev, &dev_attr_servo3);  	} +	device_unregister(dev->dev);  	usb_put_dev(dev->udev);  	dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",  		dev->type & SERVO_COUNT_QUAD ? 4 : 1,  		dev->type & SERVO_VERSION_30 ? 3 : 2); +	clear_bit(dev->dev_no, &device_no);  	kfree(dev);  }  |