rendered paste body--- 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 <martin_a_blatter@yahoo.com>
*
+ * Transmitter support
+ * (C) by Daniel Melander <lirc@rajidae.se>
+ *
* 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 <martin_a_blatter@yahoo.com>"
+#define DRIVER_VERSION "0.23"
+#define DRIVER_AUTHOR "Martin Blatter <martin_a_blatter@yahoo.com>, Daniel Melander <lirc@rajidae.se>"
#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<count) && (i+1 < CMDBUF_LEN);i++) {
+ wbuf[i]=wbuf[i]/MCE_TX_RESOLUTION;
+
+ do { //Support long pulses > 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_PULSE_MASK?wbuf[i]:MCE_MAX_PULSE_LENGTH) | (i%2?0x00:MCE_PULSE_MASK);
+
+ } while ((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;
}