8d2035fba7ad9b4fec020285a17aa437f90cd84f
[people/mcb30/quickusb.git] / kernel / quickusb.c
1 /*
2  * QuickUSB driver
3  *
4  * Copyright 2006 Michael Brown <mbrown@fensystems.co.uk>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  */
12
13 #include <linux/module.h>
14 #include <linux/fs.h>
15 #include <linux/devfs_fs_kernel.h>
16 #include <linux/kref.h>
17 #include <linux/usb.h>
18 #include <asm/uaccess.h>
19 #include "quickusb.h"
20
21 #define QUICKUSB_VENDOR_ID 0x0fbb
22 #define QUICKUSB_DEVICE_ID 0x0001
23
24 #define QUICKUSB_MAX_SUBDEVS 8
25 #define QUICKUSB_SUBDEV_MASK ( QUICKUSB_MAX_SUBDEVS - 1 )
26 #define QUICKUSB_MINOR_BOARD( dev_minor ) \
27         ( (dev_minor) / QUICKUSB_MAX_SUBDEVS )
28 #define QUICKUSB_MINOR_SUBDEV( dev_minor ) \
29         ( (dev_minor) & QUICKUSB_SUBDEV_MASK )
30 #define QUICKUSB_MINOR( board, subdev ) \
31         ( (board) * QUICKUSB_MAX_SUBDEVS + (subdev) )
32
33 #define QUICKUSB_MAX_GPPIO 5
34
35 static int debug = 0;
36 static int dev_major = 0;
37
38 struct quickusb_gppio {
39         struct quickusb_device *quickusb;
40         unsigned int port;
41 };
42
43 struct quickusb_subdev {
44         struct file_operations *f_op;
45         void *private_data;
46         unsigned char name[32];
47 };
48
49 struct quickusb_device {
50         struct usb_device *usb;
51         struct usb_interface *interface;
52         struct kref kref;
53         struct list_head list;
54         unsigned int board;
55         struct quickusb_gppio gppio[QUICKUSB_MAX_GPPIO];
56         struct quickusb_subdev subdev[QUICKUSB_MAX_SUBDEVS];
57 };
58
59 static void quickusb_delete ( struct kref *kref ) {
60         struct quickusb_device *quickusb;
61
62         quickusb = container_of ( kref, struct quickusb_device, kref );
63         usb_put_dev ( quickusb->usb );
64         kfree ( quickusb );
65 }
66
67 static LIST_HEAD ( quickusb_list );
68
69 static DECLARE_MUTEX ( quickusb_lock );
70
71 /****************************************************************************
72  *
73  * GPPIO char device operations
74  *
75  */
76
77 static ssize_t quickusb_gppio_read ( struct file *file, char __user *user_data,
78                                      size_t len, loff_t *ppos ) {
79         struct quickusb_gppio *gppio = file->private_data;
80         struct usb_device *usb = gppio->quickusb->usb;
81         unsigned char data[QUICKUSB_MAX_DATA_LEN];
82         int rc;
83
84         if ( len > sizeof ( data ) )
85                 len = sizeof ( data );
86
87         if ( ( rc = quickusb_read_port ( usb, gppio->port,
88                                          data, &len ) ) != 0 )
89                 return rc;
90
91         if ( ( rc = copy_to_user ( user_data, data, len ) ) != 0 )
92                 return rc;
93
94         *ppos += len;
95         return len;
96 }
97
98 static ssize_t quickusb_gppio_write ( struct file *file,
99                                       const char __user *user_data,
100                                       size_t len, loff_t *ppos ) {
101         struct quickusb_gppio *gppio = file->private_data;
102         struct usb_device *usb = gppio->quickusb->usb;
103         unsigned char data[QUICKUSB_MAX_DATA_LEN];
104         int rc;
105
106         if ( len > sizeof ( data ) )
107                 len = sizeof ( data );
108
109         if ( ( rc = copy_from_user ( data, user_data, len ) ) != 0 )
110                 return rc;
111
112         if ( ( rc = quickusb_write_port ( usb, gppio->port,
113                                           data, &len ) ) != 0 )
114                 return rc;
115
116         *ppos += len;
117         return len;
118 }
119
120 static int quickusb_gppio_release ( struct inode *inode, struct file *file ) {
121         struct quickusb_gppio *gppio = file->private_data;
122         
123         kref_put ( &gppio->quickusb->kref, quickusb_delete );
124         return 0;
125 }
126
127 static struct file_operations quickusb_gppio_fops = {
128         .owner          = THIS_MODULE,
129         .read           = quickusb_gppio_read,
130         .write          = quickusb_gppio_write,
131         .release        = quickusb_gppio_release,
132 };
133
134 /****************************************************************************
135  *
136  * Char device (subdev) operations
137  *
138  */
139
140 static int quickusb_open ( struct inode *inode, struct file *file ) {
141         unsigned int board = QUICKUSB_MINOR_BOARD ( iminor ( inode ) );
142         unsigned int subdev = QUICKUSB_MINOR_SUBDEV ( iminor ( inode ) );
143         struct quickusb_device *quickusb;
144         int found = 0;
145         int rc = 0;
146
147         /* Locate board and increase refcount */
148         down ( &quickusb_lock );
149         list_for_each_entry ( quickusb, &quickusb_list, list ) {
150                 if ( quickusb->board == board ) {
151                         kref_get ( &quickusb->kref );
152                         found = 1;
153                         break;
154                 }
155         }
156         up ( &quickusb_lock );
157         if ( ! found ) {
158                 quickusb = NULL;
159                 rc = -ENODEV;
160                 goto out;
161         }
162
163         /* Set up per-subdevice file operations and private data */
164         file->f_op = quickusb->subdev[subdev].f_op;
165         file->private_data = quickusb->subdev[subdev].private_data;
166         if ( ! file->f_op ) {
167                 rc = -ENODEV;
168                 goto out;
169         }
170         
171         /* Perform any subdev-specific open operation */
172         if ( file->f_op->open )
173                 rc = file->f_op->open ( inode, file );
174
175  out:
176         if ( ( rc != 0 ) && quickusb )
177                 kref_put ( &quickusb->kref, quickusb_delete );
178         return rc;
179 }
180
181 static struct file_operations quickusb_fops = {
182         .owner          = THIS_MODULE,
183         .open           = quickusb_open,
184 };
185
186 /****************************************************************************
187  *
188  * Char device (subdev) registration/deregistration
189  *
190  */
191
192 static int quickusb_register_subdev ( struct quickusb_device *quickusb,
193                                       unsigned int subdev_idx,
194                                       struct file_operations *f_op,
195                                       void *private_data,
196                                       const char *subdev_fmt, ... ) {
197         struct quickusb_subdev *subdev = &quickusb->subdev[subdev_idx];
198         unsigned int dev_minor;
199         dev_t dev;
200         va_list ap;
201         int rc;
202
203         /* Construct device number */
204         dev_minor = QUICKUSB_MINOR ( quickusb->board, subdev_idx );
205         dev = MKDEV ( dev_major, dev_minor );
206
207         /* Construct device name */
208         va_start ( ap, subdev_fmt );
209         vsnprintf ( subdev->name, sizeof ( subdev->name ), subdev_fmt, ap );
210         va_end ( ap );
211
212         /* Create devfs device */
213         if ( ( rc = devfs_mk_cdev ( dev,
214                                     ( S_IFCHR | S_IRUSR | S_IWUSR |
215                                       S_IRGRP | S_IWGRP ),
216                                     subdev->name ) ) != 0 )
217                 return rc;
218
219         /* Fill subdev structure */
220         subdev->f_op = f_op;
221         subdev->private_data = private_data;
222
223         return 0;
224 }
225                                       
226 static void quickusb_deregister_subdev ( struct quickusb_device *quickusb,
227                                          unsigned int subdev_idx ) {
228         struct quickusb_subdev *subdev = &quickusb->subdev[subdev_idx];
229
230         if ( ! subdev->f_op )
231                 return;
232
233         /* Clear subdev structure */
234         memset ( subdev, 0, sizeof ( *subdev ) );
235         
236         /* Remove devfs device */
237         devfs_remove ( subdev->name );
238 }
239
240 /****************************************************************************
241  *
242  * Device creation / destruction
243  *
244  */
245
246 static int quickusb_register_devices ( struct quickusb_device *quickusb ) {
247         unsigned int subdev_idx = 0;
248         struct quickusb_gppio *gppio;
249         unsigned char gppio_char;
250         int i;
251         int rc;
252
253         /* Register GPPIO ports as subdevs */
254         for ( i = 0 ; i < QUICKUSB_MAX_GPPIO ; i++ ) {
255                 gppio = &quickusb->gppio[i];
256                 gppio_char = ( 'a' + gppio->port );
257                 if ( ( rc = quickusb_register_subdev ( quickusb, subdev_idx++,
258                                                        &quickusb_gppio_fops,
259                                                        gppio,
260                                                        "quickusb%d/gppio_%c",
261                                                        quickusb->board,
262                                                        gppio_char ) ) != 0 )
263                         return rc;
264         }
265         
266         return 0;
267 }
268
269 static void quickusb_deregister_devices ( struct quickusb_device *quickusb ) {
270         int i;
271
272         /* Deregister all subdevs */
273         for ( i = 0 ; i < QUICKUSB_MAX_SUBDEVS ; i++ ) {
274                 quickusb_deregister_subdev ( quickusb, i );
275         }
276 }
277
278 /****************************************************************************
279  *
280  * USB hotplug add/remove
281  *
282  */
283
284 static int quickusb_probe ( struct usb_interface *interface,
285                             const struct usb_device_id *id ) {
286         struct quickusb_device *quickusb = NULL;
287         struct quickusb_device *pre_existing_quickusb;
288         unsigned int board = 0;
289         int i;
290         int rc = 0;
291
292         down ( &quickusb_lock );
293
294         /* Create new quickusb device structure */
295         quickusb = kmalloc ( sizeof ( *quickusb ), GFP_KERNEL );
296         if ( ! quickusb ) {
297                 rc = -ENOMEM;
298                 goto err;
299         }
300         memset ( quickusb, 0, sizeof ( *quickusb ) );
301         kref_init ( &quickusb->kref );
302         INIT_LIST_HEAD ( &quickusb_list );
303         quickusb->usb = usb_get_dev ( interface_to_usbdev ( interface ) );
304         quickusb->interface = interface;
305         for ( i = 0 ; i < QUICKUSB_MAX_GPPIO ; i++ ) {
306                 quickusb->gppio[i].quickusb = quickusb;
307                 quickusb->gppio[i].port = i;
308         }
309         
310         /* Obtain a free board board and link into list */
311         list_for_each_entry ( pre_existing_quickusb, &quickusb_list, list ) {
312                 if ( pre_existing_quickusb->board != board )
313                         break;
314                 board++;
315         }
316         quickusb->board = board;
317         list_add_tail ( &quickusb->list, &pre_existing_quickusb->list );
318
319         /* Record driver private data */
320         usb_set_intfdata ( interface, quickusb );
321
322         /* Register devices */
323         if ( ( rc = quickusb_register_devices ( quickusb ) ) != 0 ) {
324                 printk ( KERN_ERR "quickusb unable to register devices\n" );
325                 goto err;
326         }
327
328         printk ( KERN_INFO "quickusb%d connected\n", quickusb->board ); 
329         goto out;
330
331  err:
332         usb_set_intfdata ( interface, NULL );
333         if ( quickusb ) {
334                 quickusb_deregister_devices ( quickusb );
335                 list_del ( &quickusb->list );
336                 kref_put ( &quickusb->kref, quickusb_delete );
337         }
338  out:
339         up ( &quickusb_lock );
340         return rc;
341 }
342
343 static void quickusb_disconnect ( struct usb_interface *interface ) {
344         struct quickusb_device *quickusb = usb_get_intfdata ( interface );
345
346         printk ( KERN_INFO "quickusb%d disconnected\n", quickusb->board );
347
348         down ( &quickusb_lock );
349         usb_set_intfdata ( interface, NULL );
350         quickusb_deregister_devices ( quickusb );
351         list_del ( &quickusb->list );
352         up ( &quickusb_lock );
353
354         kref_put ( &quickusb->kref, quickusb_delete );
355 }
356
357 static struct usb_device_id quickusb_ids[] = {
358         { USB_DEVICE ( QUICKUSB_VENDOR_ID, QUICKUSB_DEVICE_ID ) },
359         { },
360 };
361
362 static struct usb_driver quickusb_driver = {
363         .owner          = THIS_MODULE,
364         .name           = "quickusb",
365         .probe          = quickusb_probe,
366         .disconnect     = quickusb_disconnect,
367         .id_table       = quickusb_ids,
368 };
369
370 /****************************************************************************
371  *
372  * Kernel module interface
373  *
374  */
375
376 static int quickusb_init ( void ) {
377         int rc;
378
379         /* Register major char device */
380         if ( ( rc = register_chrdev ( dev_major, "quickusb",
381                                       &quickusb_fops ) ) < 0 )
382                 goto err_chrdev;
383         if ( ! dev_major ) {
384                 dev_major = rc;
385                 printk ( KERN_INFO "quickusb using major device %d\n",
386                          dev_major );
387         }
388         if ( ( rc = usb_register ( &quickusb_driver ) ) != 0 )
389                 goto err_usb;
390
391         return 0;
392
393  err_usb:
394         unregister_chrdev ( dev_major, "quickusb" );
395  err_chrdev:
396         return rc;
397 }
398
399 static void quickusb_exit ( void ) {
400         usb_deregister ( &quickusb_driver );
401         unregister_chrdev ( dev_major, "quickusb" );
402 }
403
404 module_init ( quickusb_init );
405 module_exit ( quickusb_exit );
406
407 MODULE_AUTHOR ( "Michael Brown <mbrown@fensystems.co.uk>" );
408 MODULE_DESCRIPTION ( "QuickUSB serial driver" );
409 MODULE_LICENSE ( "GPL" );
410 MODULE_DEVICE_TABLE ( usb, quickusb_ids );
411
412 module_param ( debug, bool, S_IRUGO | S_IWUSR );
413 MODULE_PARM_DESC ( debug, "Enable debugging" );
414
415 module_param ( dev_major, uint, S_IRUGO | S_IWUSR );
416 MODULE_PARM_DESC ( dev_major, "Major device number" );