2011-01-24 20:45:30 +03:00
/*
* Linux driver for TerraTec DMX 6F ire USB
*
* Device communications
*
* Author : Torsten Schenk < torsten . schenk @ zoho . com >
* Created : Jan 01 , 2011
* Copyright : ( C ) Torsten Schenk
*
* 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 .
*/
# include "comm.h"
# include "chip.h"
# include "midi.h"
enum {
COMM_EP = 1 ,
COMM_FPGA_EP = 2
} ;
static void usb6fire_comm_init_urb ( struct comm_runtime * rt , struct urb * urb ,
u8 * buffer , void * context , void ( * handler ) ( struct urb * urb ) )
{
usb_init_urb ( urb ) ;
urb - > transfer_buffer = buffer ;
urb - > pipe = usb_sndintpipe ( rt - > chip - > dev , COMM_EP ) ;
urb - > complete = handler ;
urb - > context = context ;
urb - > interval = 1 ;
urb - > dev = rt - > chip - > dev ;
}
static void usb6fire_comm_receiver_handler ( struct urb * urb )
{
struct comm_runtime * rt = urb - > context ;
struct midi_runtime * midi_rt = rt - > chip - > midi ;
if ( ! urb - > status ) {
if ( rt - > receiver_buffer [ 0 ] = = 0x10 ) /* midi in event */
if ( midi_rt )
midi_rt - > in_received ( midi_rt ,
rt - > receiver_buffer + 2 ,
rt - > receiver_buffer [ 1 ] ) ;
}
if ( ! rt - > chip - > shutdown ) {
urb - > status = 0 ;
urb - > actual_length = 0 ;
if ( usb_submit_urb ( urb , GFP_ATOMIC ) < 0 )
2014-02-26 18:51:04 +04:00
dev_warn ( & urb - > dev - > dev ,
2011-01-24 20:45:30 +03:00
" comm data receiver aborted. \n " ) ;
}
}
static void usb6fire_comm_init_buffer ( u8 * buffer , u8 id , u8 request ,
u8 reg , u8 vl , u8 vh )
{
buffer [ 0 ] = 0x01 ;
buffer [ 2 ] = request ;
buffer [ 3 ] = id ;
switch ( request ) {
case 0x02 :
buffer [ 1 ] = 0x05 ; /* length (starting at buffer[2]) */
buffer [ 4 ] = reg ;
buffer [ 5 ] = vl ;
buffer [ 6 ] = vh ;
break ;
case 0x12 :
buffer [ 1 ] = 0x0b ; /* length (starting at buffer[2]) */
buffer [ 4 ] = 0x00 ;
buffer [ 5 ] = 0x18 ;
buffer [ 6 ] = 0x05 ;
buffer [ 7 ] = 0x00 ;
buffer [ 8 ] = 0x01 ;
buffer [ 9 ] = 0x00 ;
buffer [ 10 ] = 0x9e ;
buffer [ 11 ] = reg ;
buffer [ 12 ] = vl ;
break ;
case 0x20 :
case 0x21 :
case 0x22 :
buffer [ 1 ] = 0x04 ;
buffer [ 4 ] = reg ;
buffer [ 5 ] = vl ;
break ;
}
}
static int usb6fire_comm_send_buffer ( u8 * buffer , struct usb_device * dev )
{
int ret ;
int actual_len ;
ret = usb_interrupt_msg ( dev , usb_sndintpipe ( dev , COMM_EP ) ,
buffer , buffer [ 1 ] + 2 , & actual_len , HZ ) ;
if ( ret < 0 )
return ret ;
else if ( actual_len ! = buffer [ 1 ] + 2 )
return - EIO ;
return 0 ;
}
static int usb6fire_comm_write8 ( struct comm_runtime * rt , u8 request ,
u8 reg , u8 value )
{
2013-08-06 15:53:24 +04:00
u8 * buffer ;
int ret ;
/* 13: maximum length of message */
buffer = kmalloc ( 13 , GFP_KERNEL ) ;
if ( ! buffer )
return - ENOMEM ;
2011-01-24 20:45:30 +03:00
usb6fire_comm_init_buffer ( buffer , 0x00 , request , reg , value , 0x00 ) ;
2013-08-06 15:53:24 +04:00
ret = usb6fire_comm_send_buffer ( buffer , rt - > chip - > dev ) ;
kfree ( buffer ) ;
return ret ;
2011-01-24 20:45:30 +03:00
}
static int usb6fire_comm_write16 ( struct comm_runtime * rt , u8 request ,
u8 reg , u8 vl , u8 vh )
{
2013-08-06 15:53:24 +04:00
u8 * buffer ;
int ret ;
/* 13: maximum length of message */
buffer = kmalloc ( 13 , GFP_KERNEL ) ;
if ( ! buffer )
return - ENOMEM ;
2011-01-24 20:45:30 +03:00
usb6fire_comm_init_buffer ( buffer , 0x00 , request , reg , vl , vh ) ;
2013-08-06 15:53:24 +04:00
ret = usb6fire_comm_send_buffer ( buffer , rt - > chip - > dev ) ;
kfree ( buffer ) ;
return ret ;
2011-01-24 20:45:30 +03:00
}
2012-12-06 21:35:28 +04:00
int usb6fire_comm_init ( struct sfire_chip * chip )
2011-01-24 20:45:30 +03:00
{
struct comm_runtime * rt = kzalloc ( sizeof ( struct comm_runtime ) ,
GFP_KERNEL ) ;
2012-11-21 13:06:57 +04:00
struct urb * urb ;
2011-01-24 20:45:30 +03:00
int ret ;
if ( ! rt )
return - ENOMEM ;
2013-08-06 15:53:24 +04:00
rt - > receiver_buffer = kzalloc ( COMM_RECEIVER_BUFSIZE , GFP_KERNEL ) ;
if ( ! rt - > receiver_buffer ) {
kfree ( rt ) ;
return - ENOMEM ;
}
2012-11-21 13:06:57 +04:00
urb = & rt - > receiver ;
2011-01-24 20:45:30 +03:00
rt - > serial = 1 ;
rt - > chip = chip ;
usb_init_urb ( urb ) ;
rt - > init_urb = usb6fire_comm_init_urb ;
rt - > write8 = usb6fire_comm_write8 ;
rt - > write16 = usb6fire_comm_write16 ;
/* submit an urb that receives communication data from device */
urb - > transfer_buffer = rt - > receiver_buffer ;
urb - > transfer_buffer_length = COMM_RECEIVER_BUFSIZE ;
urb - > pipe = usb_rcvintpipe ( chip - > dev , COMM_EP ) ;
urb - > dev = chip - > dev ;
urb - > complete = usb6fire_comm_receiver_handler ;
urb - > context = rt ;
urb - > interval = 1 ;
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret < 0 ) {
2013-08-06 15:53:24 +04:00
kfree ( rt - > receiver_buffer ) ;
2011-01-24 20:45:30 +03:00
kfree ( rt ) ;
2014-02-26 18:51:04 +04:00
dev_err ( & chip - > dev - > dev , " cannot create comm data receiver. " ) ;
2011-01-24 20:45:30 +03:00
return ret ;
}
chip - > comm = rt ;
return 0 ;
}
void usb6fire_comm_abort ( struct sfire_chip * chip )
{
struct comm_runtime * rt = chip - > comm ;
if ( rt )
usb_poison_urb ( & rt - > receiver ) ;
}
void usb6fire_comm_destroy ( struct sfire_chip * chip )
{
2013-08-06 15:53:24 +04:00
struct comm_runtime * rt = chip - > comm ;
kfree ( rt - > receiver_buffer ) ;
kfree ( rt ) ;
2011-01-24 20:45:30 +03:00
chip - > comm = NULL ;
}