pirblaster  0.01
Use the pi as a remote control for your TV, DVD player etc.
MyIrMod.c
Go to the documentation of this file.
1 /********************************************************************************/
2 /* Use a raspberry pi with a IR led as remote control for your Tv, Dvd etc. */
3 /* Copyright (C) 2016 Ed Kapitein */
4 /* */
5 /* This program is free software: you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation, either version 3 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /********************************************************************************/
18 /*
19  * \brief Create a device to send IR commands.
20  *
21  * Create an input/output character device to send IR commands to a TV, setopbox etc
22  * Thanks to all the people who share code and explain how to do things.
23  * I could not have done it without them
24  * Most is taken from: http://www.tldp.org/LDP/lkmpg/2.6/html/x892.html
25  */
26 
27 #include <linux/kernel.h> /* We're doing kernel work */
28 #include <linux/module.h> /* Specifically, a module */
29 #include <linux/device.h> /* and we create a device */
30 #include <linux/fs.h>
31 #include <asm/uaccess.h> /* for get_user and put_user */
32 #include "../Kmod/Kmod.h"
33 #include <linux/gpio.h>
34 #include <linux/delay.h>
35 
36 MODULE_LICENSE("GPL");
37 MODULE_AUTHOR("Ed Kapitein");
38 
39 static short int gpionr = 14;
40 module_param(gpionr, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
41 MODULE_PARM_DESC(gpionr, "gpio number used for modulating the carrier");
42 
48 static short int invert = 1;
49 module_param(invert, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
50 MODULE_PARM_DESC(invert, "invert value (gpio=low means CarrierOn ), default=1");
51 
52 static short int debug = 0;
53 module_param(debug, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
54 MODULE_PARM_DESC(debug, "debug level");
55 
56 char *label = "MyLabel";
57 unsigned long flags;
58 static struct class* MyIrClass = NULL; /*/< The device-driver class struct pointer */
59 static struct device* MyIrDevice = NULL; /*/< The device-driver device struct pointer */
60 static int majorNumber; /*/< Stores the device number - determined automatically */
61 static int Device_Open = 0;
62 static char Message[BUF_LEN];
69 int IoctlRange( int Range )
70  {
71  volatile uint32_t *GpioBase;
72  volatile uint32_t *Pwm;
73  uint32_t Mask;
74 
75  /* initialize a pointer to the gpio registers */
76  if( ( GpioBase = ioremap( IO_BASE + GPIO_CONTROL, SZ_4K ) ) == NULL )
77  {
78  printk(KERN_ALERT "201608202038 mapping GpioBase failed.\n");
79  return(-1);
80  }
81 
82  /***************************************************************************************************************************************/
83  /* This whole section could be written as: */
84  /* #define INP_GPIO(g) *(GpioBase + ( (g)/10) ) &= ~(7<<(((g)%10)*3)) */
85  /* #define SET_GPIO_ALT(g,a) *(GpioBase + (((g)/10))) |= (((a)<=3?(a) + 4:(a)==4?3:2)<<(((g)%10)*3)) */
86  /* INP_GPIO(PwmPin); */
87  /* SET_GPIO_ALT(PwmPin,5); */
88  /* But i can't seem to get my head around it... */
89  /* the gpio pins are controlled by 32 bit registers for their Alt functions */
90  /* the Alt functions have 3 bits, and there are 10 gpio per register. */
91  /* So setting gpio pin 18 is done by selecting register 1 (=18/10), ( register 0 holds gpio 0-9 ), */
92  /* and shift the disired 3 bit Alt function pattern 8 times to the left. ( (PwmPin-(10*(PwmPin/10))*3) = (18-10)*3 = 24 ) */
93  /* That will put it at bit 24-26. */
94  /* To only affected the bits we want and to leave the other bits as they are, we use OR and AND functions */
95  /* Alt function 5 has bit battern 010, so you need to select bit patern 101 (=0x005), shift it and invert it so it becomes 010 */
96  /***************************************************************************************************************************************/
97  Mask = 0x0007 << ( ( PwmPin - 10 * (PwmPin/10) ) * 3 ); /* set all AltReg bits to 1 and shift them into place */
98  Mask = ~Mask; /* invert the mask so all AltReg bits are 0 */
99 
100  *( GpioBase + PwmPin/10 ) = *(GpioBase + PwmPin/10 ) & Mask; /* AND the mask, so only the AltReg are set to 0 */
101  Mask = ~Mask; /* invert the mask so all AltReg bits are 1 */
102  *( GpioBase + PwmPin/10 ) = *(GpioBase + PwmPin/10 ) | Mask; /* OR the mask, so only the AltReg bits are set to 1 */
103 
104  Mask = 0x0005 << ( ( PwmPin - 10 * (PwmPin/10) ) * 3 ); /* select the AltReg bits that need to become 0 (010) and shift them */
105  Mask = ~Mask; /* invert the mask so all bits are 1 except the selected AltReg bits */
106  *(GpioBase + PwmPin/10) = *(GpioBase + PwmPin/10) & Mask; /* AND the mask, so only the selected AltReg are set to 0 */
107 
108  udelay(110);
109 
110  /* initialize a pointer to the pwm registers */
111  if( ( Pwm = ioremap( IO_BASE + GPIO_CONTROL + GPIO_PWM, SZ_4K ) ) == NULL )
112  {
113  printk(KERN_ALERT "201608202039 mapping Pwm failed.\n");
114  return(-1);
115  }
116 
117  /* set Pwm to balanced mode. */
119 
120  /* set the range for the Pwm channel. */
121  *(Pwm + PWM0_RANGE) = Range ;
122 
123  udelay(10);
124 
125  if( debug > 0 )
126  {
127  printk( KERN_INFO "201608202219 Range is: %i\n", Range );
128  }
129 
130  return(0);
131 
132  }
133 
139 int IoctlDivisor( int Divisor )
140  {
141  long PwmControl;
142  volatile uint32_t *Pwm;
143  volatile uint32_t *Clk;
144 
145  /* initialize a pointer to the pwm registers */
146  if( ( Pwm = ioremap( IO_BASE + GPIO_CONTROL + GPIO_PWM, SZ_4K ) ) == NULL )
147  {
148  printk(KERN_ALERT "201608202039 mapping Pwm failed.\n");
149  return(-1);
150  }
151 
152  if( ( Clk = ioremap( IO_BASE + GPIO_CLK, SZ_4K ) ) == NULL )
153  {
154  printk(KERN_ALERT "201608202040 mapping Clk failed.\n");
155  return(-1);
156  }
157 
158  /* set clock */
159  Divisor &= 4095 ;
160  PwmControl = *(Pwm + PWM_CONTROL) ; /* preserve PWM_CONTROL */
161  *(Pwm + PWM_CONTROL) = 0 ; /* Stop PWM */
162  *(Clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; /* Stop PWM Clock */
163 
164  udelay(110); /* 110 uS prevents clock going sloooow */
165 
166  while ((*(Clk + PWMCLK_CNTL) & 0x80) != 0) /* Wait for clock to be !BUSY */
167  {
168  udelay(1);
169  }
170 
171  *(Clk + PWMCLK_DIV) = BCM_PASSWORD | (Divisor << 12) ; /* Set the Divisor */
172 
173  *(Clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11; /* Start PWM clock */
174  *(Pwm + PWM_CONTROL) = PwmControl; /* restore PWM_CONTROL */
175 
176  if( debug > 0 )
177  {
178  printk( KERN_INFO "201608202220 Divisor is: %i\n", Divisor );
179  }
180 
181  return(0);
182 
183  }
184 
188 int IoctlDuty( int DutyCycle )
189  {
190  static volatile uint32_t *Pwm;
191  volatile uint16_t Range;
192 
193  /* initialize a pointer to the Pwm registers */
194  if( ( Pwm = ioremap( IO_BASE + GPIO_CONTROL + GPIO_PWM, SZ_4K) ) == NULL )
195  {
196  printk( KERN_ALERT "201608201747 mapping Pwm failed\n" );
197  return(-1);
198  }
199 
200  /* read the Range for the pwm channel. */
201  if( ( Range = *( Pwm + PWM0_RANGE ) ) < 1 )
202  {
203  printk( KERN_ALERT "201608201747 readin Range failed\n" );
204  return(-1);
205  }
206 
207  if( debug > 0 )
208  {
209  printk( KERN_INFO "201608201830 Range is: %i\n", Range );
210  }
211 
212  *( Pwm + PWM0_DATA ) = Range * DutyCycle / 100; /* Set the dutycycle */
213 
214  return(0);
215  }
216 
220 static int device_open(struct inode *inode, struct file *file)
221  {
222  if( debug > 0 )
223  {
224  printk(KERN_INFO "device_open(%p)\n", file);
225  }
226 
227  /* We don't want to talk to two processes at the same time */
228  if(Device_Open)
229  {
230  return -EBUSY;
231  }
232 
233  Device_Open++;
234  try_module_get(THIS_MODULE);
235  return 0;
236  }
237 
241 static int device_release(struct inode *inode, struct file *file)
242  {
243  if( debug > 0 )
244  {
245  printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
246  }
247 
248  /* We're now ready for our next caller */
249  Device_Open--;
250 
251  module_put(THIS_MODULE);
252  return 0;
253  }
254 
261 static ssize_t device_read(struct file *file, char __user * buffer, size_t length, loff_t * offset)
262  {
263  printk(KERN_ALERT "201608131202 Sorry, this operation isn't supported.\n");
264  return -EINVAL;
265  }
266 
276 static ssize_t device_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset)
277  {
278  int i;
279  int n;
280  int NrOfStates=0; /* use a counter for the state and duration elements */
281  static char TempBuf[BUF_LEN]; /* a buffers to store the values before computation */
282  volatile static uint64_t *Timer;
283  uint64_t Prev;
284  static long int State[BUF_LEN]; /* State is 0 or 1 */
285  static long int Duration[BUF_LEN]; /* Duration in usecs */
286  int BytesRead;
287 
288  if( debug > 0 )
289  {
290  printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length);
291  }
292 
293  /* set a pointer to the 1MHz clock we use for time stamps */
294  if( ( Timer = ioremap( IO_BASE + TIMER_CONTROL + ONE_MHZ_COUNTER, SZ_4K) ) == NULL )
295  {
296  printk(KERN_ALERT "201608111618 ioremap() failed.\n");
297  return -1;
298  }
299 
300  /* request our gpionr */
301  if( ( gpio_request(gpionr, label) ) != 0 )
302  {
303  printk(KERN_ALERT "201608112230 gpio_request failed\n");
304  return(-1);
305  }
306 
307  /* set it to output */
308  if( ( gpio_direction_output(gpionr,1) ) != 0 )
309  {
310  printk(KERN_ALERT "201608112231 gpio_direction_output failed\n");
311  return(-1);
312  }
313 
314  /* read the user data and store it in a Message buffer */
315  for (i = 0; i < length && i < BUF_LEN; i++)
316  {
317  get_user(Message[i], buffer + i);
318  }
319  BytesRead=i;
320 
321  /* split the comma seperated values in the Message buffer into Element buffers, one value per element */
322  NrOfStates=0;
323  for (i = 0; i < length && i < BUF_LEN; i++)
324  {
325  /* Read first element (State) and save it in its array */
326  n=0;
327  while( Message[i] != ',' && i < length && i < BUF_LEN ) /* state and duration are comma seperated */
328  {
329  TempBuf[n]=Message[i];
330  i++;
331  n++;
332  }
333  TempBuf[n]=0; /* NULL terminate the string */
334 
335  if( ( kstrtol( TempBuf, 10, &State[NrOfStates] ) ) != 0 ) /* and convert it to a long integer */
336  {
337  printk(KERN_ALERT "201608151349 kstrtol failed\n" );
338  }
339 
340  if( State[NrOfStates] < 0 || State[NrOfStates] > 1 )
341  {
342  if( State[NrOfStates] != -1 ) /* -1 means end of frame */
343  {
344  printk(KERN_ALERT "201608151309 State is not 1 or 0 or -1 (End of Frame)\n" );
345  }
346  }
347 
348  /* Read second element (Duration) and save it in its array */
349  i++;
350  n=0;
351  while( Message[i] != ',' && i < length && i < BUF_LEN ) /* state and duration are comma seperated */
352  {
353  TempBuf[n]=Message[i];
354  i++;
355  n++;
356  }
357  TempBuf[n]=0; /* NULL terminate the string */
358 
359  if( ( kstrtol( TempBuf, 10, &Duration[NrOfStates] ) ) != 0 ) /* and convert it to a long integer */
360  {
361  printk(KERN_ALERT "20160808122108 kstrtol failed\n" );
362  }
363 
364  if( Duration[NrOfStates] < 0 || Duration[NrOfStates] > MaxFrameTime )
365  {
366  if( Duration[NrOfStates] != -1 ) /* -1 means end of frame */
367  {
368  printk(KERN_ALERT "201608151352 Duration is too small or to big\n" );
369  }
370  }
371 
372  NrOfStates++;
373  }
374 
375  /* pulse the gpio pin acording to the info in the frame */
376 
381  /* switch the pin off to have a known state */
382  /* the XOR inverts the 0x00 if invert is set to 1 */
383  /* the AND ignores the other bits */
384  gpio_set_value(gpionr, ( 0x00 ^ invert ) & 0x01 );
385 
386  /* This code runs with interrupts disabled */
387  local_irq_save(flags);
388 
389  for( n=0; n< NrOfStates; n++ )
390  {
391  /* check if this is the last element of the frame (,-1,-1) */
392  if( State[n] == -1 )
393  {
394  local_irq_restore(flags);
395  gpio_free(gpionr);
396  return(BytesRead);
397  }
398 
399  if( debug > 0 )
400  {
401  printk(KERN_INFO "State In Loop: %i = %li\n", n, State[n]);
402  printk(KERN_INFO "Duration In Loop: %i = %li\n", n, Duration[n]);
403  }
404 
405  gpio_set_value(gpionr, ( State[n] ^ invert ) & 0x01 );
406 
407  if( Duration[n] > 2000 ) /* keeping interrupts off for to long seems to fail */
408  {
409  Prev = *Timer; /* save the hardware timer */
410  local_irq_restore(flags); /* restore interrupts */
411 
412  while( *Timer - Prev < Duration[n] ) /* run a loose loop, it works better than msleep/mdelay */
413  {
414  udelay(100);
415  }
416 
417  if( debug > 0 )
418  {
419  printk(KERN_INFO "Slept in loop: %llu\n", *Timer - Prev);
420  }
421 
422  local_irq_save(flags);
423  }
424  else
425  {
426  Prev = *Timer; /* save the hardware timer */
427  udelay(Duration[n]);
428 
429  if( debug > 0 )
430  {
431  printk(KERN_INFO "uSlept in loop: %llu\n", *Timer - Prev);
432  }
433 
434  }
435 
436  }
437 
438  /* we should never reach this, as the frame should end with -1,-1 and that is checked earlier */
439  /* but just in case a frame is uncorectly terminated ... */
440  local_irq_restore(flags);
441  mdelay(10);
442  gpio_free(gpionr);
443  return(BytesRead);
444 
445  }
446 
450 static long device_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
451  {
452  switch(cmd) {
453  case IOCTL_RANGE:
454  IoctlRange( arg );
455  break;
456 
457  case IOCTL_DIVISOR:
458  IoctlDivisor( arg );
459  break;
460 
461  case IOCTL_DUTY:
462  IoctlDuty( arg );
463  break;
464 
465  default:
466  printk(KERN_ALERT "201608151725 Sorry, this operation isn't supported.\n");
467  return -EINVAL;
468  }
469 
470  return 0;
471  }
472 
473 /* Module Declarations */
474 
482 struct file_operations Fops = {
483  .read = device_read,
484  .write = device_write,
485  .open = device_open,
486  .unlocked_ioctl = device_ioctl,
487  .release = device_release, /* a.k.a. close */
488 };
489 
496  {
497  if( debug > 0 )
498  {
499  printk(KERN_INFO "Using Gpio %hd", gpionr);
500  }
501 
502  /* Try to dynamically allocate a major number for the device -- more difficult but worth it */
503  majorNumber = register_chrdev(0, DEVICE_NAME, &Fops);
504  if (majorNumber<0)
505  {
506  printk(KERN_ALERT "MyIrMod failed to register a major number\n");
507  return majorNumber;
508  }
509  printk(KERN_INFO "MyIrMod: registered correctly with major number %d\n", majorNumber);
510 
511  /* Register the device class */
512  MyIrClass = class_create(THIS_MODULE, CLASS_NAME);
513 
514  /* Check for error and clean up if there is */
515  if(IS_ERR(MyIrClass))
516  {
517  unregister_chrdev(majorNumber, DEVICE_NAME);
518  printk(KERN_ALERT "Failed to register device class\n");
519  return PTR_ERR(MyIrClass); /* Correct way to return an error on a pointer */
520  }
521  printk(KERN_INFO "MyIrMod: device class registered correctly\n");
522 
523  /* Register the device driver */
524  MyIrDevice = device_create(MyIrClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
525 
526  /* Clean up if there is an error */
527  if (IS_ERR(MyIrDevice))
528  {
529  class_destroy(MyIrClass); /* Repeated code but the alternative is goto statements */
530  unregister_chrdev(majorNumber, DEVICE_NAME);
531  printk(KERN_ALERT "Failed to create the device\n");
532  return PTR_ERR(MyIrDevice);
533  }
534  printk(KERN_INFO "MyIrMod: device class created correctly\n");
535 
536  return 0;
537  }
538 
545  {
546  /*Unregister the device */
547  device_destroy(MyIrClass, MKDEV(majorNumber, 0)); /* remove the device */
548  class_unregister(MyIrClass); /* unregister the device class */
549  class_destroy(MyIrClass); /* remove the device class */
550  unregister_chrdev(majorNumber, DEVICE_NAME); /* unregister the major number */
551  }
static short int debug
Definition: MyIrMod.c:52
int IoctlDivisor(int Divisor)
routine called when IOCTL_DIVISOR is called
Definition: MyIrMod.c:139
int init_module()
Initialize the module.
Definition: MyIrMod.c:495
#define TIMER_CONTROL
Definition: Kmod.h:14
#define PWMCLK_CNTL
Definition: Kmod.h:18
MODULE_PARM_DESC(gpionr,"gpio number used for modulating the carrier")
MODULE_LICENSE("GPL")
#define IOCTL_DUTY
Definition: Kmod.h:42
#define DEVICE_NAME
Definition: Kmod.h:31
static struct class * MyIrClass
Definition: MyIrMod.c:58
struct file_operations Fops
Definition: MyIrMod.c:482
static int majorNumber
Definition: MyIrMod.c:60
#define ONE_MHZ_COUNTER
Definition: Kmod.h:25
static int Device_Open
Definition: MyIrMod.c:61
#define MaxFrameTime
Definition: Kmod.h:28
#define IOCTL_RANGE
Definition: Kmod.h:40
#define PWM0_ENABLE
Definition: Kmod.h:22
#define PWM0_DATA
Definition: Kmod.h:20
#define GPIO_CLK
Definition: Kmod.h:13
int IoctlDuty(int DutyCycle)
routine called when IOCTL_DUTY is called
Definition: MyIrMod.c:188
#define PWM_CONTROL
Definition: Kmod.h:23
static int device_open(struct inode *inode, struct file *file)
This is called whenever a process attempts to open the device file.
Definition: MyIrMod.c:220
static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
This is called whenever a process read from the device file.
Definition: MyIrMod.c:261
#define IOCTL_DIVISOR
Definition: Kmod.h:41
#define PWM0_RANGE
Definition: Kmod.h:21
static short int invert
Invert the frame.
Definition: MyIrMod.c:48
static short int gpionr
Definition: MyIrMod.c:39
static long device_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
This function is called when somebody sends a ioctl to our device file.
Definition: MyIrMod.c:450
unsigned long flags
Definition: MyIrMod.c:57
module_param(gpionr, short, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
#define IO_BASE
Definition: Kmod.h:11
static int device_release(struct inode *inode, struct file *file)
This is called whenever a process releases the device file.
Definition: MyIrMod.c:241
#define GPIO_CONTROL
Definition: Kmod.h:12
#define PWM0_MODE_BAL
Definition: Kmod.h:17
int IoctlRange(int Range)
routine called when IOCTL_RANGE is called
Definition: MyIrMod.c:69
#define PwmPin
Definition: Kmod.h:33
void cleanup_module()
Cleanup.
Definition: MyIrMod.c:544
#define PWMCLK_DIV
Definition: Kmod.h:19
#define CLASS_NAME
Definition: Kmod.h:32
MODULE_AUTHOR("Ed Kapitein")
static struct device * MyIrDevice
Definition: MyIrMod.c:59
static char Message[BUF_LEN]
Definition: MyIrMod.c:62
#define GPIO_PWM
Definition: Kmod.h:15
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
This function is called when somebody write to our device file.
Definition: MyIrMod.c:276
#define BUF_LEN
Definition: Kmod.h:29
#define BCM_PASSWORD
Definition: Kmod.h:10
char * label
Definition: MyIrMod.c:56