1 /***************************************************************************** 2 * USBLCD Kernel Driver * 3 * Version 1.05 * 4 * (C) 2005 Georges Toth <g.toth@e-biz.lu> * 5 * * 6 * This file is licensed under the GPL. See COPYING in the package. * 7 * Based on usb-skeleton.c 2.0 by Greg Kroah-Hartman (greg@kroah.com) * 8 * * 9 * * 10 * 28.02.05 Complete rewrite of the original usblcd.c driver, * 11 * based on usb_skeleton.c. * 12 * This new driver allows more than one USB-LCD to be connected * 13 * and controlled, at once * 14 *****************************************************************************/ 15 #include <linux/module.h> 16 #include <linux/kernel.h> 17 #include <linux/init.h> 18 #include <linux/slab.h> 19 #include <linux/smp_lock.h> 20 #include <linux/errno.h> 21 #include <linux/mutex.h> 22 #include <asm/uaccess.h> 23 #include <linux/usb.h> 24 25 #define DRIVER_VERSION "USBLCD Driver Version 1.05" 26 27 #define USBLCD_MINOR 144 28 29 #define IOCTL_GET_HARD_VERSION 1 30 #define IOCTL_GET_DRV_VERSION 2 31 32 33 static struct usb_device_id id_table [] = { 34 { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, }, 35 { }, 36 }; 37 MODULE_DEVICE_TABLE (usb, id_table); 38 39 static DEFINE_MUTEX(open_disc_mutex); 40 41 42 struct usb_lcd { 43 struct usb_device * udev; /* init: probe_lcd */ 44 struct usb_interface * interface; /* the interface for this device */ 45 unsigned char * bulk_in_buffer; /* the buffer to receive data */ 46 size_t bulk_in_size; /* the size of the receive buffer */ 47 __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 48 __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 49 struct kref kref; 50 struct semaphore limit_sem; /* to stop writes at full throttle from 51 * using up all RAM */ 52 struct usb_anchor submitted; /* URBs to wait for before suspend */ 53 }; 54 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) 55 56 #define USB_LCD_CONCURRENT_WRITES 5 57 58 static struct usb_driver lcd_driver; 59 60 61 static void lcd_delete(struct kref *kref) 62 { 63 struct usb_lcd *dev = to_lcd_dev(kref); 64 65 usb_put_dev(dev->udev); 66 kfree (dev->bulk_in_buffer); 67 kfree (dev); 68 } 69 70 71 static int lcd_open(struct inode *inode, struct file *file) 72 { 73 struct usb_lcd *dev; 74 struct usb_interface *interface; 75 int subminor, r; 76 77 subminor = iminor(inode); 78 79 interface = usb_find_interface(&lcd_driver, subminor); 80 if (!interface) { 81 err ("USBLCD: %s - error, can't find device for minor %d", 82 __func__, subminor); 83 return -ENODEV; 84 } 85 86 mutex_lock(&open_disc_mutex); 87 dev = usb_get_intfdata(interface); 88 if (!dev) { 89 mutex_unlock(&open_disc_mutex); 90 return -ENODEV; 91 } 92 93 /* increment our usage count for the device */ 94 kref_get(&dev->kref); 95 mutex_unlock(&open_disc_mutex); 96 97 /* grab a power reference */ 98 r = usb_autopm_get_interface(interface); 99 if (r < 0) { 100 kref_put(&dev->kref, lcd_delete); 101 return r; 102 } 103 104 /* save our object in the file's private structure */ 105 file->private_data = dev; 106 107 return 0; 108 } 109 110 static int lcd_release(struct inode *inode, struct file *file) 111 { 112 struct usb_lcd *dev; 113 114 dev = (struct usb_lcd *)file->private_data; 115 if (dev == NULL) 116 return -ENODEV; 117 118 /* decrement the count on our device */ 119 usb_autopm_put_interface(dev->interface); 120 kref_put(&dev->kref, lcd_delete); 121 return 0; 122 } 123 124 static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos) 125 { 126 struct usb_lcd *dev; 127 int retval = 0; 128 int bytes_read; 129 130 dev = (struct usb_lcd *)file->private_data; 131 132 /* do a blocking bulk read to get data from the device */ 133 retval = usb_bulk_msg(dev->udev, 134 usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), 135 dev->bulk_in_buffer, 136 min(dev->bulk_in_size, count), 137 &bytes_read, 10000); 138 139 /* if the read was successful, copy the data to userspace */ 140 if (!retval) { 141 if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read)) 142 retval = -EFAULT; 143 else 144 retval = bytes_read; 145 } 146 147 return retval; 148 } 149 150 static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 151 { 152 struct usb_lcd *dev; 153 u16 bcdDevice; 154 char buf[30]; 155 156 dev = (struct usb_lcd *)file->private_data; 157 if (dev == NULL) 158 return -ENODEV; 159 160 switch (cmd) { 161 case IOCTL_GET_HARD_VERSION: 162 lock_kernel(); 163 bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice); 164 sprintf(buf,"%1d%1d.%1d%1d", 165 (bcdDevice & 0xF000)>>12, 166 (bcdDevice & 0xF00)>>8, 167 (bcdDevice & 0xF0)>>4, 168 (bcdDevice & 0xF)); 169 unlock_kernel(); 170 if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) 171 return -EFAULT; 172 break; 173 case IOCTL_GET_DRV_VERSION: 174 sprintf(buf,DRIVER_VERSION); 175 if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) 176 return -EFAULT; 177 break; 178 default: 179 return -ENOTTY; 180 break; 181 } 182 183 return 0; 184 } 185 186 static void lcd_write_bulk_callback(struct urb *urb) 187 { 188 struct usb_lcd *dev; 189 int status = urb->status; 190 191 dev = urb->context; 192 193 /* sync/async unlink faults aren't errors */ 194 if (status && 195 !(status == -ENOENT || 196 status == -ECONNRESET || 197 status == -ESHUTDOWN)) { 198 dbg("USBLCD: %s - nonzero write bulk status received: %d", 199 __func__, status); 200 } 201 202 /* free up our allocated buffer */ 203 usb_buffer_free(urb->dev, urb->transfer_buffer_length, 204 urb->transfer_buffer, urb->transfer_dma); 205 up(&dev->limit_sem); 206 } 207 208 static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) 209 { 210 struct usb_lcd *dev; 211 int retval = 0, r; 212 struct urb *urb = NULL; 213 char *buf = NULL; 214 215 dev = (struct usb_lcd *)file->private_data; 216 217 /* verify that we actually have some data to write */ 218 if (count == 0) 219 goto exit; 220 221 r = down_interruptible(&dev->limit_sem); 222 if (r < 0) 223 return -EINTR; 224 225 /* create a urb, and a buffer for it, and copy the data to the urb */ 226 urb = usb_alloc_urb(0, GFP_KERNEL); 227 if (!urb) { 228 retval = -ENOMEM; 229 goto err_no_buf; 230 } 231 232 buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); 233 if (!buf) { 234 retval = -ENOMEM; 235 goto error; 236 } 237 238 if (copy_from_user(buf, user_buffer, count)) { 239 retval = -EFAULT; 240 goto error; 241 } 242 243 /* initialize the urb properly */ 244 usb_fill_bulk_urb(urb, dev->udev, 245 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 246 buf, count, lcd_write_bulk_callback, dev); 247 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 248 249 usb_anchor_urb(urb, &dev->submitted); 250 251 /* send the data out the bulk port */ 252 retval = usb_submit_urb(urb, GFP_KERNEL); 253 if (retval) { 254 err("USBLCD: %s - failed submitting write urb, error %d", __func__, retval); 255 goto error_unanchor; 256 } 257 258 /* release our reference to this urb, the USB core will eventually free it entirely */ 259 usb_free_urb(urb); 260 261 exit: 262 return count; 263 error_unanchor: 264 usb_unanchor_urb(urb); 265 error: 266 usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); 267 usb_free_urb(urb); 268 err_no_buf: 269 up(&dev->limit_sem); 270 return retval; 271 } 272 273 static const struct file_operations lcd_fops = { 274 .owner = THIS_MODULE, 275 .read = lcd_read, 276 .write = lcd_write, 277 .open = lcd_open, 278 .unlocked_ioctl = lcd_ioctl, 279 .release = lcd_release, 280 }; 281 282 /* 283 * usb class driver info in order to get a minor number from the usb core, 284 * and to have the device registered with the driver core 285 */ 286 static struct usb_class_driver lcd_class = { 287 .name = "lcd%d", 288 .fops = &lcd_fops, 289 .minor_base = USBLCD_MINOR, 290 }; 291 292 static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id) 293 { 294 struct usb_lcd *dev = NULL; 295 struct usb_host_interface *iface_desc; 296 struct usb_endpoint_descriptor *endpoint; 297 size_t buffer_size; 298 int i; 299 int retval = -ENOMEM; 300 301 /* allocate memory for our device state and initialize it */ 302 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 303 if (dev == NULL) { 304 err("Out of memory"); 305 goto error; 306 } 307 kref_init(&dev->kref); 308 sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); 309 init_usb_anchor(&dev->submitted); 310 311 dev->udev = usb_get_dev(interface_to_usbdev(interface)); 312 dev->interface = interface; 313 314 if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) { 315 dev_warn(&interface->dev, "USBLCD model not supported.\n"); 316 retval = -ENODEV; 317 goto error; 318 } 319 320 /* set up the endpoint information */ 321 /* use only the first bulk-in and bulk-out endpoints */ 322 iface_desc = interface->cur_altsetting; 323 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 324 endpoint = &iface_desc->endpoint[i].desc; 325 326 if (!dev->bulk_in_endpointAddr && 327 usb_endpoint_is_bulk_in(endpoint)) { 328 /* we found a bulk in endpoint */ 329 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 330 dev->bulk_in_size = buffer_size; 331 dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; 332 dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 333 if (!dev->bulk_in_buffer) { 334 err("Could not allocate bulk_in_buffer"); 335 goto error; 336 } 337 } 338 339 if (!dev->bulk_out_endpointAddr && 340 usb_endpoint_is_bulk_out(endpoint)) { 341 /* we found a bulk out endpoint */ 342 dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 343 } 344 } 345 if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { 346 err("Could not find both bulk-in and bulk-out endpoints"); 347 goto error; 348 } 349 350 /* save our data pointer in this interface device */ 351 usb_set_intfdata(interface, dev); 352 353 /* we can register the device now, as it is ready */ 354 retval = usb_register_dev(interface, &lcd_class); 355 if (retval) { 356 /* something prevented us from registering this driver */ 357 err("Not able to get a minor for this device."); 358 usb_set_intfdata(interface, NULL); 359 goto error; 360 } 361 362 i = le16_to_cpu(dev->udev->descriptor.bcdDevice); 363 364 dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found " 365 "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8, 366 (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum); 367 368 /* let the user know what node this device is now attached to */ 369 dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n", 370 interface->minor); 371 return 0; 372 373 error: 374 if (dev) 375 kref_put(&dev->kref, lcd_delete); 376 return retval; 377 } 378 379 static void lcd_draw_down(struct usb_lcd *dev) 380 { 381 int time; 382 383 time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); 384 if (!time) 385 usb_kill_anchored_urbs(&dev->submitted); 386 } 387 388 static int lcd_suspend(struct usb_interface *intf, pm_message_t message) 389 { 390 struct usb_lcd *dev = usb_get_intfdata(intf); 391 392 if (!dev) 393 return 0; 394 lcd_draw_down(dev); 395 return 0; 396 } 397 398 static int lcd_resume (struct usb_interface *intf) 399 { 400 return 0; 401 } 402 403 static void lcd_disconnect(struct usb_interface *interface) 404 { 405 struct usb_lcd *dev; 406 int minor = interface->minor; 407 408 mutex_lock(&open_disc_mutex); 409 dev = usb_get_intfdata(interface); 410 usb_set_intfdata(interface, NULL); 411 mutex_unlock(&open_disc_mutex); 412 413 /* give back our minor */ 414 usb_deregister_dev(interface, &lcd_class); 415 416 /* decrement our usage count */ 417 kref_put(&dev->kref, lcd_delete); 418 419 dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor); 420 } 421 422 static struct usb_driver lcd_driver = { 423 .name = "usblcd", 424 .probe = lcd_probe, 425 .disconnect = lcd_disconnect, 426 .suspend = lcd_suspend, 427 .resume = lcd_resume, 428 .id_table = id_table, 429 .supports_autosuspend = 1, 430 }; 431 432 static int __init usb_lcd_init(void) 433 { 434 int result; 435 436 result = usb_register(&lcd_driver); 437 if (result) 438 err("usb_register failed. Error number %d", result); 439 440 return result; 441 } 442 443 444 static void __exit usb_lcd_exit(void) 445 { 446 usb_deregister(&lcd_driver); 447 } 448 449 module_init(usb_lcd_init); 450 module_exit(usb_lcd_exit); 451 452 MODULE_AUTHOR("Georges Toth <g.toth@e-biz.lu>"); 453 MODULE_DESCRIPTION(DRIVER_VERSION); 454 MODULE_LICENSE("GPL"); 455