2005-07-29 01:49:01 +04:00
/*
* Support for the Maxtor OneTouch USB hard drive ' s button
*
* Current development and maintenance by :
* Copyright ( c ) 2005 Nick Sillik < n . sillik @ temple . edu >
*
* Initial work by :
2005-09-15 11:01:43 +04:00
* Copyright ( c ) 2003 Erik Thyren < erth7411 @ student . uu . se >
2005-07-29 01:49:01 +04:00
*
* Based on usbmouse . c ( Vojtech Pavlik ) and xpad . c ( Marko Friedemann )
*
*/
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/kernel.h>
# include <linux/input.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/module.h>
2005-08-17 21:37:34 +04:00
# include <linux/usb_ch9.h>
2006-06-13 21:04:34 +04:00
# include <linux/usb/input.h>
2005-07-29 01:49:01 +04:00
# include "usb.h"
# include "onetouch.h"
# include "debug.h"
void onetouch_release_input ( void * onetouch_ ) ;
struct usb_onetouch {
char name [ 128 ] ;
char phys [ 64 ] ;
2005-09-15 11:01:43 +04:00
struct input_dev * dev ; /* input device interface */
2005-07-29 01:49:01 +04:00
struct usb_device * udev ; /* usb device */
struct urb * irq ; /* urb for interrupt in report */
unsigned char * data ; /* input data */
dma_addr_t data_dma ;
2005-12-05 08:56:51 +03:00
unsigned int is_open : 1 ;
2005-07-29 01:49:01 +04:00
} ;
static void usb_onetouch_irq ( struct urb * urb , struct pt_regs * regs )
{
struct usb_onetouch * onetouch = urb - > context ;
signed char * data = onetouch - > data ;
2005-09-15 11:01:43 +04:00
struct input_dev * dev = onetouch - > dev ;
2005-07-29 01:49:01 +04:00
int status ;
switch ( urb - > status ) {
case 0 : /* success */
break ;
case - ECONNRESET : /* unlink */
case - ENOENT :
case - ESHUTDOWN :
return ;
/* -EPIPE: should clear the halt */
default : /* error */
goto resubmit ;
}
input_regs ( dev , regs ) ;
2005-09-15 11:01:43 +04:00
input_report_key ( dev , ONETOUCH_BUTTON , data [ 0 ] & 0x02 ) ;
2005-07-29 01:49:01 +04:00
input_sync ( dev ) ;
2005-09-15 11:01:43 +04:00
2005-07-29 01:49:01 +04:00
resubmit :
status = usb_submit_urb ( urb , SLAB_ATOMIC ) ;
if ( status )
err ( " can't resubmit intr, %s-%s/input0, status %d " ,
onetouch - > udev - > bus - > bus_name ,
onetouch - > udev - > devpath , status ) ;
}
static int usb_onetouch_open ( struct input_dev * dev )
{
struct usb_onetouch * onetouch = dev - > private ;
2005-12-05 08:56:51 +03:00
onetouch - > is_open = 1 ;
2005-07-29 01:49:01 +04:00
onetouch - > irq - > dev = onetouch - > udev ;
if ( usb_submit_urb ( onetouch - > irq , GFP_KERNEL ) ) {
err ( " usb_submit_urb failed " ) ;
return - EIO ;
}
return 0 ;
}
static void usb_onetouch_close ( struct input_dev * dev )
{
struct usb_onetouch * onetouch = dev - > private ;
usb_kill_urb ( onetouch - > irq ) ;
2005-12-05 08:56:51 +03:00
onetouch - > is_open = 0 ;
2005-07-29 01:49:01 +04:00
}
2005-12-05 08:56:51 +03:00
# ifdef CONFIG_PM
static void usb_onetouch_pm_hook ( struct us_data * us , int action )
{
struct usb_onetouch * onetouch = ( struct usb_onetouch * ) us - > extra ;
if ( onetouch - > is_open ) {
switch ( action ) {
case US_SUSPEND :
usb_kill_urb ( onetouch - > irq ) ;
break ;
case US_RESUME :
if ( usb_submit_urb ( onetouch - > irq , GFP_KERNEL ) ! = 0 )
err ( " usb_submit_urb failed " ) ;
break ;
default :
break ;
}
}
}
# endif /* CONFIG_PM */
2005-07-29 01:49:01 +04:00
int onetouch_connect_input ( struct us_data * ss )
{
struct usb_device * udev = ss - > pusb_dev ;
struct usb_host_interface * interface ;
struct usb_endpoint_descriptor * endpoint ;
struct usb_onetouch * onetouch ;
2005-09-15 11:01:43 +04:00
struct input_dev * input_dev ;
2005-07-29 01:49:01 +04:00
int pipe , maxp ;
interface = ss - > pusb_intf - > cur_altsetting ;
2005-08-17 21:37:34 +04:00
if ( interface - > desc . bNumEndpoints ! = 3 )
return - ENODEV ;
2005-07-29 01:49:01 +04:00
endpoint = & interface - > endpoint [ 2 ] . desc ;
2005-09-15 11:01:43 +04:00
if ( ! ( endpoint - > bEndpointAddress & USB_DIR_IN ) )
2005-07-29 01:49:01 +04:00
return - ENODEV ;
2005-09-15 11:01:43 +04:00
if ( ( endpoint - > bmAttributes & USB_ENDPOINT_XFERTYPE_MASK )
2005-08-17 21:37:34 +04:00
! = USB_ENDPOINT_XFER_INT )
2005-07-29 01:49:01 +04:00
return - ENODEV ;
pipe = usb_rcvintpipe ( udev , endpoint - > bEndpointAddress ) ;
maxp = usb_maxpacket ( udev , pipe , usb_pipeout ( pipe ) ) ;
2005-09-15 11:01:43 +04:00
onetouch = kzalloc ( sizeof ( struct usb_onetouch ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! onetouch | | ! input_dev )
goto fail1 ;
2005-07-29 01:49:01 +04:00
2005-08-17 21:37:34 +04:00
onetouch - > data = usb_buffer_alloc ( udev , ONETOUCH_PKT_LEN ,
SLAB_ATOMIC , & onetouch - > data_dma ) ;
2005-09-15 11:01:43 +04:00
if ( ! onetouch - > data )
goto fail1 ;
2005-07-29 01:49:01 +04:00
onetouch - > irq = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2005-09-15 11:01:43 +04:00
if ( ! onetouch - > irq )
goto fail2 ;
2005-07-29 01:49:01 +04:00
onetouch - > udev = udev ;
2005-09-15 11:01:43 +04:00
onetouch - > dev = input_dev ;
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
if ( udev - > manufacturer )
strlcpy ( onetouch - > name , udev - > manufacturer ,
sizeof ( onetouch - > name ) ) ;
if ( udev - > product ) {
if ( udev - > manufacturer )
strlcat ( onetouch - > name , " " , sizeof ( onetouch - > name ) ) ;
strlcat ( onetouch - > name , udev - > product , sizeof ( onetouch - > name ) ) ;
}
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
if ( ! strlen ( onetouch - > name ) )
snprintf ( onetouch - > name , sizeof ( onetouch - > name ) ,
" Maxtor Onetouch %04x:%04x " ,
le16_to_cpu ( udev - > descriptor . idVendor ) ,
le16_to_cpu ( udev - > descriptor . idProduct ) ) ;
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
usb_make_path ( udev , onetouch - > phys , sizeof ( onetouch - > phys ) ) ;
strlcat ( onetouch - > phys , " /input0 " , sizeof ( onetouch - > phys ) ) ;
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
input_dev - > name = onetouch - > name ;
input_dev - > phys = onetouch - > phys ;
usb_to_input_id ( udev , & input_dev - > id ) ;
input_dev - > cdev . dev = & udev - > dev ;
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
set_bit ( EV_KEY , input_dev - > evbit ) ;
set_bit ( ONETOUCH_BUTTON , input_dev - > keybit ) ;
clear_bit ( 0 , input_dev - > keybit ) ;
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
input_dev - > private = onetouch ;
input_dev - > open = usb_onetouch_open ;
input_dev - > close = usb_onetouch_close ;
2005-07-29 01:49:01 +04:00
usb_fill_int_urb ( onetouch - > irq , udev , pipe , onetouch - > data ,
( maxp > 8 ? 8 : maxp ) ,
usb_onetouch_irq , onetouch , endpoint - > bInterval ) ;
onetouch - > irq - > transfer_dma = onetouch - > data_dma ;
onetouch - > irq - > transfer_flags | = URB_NO_TRANSFER_DMA_MAP ;
ss - > extra_destructor = onetouch_release_input ;
ss - > extra = onetouch ;
2005-12-05 08:56:51 +03:00
# ifdef CONFIG_PM
ss - > suspend_resume_hook = usb_onetouch_pm_hook ;
# endif
2005-07-29 01:49:01 +04:00
2005-09-15 11:01:43 +04:00
input_register_device ( onetouch - > dev ) ;
2005-07-29 01:49:01 +04:00
return 0 ;
2005-09-15 11:01:43 +04:00
fail2 : usb_buffer_free ( udev , ONETOUCH_PKT_LEN ,
onetouch - > data , onetouch - > data_dma ) ;
fail1 : kfree ( onetouch ) ;
input_free_device ( input_dev ) ;
return - ENOMEM ;
2005-07-29 01:49:01 +04:00
}
void onetouch_release_input ( void * onetouch_ )
{
struct usb_onetouch * onetouch = ( struct usb_onetouch * ) onetouch_ ;
if ( onetouch ) {
usb_kill_urb ( onetouch - > irq ) ;
2005-09-15 11:01:43 +04:00
input_unregister_device ( onetouch - > dev ) ;
2005-07-29 01:49:01 +04:00
usb_free_urb ( onetouch - > irq ) ;
usb_buffer_free ( onetouch - > udev , ONETOUCH_PKT_LEN ,
onetouch - > data , onetouch - > data_dma ) ;
}
}