Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

  1. /************************************************************************\
  2. ##                                                                      ##
  3. ##  Creation Date: 17 Mar 2007                                          ##
  4. ##  Last Update:   18 Mar 2007                                          ##
  5. ##  Author:       XInstruments                                          ##
  6. ##                                                                      ##
  7. \************************************************************************/
  8.  
  9.  
  10. #include        <linux/kernel.h>
  11. #include        <linux/init.h>
  12. #include        <linux/module.h>
  13. #include        <linux/usb.h>
  14. #include        <asm/uaccess.h>
  15. #include        "usmcdrv-driver.h"
  16. #include        "usmctypes.h"
  17. #include        "usmcpkt.h"
  18.  
  19. #include <linux/slab.h>
  20.  
  21. #if HAVE_UNLOCKED_IOCTL
  22.     #include <linux/mutex.h>
  23. #else
  24.     #include <linux/smp_lock.h>
  25. #endif
  26. #define  info( format, arg...) printk(KERN_INFO  USMC_DEV_NAME ": " format "\n", ## arg)
  27. #define  err( format, arg...) printk(KERN_ERR  USMC_DEV_NAME ": " format "\n", ## arg)
  28.  
  29.  
  30.  
  31. MODULE_DESCRIPTION ( "MicroSMC driver for Linux" );
  32. MODULE_AUTHOR      ( "XInstruments" );
  33. MODULE_LICENSE     ( "GPL"  );
  34. MODULE_VERSION     ( "1.0" );
  35.  
  36.  
  37. static int num_devices = 0;     // Number of currently connected devices.
  38.  
  39.  
  40. /*-----------------------------------------------------
  41.                 Init/Deinit section
  42. -----------------------------------------------------*/
  43. static int usmcdrv_init_module ( void )
  44. {
  45.         int res;
  46.  
  47.         printk ( KERN_DEBUG "Module usmcdrv init\n" );
  48.         res = usb_register ( &usmc_driver );
  49.  
  50.         if ( res )
  51.                 err ( "usb_register failed. Error number %d", res );
  52.  
  53.         return  res;
  54. }
  55.  
  56.  
  57. static void usmcdrv_exit_module ( void )
  58. {
  59.         printk ( KERN_DEBUG "Module usmcdrv exit\n" );
  60.  
  61.         usb_deregister ( &usmc_driver );
  62. }
  63.  
  64.  
  65. module_init ( usmcdrv_init_module );
  66. module_exit ( usmcdrv_exit_module );
  67.  
  68.  
  69. /*-----------------------------------------------------
  70.                 Connect/Disconnect section
  71. -----------------------------------------------------*/
  72. static int usmc_probe ( struct usb_interface * interface,
  73.                         const struct usb_device_id * id )
  74. {
  75.         struct usb_usmc * dev = NULL;
  76.         int retval = -ENOMEM;
  77.  
  78.         dev = kzalloc ( sizeof ( *dev ), GFP_KERNEL );
  79.  
  80.         if ( dev == NULL ) {
  81.                 err ( "Out of memory" );
  82.                 goto    error;
  83.         }
  84.  
  85.         kref_init ( &dev -> kref );
  86.         sema_init ( &dev -> limit_sem, WRITES_IN_FLIGHT );
  87.  
  88.         dev -> udev = usb_get_dev ( interface_to_usbdev ( interface ) );
  89.         dev -> interface = interface;
  90.  
  91.         usb_set_intfdata ( interface, dev );
  92.         retval = usb_register_dev ( interface, &usmc_class );
  93.  
  94.         if ( retval )
  95.         {
  96.                 err ( "Not able to get a minor for this device." );
  97.                 usb_set_intfdata ( interface, NULL );
  98.                 goto    error;
  99.         }
  100.  
  101.         info ( USMC_DEV_NAME " device now attached to USBusmc-%d", interface -> minor );
  102.         num_devices++;
  103.  
  104.         return  0;
  105. error:
  106.         if ( dev )
  107.                 kref_put ( &dev -> kref, usmc_delete );
  108.  
  109.         return  retval;
  110. }
  111.  
  112.  
  113. static void usmc_disconnect ( struct usb_interface * interface )
  114. {
  115.         struct usb_usmc * dev;
  116.         int minor = interface -> minor;
  117.  
  118. #if HAVE_UNLOCKED_IOCTL
  119.     struct mutex  fs_mutex;
  120.    mutex_init(&fs_mutex);
  121.    mutex_lock(&fs_mutex);
  122. #else
  123.    lock_kernel();
  124. #endif
  125.  
  126.         dev = usb_get_intfdata ( interface );
  127.         usb_set_intfdata ( interface, NULL );
  128.  
  129.         /* give back our minor */
  130.         usb_deregister_dev ( interface, &usmc_class );
  131.         num_devices--;
  132.  
  133. #if HAVE_UNLOCKED_IOCTL
  134.    mutex_unlock(&fs_mutex);
  135. #else
  136.    unlock_kernel();
  137. #endif
  138.  
  139.         /* decrement our usage count */
  140.         kref_put ( &dev -> kref, usmc_delete );
  141.  
  142.         info ( USMC_DEV_NAME " #%d now disconnected", minor );
  143. }
  144.  
  145.  
  146. /*-----------------------------------------------------
  147.                 File operations section
  148. -----------------------------------------------------*/
  149. static int usmc_open ( struct inode * inode, struct file * file )
  150. {
  151.         struct usb_usmc      * dev;
  152.         struct usb_interface * interface;
  153.         int subminor;
  154.         int retval = 0;
  155.  
  156.         info ( "usmc_open" );
  157.  
  158.         subminor = iminor ( inode );
  159.  
  160.         interface = usb_find_interface ( &usmc_driver, subminor );
  161.  
  162.         if ( !interface )
  163.         {
  164.                 err ( "%s - error, can't find device for minor %d",
  165.                      __FUNCTION__, subminor );
  166.                 retval = -ENODEV;
  167.  
  168.                 goto    exit;
  169.         }
  170.  
  171.         dev = usb_get_intfdata ( interface );
  172.  
  173.         if ( !dev )
  174.         {
  175.                 retval = -ENODEV;
  176.                 goto    exit;
  177.         }
  178.  
  179.         /* increment our usage count for the device */
  180.         kref_get ( &dev -> kref );
  181.  
  182.         /* save our object in the file's private structure */
  183.         file -> private_data = dev;
  184. exit:
  185.         return  retval;
  186. }
  187.  
  188.  
  189. static int usmc_release ( struct inode * inode, struct file * file )
  190. {
  191.         struct usb_usmc * dev;
  192.  
  193.         info ( "usmc_release" );
  194.  
  195.         dev = ( struct usb_usmc * ) file -> private_data;
  196.  
  197.         if ( dev == NULL )
  198.                 return  -ENODEV;
  199.  
  200.         /* decrement the count on our device */
  201.         kref_put ( &dev -> kref, usmc_delete );
  202.  
  203.         return  0;
  204. }
  205.  
  206.  
  207. static long usmc_ioctl ( struct file * file, unsigned int ioctl_num, unsigned long ioctl_param )
  208. {
  209.         struct usb_usmc * dev;
  210.         char * user_buf;
  211.         char * kern_buf;
  212.         char * kern_data_buf;
  213.         __u32  dwTimeOut;
  214.         long    dwRes;
  215.         int    i;
  216.         unsigned int pipe0;
  217.  
  218.         __u8  bRequestType;
  219.         __u8  bRequest;
  220.         __u16 wValue;
  221.         __u16 wIndex;
  222.         __u16 wLength;
  223.  
  224.         dev         = ( struct usb_usmc * ) file -> private_data;
  225.         user_buf = ( char * ) ioctl_param;
  226.         kern_buf = NULL;
  227.         dwTimeOut   = 30000;
  228.         dwRes       = USMC_SUCCESS;
  229.  
  230.         switch ( ioctl_num )
  231.         {
  232.         case IOCTL_GET_DESCRIPTOR_CONFIGURATION:
  233.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_DESCRIPTOR_CONFIGURATION" );
  234.  
  235.                 bsp_GetDescriptor ( GET_DESCRIPTOR_CONFIGURATION,
  236.                                     &bRequestType,
  237.                                     &bRequest,
  238.                                     &wValue,
  239.                                     &wIndex,
  240.                                     &wLength );
  241.  
  242.                 break;
  243.         case IOCTL_GET_DESCRIPTOR_DEVICE:
  244.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_DESCRIPTOR_DEVICE" );
  245.  
  246.                 bsp_GetDescriptor ( IOCTL_GET_DESCRIPTOR_DEVICE,
  247.                                     &bRequestType,
  248.                                     &bRequest,
  249.                                     &wValue,
  250.                                     &wIndex,
  251.                                     &wLength );
  252.  
  253.                 break;
  254.         case IOCTL_GET_DESCRIPTOR_STRING:
  255.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_DESCRIPTOR_STRING" );
  256.  
  257.                 bsp_GetDescriptor ( IOCTL_GET_DESCRIPTOR_STRING,
  258.                                     &bRequestType,
  259.                                     &bRequest,
  260.                                     &wValue,
  261.                                     &wIndex,
  262.                                     &wLength );
  263.  
  264.                 break;
  265.         case IOCTL_GET_STATUS_DEVICE:
  266.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_STATUS_DEVICE" );
  267.  
  268.                 bsp_GetStatus ( IOCTL_GET_STATUS_DEVICE,
  269.                                 &bRequestType,
  270.                                 &bRequest,
  271.                                 &wValue,
  272.                                 &wIndex,
  273.                                 &wLength );
  274.  
  275.                 break;
  276.         case IOCTL_GET_STATUS_ENDPOINT:
  277.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_STATUS_ENDPOINT" );
  278.  
  279.                 bsp_GetStatus ( IOCTL_GET_STATUS_ENDPOINT,
  280.                                 &bRequestType,
  281.                                 &bRequest,
  282.                                 &wValue,
  283.                                 &wIndex,
  284.                                 &wLength );
  285.  
  286.                 break;
  287.         case IOCTL_GET_STATUS_INTERFACE:
  288.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_STATUS_INTERFACE" );
  289.  
  290.                 bsp_GetStatus ( IOCTL_GET_STATUS_INTERFACE,
  291.                                 &bRequestType,
  292.                                 &bRequest,
  293.                                 &wValue,
  294.                                 &wIndex,
  295.                                 &wLength );
  296.  
  297.                 break;
  298.         case IOCTL_GET_VERSION:
  299.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_VERSION" );
  300.  
  301.                 bsp_GetVersion ( &bRequestType,
  302.                                  &bRequest,
  303.                                  &wValue,
  304.                                  &wIndex,
  305.                                  &wLength );
  306.  
  307.                 break;
  308.         case IOCTL_GET_SERIAL:
  309.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_SERIAL" );
  310.  
  311.                 bsp_GetSerial ( &bRequestType,
  312.                                 &bRequest,
  313.                                 &wValue,
  314.                                 &wIndex,
  315.                                 &wLength );
  316.  
  317.                 break;
  318.         case IOCTL_GET_ENCODER_STATE:
  319.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_ENCODER_STATE" );
  320.  
  321.                 bsp_GetEncoderState ( &bRequestType,
  322.                                       &bRequest,
  323.                                       &wValue,
  324.                                       &wIndex,
  325.                                       &wLength );
  326.  
  327.                 break;
  328.         case IOCTL_GET_STATE:
  329.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_STATE" );
  330.  
  331.                 bsp_GetState ( &bRequestType,
  332.                                &bRequest,
  333.                                &wValue,
  334.                                &wIndex,
  335.                                &wLength );
  336.  
  337.                 break;
  338.         case IOCTL_GO_TO:
  339.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GO_TO" );
  340.  
  341.                 kern_buf = bsp_GoTo ( user_buf,
  342.                            &bRequestType,
  343.                            &bRequest,
  344.                            &wValue,
  345.                            &wIndex,
  346.                            &wLength );
  347.  
  348.                 break;
  349.         case IOCTL_SET_MODE:
  350.                 info ( "usmc_ioctl. ioctl_num: IOCTL_SET_MODE" );
  351.  
  352.                 kern_buf = bsp_SetMode ( user_buf,
  353.                            &bRequestType,
  354.                            &bRequest,
  355.                            &wValue,
  356.                            &wIndex,
  357.                            &wLength );
  358.  
  359.                 break;
  360.         case IOCTL_SET_PARAMETERS:
  361.                 info ( "usmc_ioctl. ioctl_num: IOCTL_SET_PARAMETERS" );
  362.  
  363.                 kern_buf = bsp_SetParameters ( user_buf,
  364.                            &bRequestType,
  365.                            &bRequest,
  366.                            &wValue,
  367.                            &wIndex,
  368.                            &wLength );
  369.  
  370.                 break;
  371.         case IOCTL_DOWNLOAD:
  372.                 info ( "usmc_ioctl. ioctl_num: IOCTL_DOWNLOAD" );
  373.  
  374.                 kern_buf = bsp_Download ( user_buf,
  375.                            &bRequestType,
  376.                            &bRequest,
  377.                            &wValue,
  378.                            &wIndex,
  379.                            &wLength );
  380.  
  381.                 break;
  382.         case IOCTL_SET_SERIAL:
  383.                 info ( "usmc_ioctl. ioctl_num: IOCTL_SET_SERIAL" );
  384.  
  385.                 kern_buf = bsp_SetSerial ( user_buf,
  386.                            &bRequestType,
  387.                            &bRequest,
  388.                            &wValue,
  389.                            &wIndex,
  390.                            &wLength );
  391.  
  392.                 break;
  393.         case IOCTL_SET_CURRENT_POSITION:
  394.                 info ( "usmc_ioctl. ioctl_num: IOCTL_SET_CURRENT_POSITION" );
  395.  
  396.                 bsp_SetCurrentPosition ( user_buf,
  397.                            &bRequestType,
  398.                            &bRequest,
  399.                            &wValue,
  400.                            &wIndex,
  401.                            &wLength );
  402.  
  403.                 break;
  404.         case IOCTL_STOP_STEP_MOTOR:
  405.                 info ( "usmc_ioctl. ioctl_num: IOCTL_STOP_STEP_MOTOR" );
  406.  
  407.                 bsp_StopStepMotor ( &bRequestType,
  408.                            &bRequest,
  409.                            &wValue,
  410.                            &wIndex,
  411.                            &wLength );
  412.  
  413.                 break;
  414.         case IOCTL_EMULATE_BUTTONS:
  415.                 info ( "usmc_ioctl. ioctl_num: IOCTL_EMULATE_BUTTONS" );
  416.  
  417.                 bsp_EmulateButtons (  user_buf,
  418.                            &bRequestType,
  419.                            &bRequest,
  420.                            &wValue,
  421.                            &wIndex,
  422.                            &wLength );
  423.  
  424.                 break;
  425.         case IOCTL_SAVE_PARAMETERS:
  426.                 info ( "usmc_ioctl. ioctl_num: IOCTL_SAVE_PARAMETERS" );
  427.  
  428.                 bsp_SaveParameters ( &bRequestType,
  429.                            &bRequest,
  430.                            &wValue,
  431.                            &wIndex,
  432.                            &wLength );
  433.  
  434.                 break;
  435.         case IOCTL_GET_NOD:
  436.                 info ( "usmc_ioctl. ioctl_num: IOCTL_GET_NOD" );
  437.                 dwRes = 1;
  438.                 kern_buf = user_to_kernel ( user_buf, 1 );
  439.                 kern_buf [0] = num_devices;
  440.  
  441.                 break;
  442.         default:
  443.                 err ( "usmc_ioctl. unknown ioctl_num: %d", ioctl_num );
  444.                 dwRes = -1;
  445.  
  446.                 break;
  447.         }
  448.  
  449.        
  450.         if ( dwRes == USMC_SUCCESS )
  451.         {
  452.                 if ( ( bRequestType & USB_DIR_IN ) != USB_DIR_IN )
  453.                 {
  454.                         kern_data_buf = wLength > 0 ? kern_buf + 4 : NULL;
  455.                         pipe0 = usb_sndctrlpipe ( dev -> udev, 0 );
  456.  
  457.                 } else {
  458.                         kern_buf = ( char * ) kzalloc ( ( ssize_t ) wLength, GFP_KERNEL );
  459.                         kern_data_buf = kern_buf;
  460.                         pipe0 = usb_rcvctrlpipe ( dev -> udev, 0 );
  461.                 }
  462.  
  463.                 dwRes = usb_control_msg ( dev -> udev,
  464.                                           pipe0,
  465.                                           bRequest,
  466.                                           bRequestType,
  467.                                           wValue,
  468.                                           wIndex,
  469.                                           kern_data_buf,
  470.                                           wLength,
  471.                                           dwTimeOut );
  472.  
  473.                 if ( ( bRequestType & USB_DIR_IN ) == USB_DIR_IN )
  474.                 {
  475.                         for ( i = 0 ; i < wLength ; i++ )
  476.                                 put_user ( kern_data_buf [i], user_buf + i );
  477.                 }
  478.         } else if ( dwRes > 0 ) {
  479.                 for ( i = 0 ; i < dwRes ; i++ )
  480.                         put_user ( kern_buf [i], user_buf + i );
  481.         }
  482.  
  483.  
  484.         kfree ( kern_buf );
  485.  
  486.         if ( dwRes < 0 ) {
  487.                 err ( "usmc_ioctl failed: dwRes: %d", (int) dwRes );
  488.         } else {
  489.                 info ( "transmitted %d bytes over control pipe0", (int) dwRes );
  490.         }
  491.  
  492.  
  493.         return  dwRes;
  494. }
  495.  
  496.  
  497. /*-----------------------------------------------------
  498.                 Util functions section
  499. -----------------------------------------------------*/
  500. static void usmc_delete ( struct kref * kref )
  501. {      
  502.         struct usb_usmc * dev = to_usmc_dev ( kref );
  503.  
  504.         usb_put_dev ( dev -> udev );
  505.         kfree ( dev );
  506. }
  507.