--- lirc_mceusb2.c.org 2006-08-12 16:47:34.000000000 +0200 +++ lirc_mceusb2.c 2006-08-19 02:57:18.000000000 +0200 @@ -4,6 +4,9 @@ * * (C) by Martin A. Blatter * + * Transmitter support + * (C) by Daniel Melander + * * Derived from ATI USB driver by Paul Miller and the original * MCE USB driver by Dan Corti * @@ -56,8 +59,8 @@ #include "drivers/kcompat.h" #include "drivers/lirc_dev/lirc_dev.h" -#define DRIVER_VERSION "0.22" -#define DRIVER_AUTHOR "Martin Blatter " +#define DRIVER_VERSION "0.23" +#define DRIVER_AUTHOR "Martin Blatter , Daniel Melander " #define DRIVER_DESC "USB remote driver for LIRC" #define DRIVER_NAME "lirc_mceusb2" @@ -67,7 +70,7 @@ #define MCE_CODE_LENGTH 5 #define MCE_TIME_UNIT 50 #define MCE_PACKET_SIZE 4 -#define MCE_PACKET_HEADER 0x84 +#define MCE_PACKET_HEADER 0x84 //Actual format is 0x80+num_bytes /* module parameters */ #ifdef CONFIG_USB_DEBUG @@ -411,6 +414,130 @@ usb_submit_urb(urb, SLAB_ATOMIC); } + +////////////////////////////////////////////////// +///////////////////SEND SUPPORT/////////////////// +////////////////////////////////////////////////// + +#define CMDBUF_LEN 256 //MCE Command buffer length +#define WBUF_LEN 256 //Work buffer length +#define MCE_PULSE_MASK 0x80 //Pulse mask, MSB set == PULSE else SPACE +#define MCE_TX_RESOLUTION 50 //Approx 50us resolution, could use MCE_TIME_UNIT +#define MCE_MAX_CHANNELS 2 //Only 2 transmitters, hardware dependent? +#define MCE_MAX_PULSE_LENGTH 0x7F //Longest transmittable pulse symbol + +static unsigned int active_transmitters=0x06; //Supported values are TX1=0x2, TX2=0x4, ALL=0x6 +static lirc_t wbuf[WBUF_LEN]; //Workbuffer with values from lirc +static unsigned char cmdbuf[CMDBUF_LEN]; //MCE Command buffer + +struct irctl *usb_ir=NULL; +struct usb_endpoint_descriptor *usb_ep_out=NULL; + + +static ssize_t lirc_write(struct file *file, const char *buf, size_t n, loff_t * ppos) +{ + int i, count=0, cmdcount=0; + + if(n%sizeof(lirc_t)) return(-EINVAL); + count=n/sizeof(lirc_t); + + //Check if command is within limits + if(count>WBUF_LEN || count%2==0) return(-EINVAL); + if(copy_from_user(wbuf,buf,n)) return -EFAULT; + + //MCE tx header + cmdbuf[cmdcount++]=0x9F; + cmdbuf[cmdcount++]=0x08; + cmdbuf[cmdcount++]=active_transmitters; + + //Generate mce packet data + for(i=0;(i 127*50us=6.35ms + + //Insert mce packet header every 4th packet + if ((cmdcount+2)%MCE_CODE_LENGTH==0) { + cmdbuf[cmdcount++]=0x80+((count-i>=MCE_PACKET_SIZE)?MCE_PACKET_SIZE:count-i); + } + + //Insert mce packet data + cmdbuf[cmdcount++]=(wbuf[i] MCE_MAX_PULSE_LENGTH) && (wbuf[i]-=MCE_MAX_PULSE_LENGTH)); + } + + if (cmdcount>CMDBUF_LEN) return(-EINVAL); + + //Always end with an empty packet (0x80) + cmdbuf[cmdcount++]=0x80; + + //Transmit packet to mce device + request_packet_async( usb_ir, usb_ep_out, cmdbuf, cmdcount, PHILUSB_OUTBOUND ); + + return(n); +} + + +static int lirc_ioctl(struct inode *node,struct file *filep,unsigned int cmd, unsigned long arg) +{ + int result; + unsigned int ivalue; + unsigned long lvalue; + + switch(cmd) { + + case LIRC_SET_TRANSMITTER_MASK: + + result=get_user(ivalue,(unsigned int *) arg); + if(result) return(result); + + switch(ivalue) { + case 0x01: //Transmitter 2 + case 0x02: //Transmitter 1 + case 0x03: //Transmitter 1 and 2 + active_transmitters = (ivalue!=0x03?ivalue ^ 0x03:ivalue) << 1; //Yhe mask begins at 0x02 and has an inverted numbering scheme + break; + + default: //If unsupported transmitter mask + return MCE_MAX_CHANNELS; + } + + printk(DRIVER_NAME ":SET_TRANSMITTERS mask=%d\n", ivalue); + return (0); + break; + + case LIRC_GET_SEND_MODE: + + result=put_user(LIRC_SEND2MODE (LIRC_CAN_SEND_PULSE&LIRC_CAN_SEND_MASK), (unsigned long *) arg); + + if(result) return(result); + break; + + case LIRC_SET_SEND_MODE: + + result=get_user(lvalue,(unsigned long *) arg); + + if(result) return(result); + if(lvalue!=(LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) return(-EINVAL); + break; + + default: + return(-ENOIOCTLCMD); + } + + return(0); +} + +static struct file_operations lirc_fops = +{ + write: lirc_write, +}; + +////////////////////////////////////////////////// +///////////////////SEND SUPPORT/////////////////// +////////////////////////////////////////////////// + static int usb_remote_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -493,13 +620,16 @@ strcpy(plugin->name, DRIVER_NAME " "); plugin->minor = -1; - plugin->features = LIRC_CAN_REC_MODE2; + plugin->features = LIRC_CAN_SEND_PULSE | + LIRC_CAN_SET_TRANSMITTER_MASK | + LIRC_CAN_REC_MODE2; plugin->data = ir; plugin->rbuf = rbuf; plugin->set_use_inc = &set_use_inc; plugin->set_use_dec = &set_use_dec; plugin->code_length = sizeof(lirc_t) * 8; - plugin->ioctl = NULL; + plugin->ioctl = lirc_ioctl; + plugin->fops = &lirc_fops; plugin->owner = THIS_MODULE; init_MUTEX(&ir->lock); @@ -561,6 +691,11 @@ request_packet_async( ir, ep_in, NULL, maxp, 0); usb_set_intfdata(intf, ir); + + //Saving usb interface data for use by the transmitter routine + usb_ir=ir; + usb_ep_out=ep_out; + return SUCCESS; }