21,597
社区成员
发帖
与我相关
我的任务
分享
static void leddm_timer_handler_update_display(unsigned long data)
{
if( !( leddm_cdevp->is_update_display_on ) )
{
goto reconfig_timer_update_display;
}
leddm_update_display_screen( LEDDM_UPDATE_NORMAL );
reconfig_timer_update_display:
leddm_cdevp->timer_update_display.expires = jiffies + ( HZ / leddm_cdevp->current_jiffies_update_data );
mod_timer( &( leddm_cdevp->timer_update_display ), leddm_cdevp->timer_update_display.expires );
}
static void leddm_timer_handler_update_data(unsigned long data)
{
if( !( leddm_cdevp->is_update_data_on ) )
{
goto reconfig_timer_update_data;
}
leddm_update_data();
reconfig_timer_update_data:
leddm_cdevp->timer_update_data.expires = jiffies + ( HZ / leddm_cdevp->current_jiffies_update_data) ;
mod_timer( &( leddm_cdevp->timer_update_data ), leddm_cdevp->timer_update_data.expires );
}
static int leddm_open(struct inode *inode, struct file *filp)
{
leddm_info( "Entry leddm_open !\n" );
filp->private_data = leddm_cdevp;
return nonseekable_open( inode, filp );
}
static int leddm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
struct leddm_cdev *pcdevp = filp->private_data;
int ret=-EFAULT;
void __user *argp=(void __user *)arg;
leddm_info( "Entry leddm_ioctl !\n" );
if(LEDDM_IOCTL_MAGIC!=_IOC_TYPE(cmd)){
leddm_dbg("ioctype mismatch!\n");
return ret;
}
if((LEDDM_IOCTL_MINNR>_IOC_NR(cmd))||(_IOC_NR(cmd)>LEDDM_IOCTL_MAXNR)){
leddm_dbg("iocnr mistmatch!\n");
return ret;
}
leddm_info("cmd=%.4x\tioctype=%.4x\tiocnr=%.4x\tiocdir=%.4x\tiocsize=%.4x!\n",cmd,_IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd));
if(_IOC_WRITE&_IOC_DIR(cmd)){
if(!access_ok(VERIFY_READ,argp,_IOC_SIZE(cmd))){
leddm_dbg("User buffer cann't be read!\n");
return ret;
}
}
ret=0;
switch(cmd){
case LEDDM_IOCTL_STOP:
leddm_info("recrived ioctl command:LEDDM_IOCTL_STOP!\n");
pcdevp->is_update_data_on=FALSE;
pcdevp->is_update_display_on=FALSE;
memset(pcdevp->display_buf0,CHAR_COLOR_CLEAR,LED_DM_HEIGHT*LED_DM_WIDTH);
memset(pcdevp->display_buf1,CHAR_COLOR_CLEAR,LED_DM_HEIGHT*LED_DM_WIDTH);
pcdevp->data_buf_pos=0;
break;
case LEDDM_IOCTL_START:
leddm_info("recrived ioctl command:LEDDM_IOCTL_START!\n");
pcdevp->is_update_data_on=FALSE;
pcdevp->is_update_display_on=FALSE;
pcdevp->data_buf_pos=0;
break;
case LEDDM_IOCTL_PAUSE:
leddm_info("recrived ioctl command:LEDDM_IOCTL_PAUSE!\n");
pcdevp->is_update_display_on=FALSE;
break;
case LEDDM_IOCTL_RESUME:
leddm_info("recrived ioctl command:LEDDM_IOCTL_RESUME!\n");
pcdevp->is_update_display_on=TRUE;
break;
case LEDDM_IOCTL_SPEEDUP:
leddm_info("recrived ioctl command:LEDDM_IOCTL_SPEEDUP!\n");
if(pcdevp->current_jiffies_update_data<100){
pcdevp->current_jiffies_update_data+=10;
}
break;
case LEDDM_IOCTL_SPEEDDOWN:
leddm_info("recrived ioctl :command:LEDDM_IOCTL_SPEEDDOWN!\n");
if(pcdevp->current_jiffies_update_data>20){
pcdevp->current_jiffies_update_data-=10;
}
break;
case LEDDM_IOCTL_SETDATAWIDTH:
leddm_info("recrived ioctl command:LEDDM_IOCTL_SETDATAWIDTH!\n");
pcdevp->data_buf_width_temp=(int)arg;
pcdevp->is_update_data_on=FALSE;
pcdevp->is_update_display_on=FALSE;
break;
case LEDDM_IOCTL_SETDATAHEIGHT:
leddm_info("recrived ioctl command:LEDDM_IOCTL_SETDATAHEIGHT!\n");
pcdevp->data_buf_height_temp=(int)arg;
break;
case LEDDM_IOCTL_SETDATA:
leddm_info("recrived ioctl command:LEDDM_IOCTL_SETDATA!\n");
pcdevp->pdata_buf_temp=(unsigned char *)kmalloc((pcdevp->data_buf_width_temp*pcdevp->data_buf_height_temp),GFP_KERNEL);
if(!pcdevp->pdata_buf_temp){
leddm_dbg("Failure to allocate memory for new leddmdata!\n");
ret=-ENOMEM;
break;
}
if(copy_from_user(pcdevp->pdata_buf_temp,argp,(pcdevp->data_buf_width_temp*pcdevp->data_buf_height_temp))){
ret=-EFAULT;
break;
}
if(pcdevp->pdata_buf!=CharDM){
kfree(pcdevp->pdata_buf);
}
pcdevp->pdata_buf=pcdevp->pdata_buf_temp;
pcdevp->pdata_buf_temp=NULL;
pcdevp->data_buf_width=pcdevp->data_buf_width_temp;
pcdevp->data_buf_width_temp=0;
pcdevp->data_buf_height=pcdevp->data_buf_height_temp;
pcdevp->data_buf_height_temp=0;
pcdevp->data_buf_pos=0;
memset(pcdevp->display_buf0,CHAR_COLOR_CLEAR,LED_DM_HEIGHT*LED_DM_WIDTH);
memset(pcdevp->display_buf1,CHAR_COLOR_CLEAR,LED_DM_HEIGHT*LED_DM_WIDTH);
pcdevp->is_update_data_on=TRUE;
pcdevp->is_update_display_on=TRUE;
break;
default:
leddm_dbg("Unknown IOCTL command!\n");
break;
}
return ret;
}
static int leddm_release(struct inode *inode, struct file *filp)
{
struct leddm_cdev *pcdevp = filp->private_data;
leddm_info( "Entry leddm_release !\n" );
return 0;
}
static struct file_operations leddm_fops =
{
.owner = THIS_MODULE,
.open = leddm_open,
.llseek = no_llseek,
.ioctl = leddm_ioctl,
.release= leddm_release,
};
static int leddm_setup_cdev(struct leddm_cdev *pcdevp, int index)
{
int ret = 0;
dev_t dev = MKDEV( leddm_major, leddm_minor );
cdev_init( &( pcdevp->cdev ), &leddm_fops );
ret = cdev_add( &( pcdevp->cdev ), dev, 1 );
if( 0 > ret )
{
leddm_dbg( "Failure to add cdev Major: %d\tMinor: %d\tErrorno: %d\n", \
leddm_major, leddm_minor, ret);
}
else
{
leddm_info( "Success to add cdev Major: %d\tMinor: %d\n", \
leddm_major, leddm_minor );
}
return ret;
}
static int __init leddm_init(void)
{
int ret = 0;
dev_t dev = 0;
leddm_info( "Entry leddm_init !\n" );
if( leddm_major )
{
dev = MKDEV( leddm_major, leddm_minor );
ret = register_chrdev_region( dev, LEDDM_COUNT, LEDDM_NAME );
}
else
{
ret = alloc_chrdev_region( &dev, leddm_minor, LEDDM_COUNT, LEDDM_NAME );
leddm_major = MAJOR( dev );
}
if( 0 > ret )
{
leddm_dbg( "Cann't get major: %d !\n", leddm_major );
return ret;
}
leddm_info( "Success to get major: %d !\n", leddm_major );
leddm_cdevp = kmalloc( sizeof( struct leddm_cdev ), GFP_KERNEL );
if( !leddm_cdevp )
{
ret = -ENOMEM;
goto fail_kmalloc;
}
memset( leddm_cdevp, 0, sizeof( struct leddm_cdev ) );
leddm_driver_init();
ret = leddm_setup_cdev( leddm_cdevp, 0 );
if( 0 == ret )
{
leddm_cdevp->leddm_cls = class_create( THIS_MODULE, LEDDM_CLASSNAME );
if( IS_ERR( leddm_cdevp->leddm_cls ) )
{
leddm_dbg( "Cann't create device class !\n" );
ret = -EPERM;
goto fail_class_create;
}
leddm_info( "Success to create device class !\n" );
leddm_cdevp->leddm_dev = device_create( leddm_cdevp->leddm_cls, NULL, dev, NULL, LEDDM_NAME );
leddm_info( "Success to create device inode !\n" );
return ret;
}
fail_class_create:
kfree( leddm_cdevp );
fail_kmalloc:
unregister_chrdev_region( dev, LEDDM_COUNT );
return ret;
}
static void __exit leddm_exit(void)
{
leddm_info( "Entry leddm_exit !\n" );
device_destroy( leddm_cdevp->leddm_cls, MKDEV( leddm_major, leddm_minor ) );
class_destroy( leddm_cdevp->leddm_cls );
cdev_del( &( leddm_cdevp->cdev ) );
del_timer( &( leddm_cdevp->timer_update_data ) );
del_timer( &( leddm_cdevp->timer_update_display ) );
kfree( leddm_cdevp );
unregister_chrdev_region( MKDEV( leddm_major, leddm_minor ), LEDDM_COUNT );
}
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/fcntl.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/gpio.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-bank-c.h>
#include <plat/gpio-bank-f.h>
#include "leddm.h"
#include "leddmio.h"
#include "CharDM.h"
MODULE_LICENSE("Dual BSD/GPL");
static u32 leddm_major = LEDDM_MAJOR;
static u32 leddm_minor = LEDDM_MINOR;
static u32 leddm_port_table[] =
{
LEDDM_PORT_A,
LEDDM_PORT_B,
LEDDM_PORT_C,
LEDDM_PORT_D,
LEDDM_PORT_E,
LEDDM_PORT_R1,
LEDDM_PORT_G1,
LEDDM_PORT_R2,
LEDDM_PORT_G2,
LEDDM_PORT_LAT,
LEDDM_PORT_CLK,
LEDDM_ARRAY_END,
};
struct leddm_cdev
{
struct class *leddm_cls;
struct device *leddm_dev;
struct cdev cdev;
struct mutex mut;
struct timer_list timer_update_display;
struct timer_list timer_update_data;
int current_jiffies_update_data;
int is_update_display_on;
int is_update_data_on;
u8 display_buf0[ LED_DM_HEIGHT * LED_DM_WIDTH ];
u8 display_buf1[ LED_DM_HEIGHT * LED_DM_WIDTH ];
u8 display_buf_toggle;
u8 *pdata_display;
u8 *pdata_data;
u8 *pdata_buf;
u32 data_buf_width;
u32 data_buf_height;
u32 data_buf_pos;
u8 *pdata_buf_temp;
u32 data_buf_width_temp;
u32 data_buf_height_temp;
};
static struct leddm_cdev *leddm_cdevp = NULL;
static void leddm_timer_handler_update_display(unsigned long data);
static void leddm_timer_handler_update_data(unsigned long data);
void leddm_driver_port_init(void)
{
int i = 0;
while( LEDDM_ARRAY_END != ( leddm_port_table[i] ) )
{
gpio_direction_output( leddm_port_table[i], LEDDM_SIGNAL_LOW );
s3c_gpio_setpull( leddm_port_table[i], S3C_GPIO_PULL_NONE );
if( LEDDM_PORT_E >= leddm_port_table[i] )
{
gpio_set_value( leddm_port_table[i], LEDDM_SIGNAL_HIGH );
}
else
{
gpio_set_value( leddm_port_table[i], LEDDM_SIGNAL_LOW );
}
i++;
}
}
void leddm_update_display_send_line( int line, int flag )
{
unsigned int i;
unsigned char uch1;
unsigned char uch2;
for( i = 0; i < LED_DM_WIDTH; i++ )
{
if( LEDDM_UPDATE_NORMAL == flag )
{
uch1 = *( leddm_cdevp->pdata_display + line * LED_DM_WIDTH + i );
uch2 = *( leddm_cdevp->pdata_display + ( line + 16 ) * LED_DM_WIDTH + i );
}
else if( LEDDM_UPDATE_CLEAR == flag )
{
uch1 = CHAR_COLOR_CLEAR;
uch2 = CHAR_COLOR_CLEAR;
}
else
{
uch1 = CHAR_COLOR_ORANGE;
uch2 = CHAR_COLOR_ORANGE;
}
switch(uch1)
{
case CHAR_COLOR_CLEAR:
gpio_set_value( LEDDM_PORT_R1, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_G1, LEDDM_SIGNAL_HIGH );
break;
case CHAR_COLOR_RED:
gpio_set_value( LEDDM_PORT_R1, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_G1, LEDDM_SIGNAL_HIGH );
break;
case CHAR_COLOR_GREEN:
gpio_set_value( LEDDM_PORT_R1, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_G1, LEDDM_SIGNAL_LOW );
break;
case CHAR_COLOR_ORANGE:
gpio_set_value( LEDDM_PORT_R1, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_G1, LEDDM_SIGNAL_LOW );
break;
default:
break;
}
switch(uch2)
{
case CHAR_COLOR_CLEAR:
gpio_set_value( LEDDM_PORT_R2, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_G2, LEDDM_SIGNAL_HIGH );
break;
case CHAR_COLOR_RED:
gpio_set_value( LEDDM_PORT_R2, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_G2, LEDDM_SIGNAL_HIGH );
break;
case CHAR_COLOR_GREEN:
gpio_set_value( LEDDM_PORT_R2, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_G2, LEDDM_SIGNAL_LOW );
break;
case CHAR_COLOR_ORANGE:
gpio_set_value( LEDDM_PORT_R2, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_G2, LEDDM_SIGNAL_LOW );
break;
default:
break;
}
gpio_set_value( LEDDM_PORT_CLK, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_CLK, LEDDM_SIGNAL_HIGH );
}
}
void leddm_update_display_screen(int flag)
{
int i;
mutex_lock( &( leddm_cdevp->mut ) );
gpio_set_value( LEDDM_PORT_A, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_B, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_C, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_D, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_E, LEDDM_SIGNAL_HIGH );
for( i = 0; i < 17; i++ )
{
gpio_set_value( LEDDM_PORT_E, LEDDM_SIGNAL_LOW );
if( 16 == i )
{
leddm_update_display_send_line( 15 , flag );
}
else
{
leddm_update_display_send_line( i , flag );
}
gpio_set_value( LEDDM_PORT_A, (i & 0x01));
gpio_set_value( LEDDM_PORT_B, ((i & 0x02) >> 1));
gpio_set_value( LEDDM_PORT_C, ((i & 0x04) >> 2));
gpio_set_value( LEDDM_PORT_D, ((i & 0x08) >> 3));
gpio_set_value( LEDDM_PORT_LAT, LEDDM_SIGNAL_LOW );
gpio_set_value( LEDDM_PORT_LAT, LEDDM_SIGNAL_HIGH );
gpio_set_value( LEDDM_PORT_E, LEDDM_SIGNAL_HIGH );
}
mutex_unlock( &( leddm_cdevp->mut ) );
}
void leddm_display_buffer_toggle(void)
{
mutex_lock(&(leddm_cdevp->mut));
if(FALSE==leddm_cdevp->display_buf_toggle){
leddm_cdevp->display_buf_toggle=TRUE;
leddm_cdevp->pdata_display=leddm_cdevp->display_buf1;
leddm_cdevp->pdata_data=leddm_cdevp->display_buf0;
}
else{
leddm_cdevp->display_buf_toggle=FALSE;
leddm_cdevp->pdata_display=leddm_cdevp->display_buf0;
leddm_cdevp->pdata_data=leddm_cdevp->display_buf1;
}
mutex_unlock(&(leddm_cdevp->mut));
}
void leddm_update_data(void)
{
int i;
int j;
for(j=0;j<LED_DM_HEIGHT;j++){
for(i=0;i<(LED_DM_WIDTH-1);i++){
*(leddm_cdevp->pdata_data+j*LED_DM_WIDTH+i)=*(leddm_cdevp->pdata_display+j*LED_DM_WIDTH+i+1);
}
if(leddm_cdevp->data_buf_width>leddm_cdevp->data_buf_pos){
*(leddm_cdevp->pdata_data+j*LED_DM_WIDTH+i)=*(leddm_cdevp->pdata_buf+j*leddm_cdevp->data_buf_width+leddm_cdevp->data_buf_pos);
}
else{
*(leddm_cdevp->pdata_data+j*LED_DM_WIDTH+i)=CHAR_COLOR_CLEAR;
}
}
if(leddm_cdevp->data_buf_pos>=(leddm_cdevp->data_buf_width+LED_DM_WIDTH)){
leddm_cdevp->data_buf_pos=0;
}
else{
leddm_cdevp->data_buf_pos++;
}
leddm_display_buffer_toggle();
}
void leddm_driver_init(void)
{
leddm_driver_port_init();
leddm_cdevp->display_buf_toggle = FALSE;
leddm_cdevp->pdata_display = leddm_cdevp->display_buf0;
leddm_cdevp->pdata_data = leddm_cdevp->display_buf1;
leddm_cdevp->pdata_buf = CharDM;
leddm_cdevp->data_buf_width = CharDM_Width;
leddm_cdevp->data_buf_height = CharDM_Height;
leddm_cdevp->data_buf_pos = 0;
mutex_init( &( leddm_cdevp->mut ) );
init_timer( &( leddm_cdevp->timer_update_display ) );
leddm_cdevp->timer_update_display.function = leddm_timer_handler_update_display;
leddm_cdevp->timer_update_display.expires = jiffies + ( HZ / LEDDM_JIFFIES_UPDATE_DISPLAY );
add_timer( &( leddm_cdevp->timer_update_display ) );
leddm_cdevp->is_update_display_on = TRUE;
init_timer( &( leddm_cdevp->timer_update_data ) );
leddm_cdevp->timer_update_data.function = leddm_timer_handler_update_data;
leddm_cdevp->current_jiffies_update_data = LEDDM_JIFFIES_UPDATE_DATA;
leddm_cdevp->timer_update_data.expires = jiffies + ( HZ / leddm_cdevp->current_jiffies_update_data );
add_timer( &( leddm_cdevp->timer_update_data ) );
leddm_cdevp->is_update_data_on = TRUE;
}