aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/phidgetservo.c
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2006-08-11 05:28:28 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:49 -0400
commitda308e8da700637d6271dddda08128094691b980 (patch)
tree07d132503e754915db98171cd00e106c27138b64 /drivers/usb/misc/phidgetservo.c
parent912b24c333843514ff77ed88961c6945f0f286ce (diff)
USB: Phidgets should check create_device_file() return value
device_create_file() could fail, add proper error paths for this condition. Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/misc/phidgetservo.c')
-rw-r--r--drivers/usb/misc/phidgetservo.c74
1 files changed, 48 insertions, 26 deletions
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 66be9513fd6f..7163f05c5b27 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * USB PhidgetServo driver 1.0 2 * USB PhidgetServo driver 1.0
3 * 3 *
4 * Copyright (C) 2004 Sean Young <sean@mess.org> 4 * Copyright (C) 2004, 2006 Sean Young <sean@mess.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
@@ -235,86 +235,108 @@ static ssize_t show_servo##value (struct device *dev, \
235 \ 235 \
236 return sprintf(buf, "%d.%02d\n", servo->degrees[value], \ 236 return sprintf(buf, "%d.%02d\n", servo->degrees[value], \
237 servo->minutes[value]); \ 237 servo->minutes[value]); \
238} \ 238}
239static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
240 show_servo##value, set_servo##value);
241 239
240#define servo_attr(value) \
241 __ATTR(servo##value, S_IWUGO | S_IRUGO, \
242 show_servo##value, set_servo##value)
242show_set(0); 243show_set(0);
243show_set(1); 244show_set(1);
244show_set(2); 245show_set(2);
245show_set(3); 246show_set(3);
246 247
248static struct device_attribute dev_attrs[] = {
249 servo_attr(0), servo_attr(1), servo_attr(2), servo_attr(3)
250};
251
247static int 252static int
248servo_probe(struct usb_interface *interface, const struct usb_device_id *id) 253servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
249{ 254{
250 struct usb_device *udev = interface_to_usbdev(interface); 255 struct usb_device *udev = interface_to_usbdev(interface);
251 struct phidget_servo *dev; 256 struct phidget_servo *dev;
252 int bit, value; 257 int bit, value, rc;
258 int servo_count, i;
253 259
254 dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL); 260 dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
255 if (dev == NULL) { 261 if (dev == NULL) {
256 dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); 262 dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
257 return -ENOMEM; 263 rc = -ENOMEM;
264 goto out;
258 } 265 }
259 266
260 dev->udev = usb_get_dev(udev); 267 dev->udev = usb_get_dev(udev);
261 dev->type = id->driver_info; 268 dev->type = id->driver_info;
269 dev->dev_no = -1;
262 usb_set_intfdata(interface, dev); 270 usb_set_intfdata(interface, dev);
263 271
264 do { 272 do {
265 bit = find_first_zero_bit(&device_no, sizeof(device_no)); 273 bit = find_first_zero_bit(&device_no, sizeof(device_no));
266 value = test_and_set_bit(bit, &device_no); 274 value = test_and_set_bit(bit, &device_no);
267 } while(value); 275 } while (value);
268 dev->dev_no = bit; 276 dev->dev_no = bit;
269 277
270 dev->dev = device_create(phidget_class, &dev->udev->dev, 0, 278 dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
271 "servo%d", dev->dev_no); 279 "servo%d", dev->dev_no);
272 if (IS_ERR(dev->dev)) { 280 if (IS_ERR(dev->dev)) {
273 int rc = PTR_ERR(dev->dev); 281 rc = PTR_ERR(dev->dev);
274 clear_bit(dev->dev_no, &device_no); 282 dev->dev = NULL;
275 kfree(dev); 283 goto out;
276 return rc;
277 } 284 }
278 285
279 device_create_file(dev->dev, &dev_attr_servo0); 286 servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
280 if (dev->type & SERVO_COUNT_QUAD) { 287
281 device_create_file(dev->dev, &dev_attr_servo1); 288 for (i=0; i<servo_count; i++) {
282 device_create_file(dev->dev, &dev_attr_servo2); 289 rc = device_create_file(dev->dev, &dev_attrs[i]);
283 device_create_file(dev->dev, &dev_attr_servo3); 290 if (rc)
291 goto out2;
284 } 292 }
285 293
286 dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n", 294 dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
287 dev->type & SERVO_COUNT_QUAD ? 4 : 1, 295 servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
288 dev->type & SERVO_VERSION_30 ? 3 : 2);
289 296
290 if (!(dev->type & SERVO_VERSION_30)) 297 if (!(dev->type & SERVO_VERSION_30))
291 dev_info(&interface->dev, 298 dev_info(&interface->dev,
292 "WARNING: v2.0 not tested! Please report if it works.\n"); 299 "WARNING: v2.0 not tested! Please report if it works.\n");
293 300
294 return 0; 301 return 0;
302out2:
303 while (i-- > 0)
304 device_remove_file(dev->dev, &dev_attrs[i]);
305out:
306 if (dev) {
307 if (dev->dev)
308 device_unregister(dev->dev);
309 if (dev->dev_no >= 0)
310 clear_bit(dev->dev_no, &device_no);
311
312 kfree(dev);
313 }
314
315 return rc;
295} 316}
296 317
297static void 318static void
298servo_disconnect(struct usb_interface *interface) 319servo_disconnect(struct usb_interface *interface)
299{ 320{
300 struct phidget_servo *dev; 321 struct phidget_servo *dev;
322 int servo_count, i;
301 323
302 dev = usb_get_intfdata(interface); 324 dev = usb_get_intfdata(interface);
303 usb_set_intfdata(interface, NULL); 325 usb_set_intfdata(interface, NULL);
304 326
305 device_remove_file(dev->dev, &dev_attr_servo0); 327 if (!dev)
306 if (dev->type & SERVO_COUNT_QUAD) { 328 return;
307 device_remove_file(dev->dev, &dev_attr_servo1); 329
308 device_remove_file(dev->dev, &dev_attr_servo2); 330 servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
309 device_remove_file(dev->dev, &dev_attr_servo3); 331
310 } 332 for (i=0; i<servo_count; i++)
333 device_remove_file(dev->dev, &dev_attrs[i]);
311 334
312 device_unregister(dev->dev); 335 device_unregister(dev->dev);
313 usb_put_dev(dev->udev); 336 usb_put_dev(dev->udev);
314 337
315 dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n", 338 dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
316 dev->type & SERVO_COUNT_QUAD ? 4 : 1, 339 servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
317 dev->type & SERVO_VERSION_30 ? 3 : 2);
318 340
319 clear_bit(dev->dev_no, &device_no); 341 clear_bit(dev->dev_no, &device_no);
320 kfree(dev); 342 kfree(dev);