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 return -ENODEV; 317 } 318 319 /* set up the endpoint information */ 320 /* use only the first bulk-in and bulk-out endpoints */ 321 iface_desc = interface->cur_altsetting; 322 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 323 endpoint = &iface_desc->endpoint[i].desc; 324 325 if (!dev->bulk_in_endpointAddr && 326 usb_endpoint_is_bulk_in(endpoint)) { 327 /* we found a bulk in endpoint */ 328 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 329 dev->bulk_in_size = buffer_size; 330 dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; 331 dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 332 if (!dev->bulk_in_buffer) { 333 err("Could not allocate bulk_in_buffer"); 334 goto error; 335 } 336 } 337 338 if (!dev->bulk_out_endpointAddr && 339 usb_endpoint_is_bulk_out(endpoint)) { 340 /* we found a bulk out endpoint */ 341 dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 342 } 343 } 344 if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { 345 err("Could not find both bulk-in and bulk-out endpoints"); 346 goto error; 347 } 348 349 /* save our data pointer in this interface device */ 350 usb_set_intfdata(interface, dev); 351 352 /* we can register the device now, as it is ready */ 353 retval = usb_register_dev(interface, &lcd_class); 354 if (retval) { 355 /* something prevented us from registering this driver */ 356 err("Not able to get a minor for this device."); 357 usb_set_intfdata(interface, NULL); 358 goto error; 359 } 360 361 i = le16_to_cpu(dev->udev->descriptor.bcdDevice); 362 363 dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found " 364 "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8, 365 (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum); 366 367 /* let the user know what node this device is now attached to */ 368 dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n", 369 interface->minor); 370 return 0; 371 372 error: 373 if (dev) 374 kref_put(&dev->kref, lcd_delete); 375 return retval; 376 } 377 378 static void lcd_draw_down(struct usb_lcd *dev) 379 { 380 int time; 381 382 time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); 383 if (!time) 384 usb_kill_anchored_urbs(&dev->submitted); 385 } 386 387 static int lcd_suspend(struct usb_interface *intf, pm_message_t message) 388 { 389 struct usb_lcd *dev = usb_get_intfdata(intf); 390 391 if (!dev) 392 return 0; 393 lcd_draw_down(dev); 394 return 0; 395 } 396 397 static int lcd_resume (struct usb_interface *intf) 398 { 399 return 0; 400 } 401 402 static void lcd_disconnect(struct usb_interface *interface) 403 { 404 struct usb_lcd *dev; 405 int minor = interface->minor; 406 407 mutex_lock(&open_disc_mutex); 408 dev = usb_get_intfdata(interface); 409 usb_set_intfdata(interface, NULL); 410 mutex_unlock(&open_disc_mutex); 411 412 /* give back our minor */ 413 usb_deregister_dev(interface, &lcd_class); 414 415 /* decrement our usage count */ 416 kref_put(&dev->kref, lcd_delete); 417 418 dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor); 419 } 420 421 static struct usb_driver lcd_driver = { 422 .name = "usblcd", 423 .probe = lcd_probe, 424 .disconnect = lcd_disconnect, 425 .suspend = lcd_suspend, 426 .resume = lcd_resume, 427 .id_table = id_table, 428 .supports_autosuspend = 1, 429 }; 430 431 static int __init usb_lcd_init(void) 432 { 433 int result; 434 435 result = usb_register(&lcd_driver); 436 if (result) 437 err("usb_register failed. Error number %d", result); 438 439 return result; 440 } 441 442 443 static void __exit usb_lcd_exit(void) 444 { 445 usb_deregister(&lcd_driver); 446 } 447 448 module_init(usb_lcd_init); 449 module_exit(usb_lcd_exit); 450 451 MODULE_AUTHOR("Georges Toth <g.toth@e-biz.lu>"); 452 MODULE_DESCRIPTION(DRIVER_VERSION); 453 MODULE_LICENSE("GPL"); 454