#include <linux/device.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>
static struct resource key_resource[]=
{
[0] = {
.start = IRQ_EINT8,
.end = IRQ_EINT8,
.flags = IORESOURCE_IRQ,
},
[1] = {
.start = IRQ_EINT11,
.end = IRQ_EINT11,
.flags = IORESOURCE_IRQ,
},
[2]= {
.start = IRQ_EINT13,
.end = IRQ_EINT13,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_EINT14,
.end = IRQ_EINT14,
.flags = IORESOURCE_IRQ,
},
[4] = {
.start = IRQ_EINT15,
.end = IRQ_EINT15,
.flags = IORESOURCE_IRQ,
},
[5] = {
.start = IRQ_EINT19,
.end = IRQ_EINT19,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device *my_buttons_dev;
static int __init platform_dev_init(void)
{
int ret;
my_buttons_dev = platform_device_alloc("my_buttons", -1);/*分配設備*/
platform_device_add_resources(my_buttons_dev,key_resource,6);/*添加資源一定要用該函數,不能使用對platform_device->resource賦值
否則會導致platform_device_unregister調用失敗,內核異常。*/
ret = platform_device_add(my_buttons_dev);/*平臺設備的註冊*/
if(ret)
platform_device_put(my_buttons_dev);
return ret;
}
static void __exit platform_dev_exit(void)
{
platform_device_unregister(my_buttons_dev);/*平臺設備的卸載*/
}
module_init(platform_dev_init);
module_exit(platform_dev_exit);
MODULE_AUTHOR("Chen chunjian");
MODULE_LICENSE("GPL");
button_driver.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/unistd.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fcntl.h>
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_*_user */
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#define DEVICE_NAME "buttons"
#define BUTTON_NUM 6 /* button numbers */
static int buttons_irq[BUTTON_NUM];
struct irq_des
{
int *buttons_irq;
char *name[BUTTON_NUM];
};
struct irq_des button_irqs = {
.buttons_irq = buttons_irq,
.name = {"KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5"},
};
static volatile int key_values[] = {0,0,0,0,0,0};
struct timer_list button_timers[BUTTON_NUM]; /* buttons delay timer */
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
int i;
for(i=0; i<BUTTON_NUM; i++)
{
if(irq == buttons_irq[i])
{
key_values[i] = !key_values[i];
ev_press = 1;
wake_up_interruptible(&button_waitq);
mdelay(100);
}
}
return IRQ_RETVAL(IRQ_HANDLED);
}
static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
{
int i;
int err = 0;
for (i = 0; i < BUTTON_NUM; i++) {
err = request_irq(button_irqs.buttons_irq[i], buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
button_irqs.name[i], (void *)&button_irqs.buttons_irq[i]);
if (err)
break;
}
if (err) {
i--;
for (; i >= 0; i--) {
if (button_irqs.buttons_irq[i] < 0) {
continue;
}
disable_irq(button_irqs.buttons_irq[i]);
free_irq(button_irqs.buttons_irq[i], (void *)&button_irqs.buttons_irq[i]);
}
return -EBUSY;
}
return 0;
}
static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
{
int i;
for (i = 0; i < BUTTON_NUM; i++) {
free_irq(button_irqs.buttons_irq[i], (void *)&button_irqs.buttons_irq[i]);
}
return 0;
}
static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;
if (!ev_press) {
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else
wait_event_interruptible(button_waitq, ev_press);
}
ev_press = 0;
err = copy_to_user(buff, (const void *)&key_values, min(sizeof(key_values), count));
return err ? -EFAULT : min(sizeof(key_values), count);
}
static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = s3c24xx_buttons_open,
.release = s3c24xx_buttons_close,
.read = s3c24xx_buttons_read,
.poll = s3c24xx_buttons_poll,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "my_buttons",
.fops = &dev_fops,
};
static int my_plat_probe(struct platform_device *dev)
{
int ret,i;
struct resource *plat_resource;
struct platform_device *pdev = dev;
printk("my platform dirver find my platfrom device.\n");
for(i=0; i<BUTTON_NUM; i++){
plat_resource = platform_get_resource(pdev,IORESOURCE_IRQ,i);/*獲取資源*/
if(plat_resource == NULL)
return -ENOENT;
buttons_irq[i] = plat_resource->start;
}
ret = misc_register(&misc);//娣鋒潅璁懼鍙鋒敞鍐?
if(ret)
return ret;
return 0;
}
static int my_plat_remove(struct platform_device *dev)
{
printk("my platfrom device has removed.\n");
misc_deregister(&misc);
return 0;
}
struct platform_driver my_buttons_drv = {
.probe = my_plat_probe,
.remove = my_plat_remove,
.driver = {
.owner = THIS_MODULE,
.name = "my_buttons",
},
};
static int __init platform_drv_init(void)
{
int ret;
ret = platform_driver_register(&my_buttons_drv);/*平臺設備驅動的註冊*/
return ret;
}
static void __exit platform_drv_exit(void)
{
platform_driver_unregister(&my_buttons_drv);/*平臺設備驅動卸載*/
}
module_init(platform_drv_init);
module_exit(platform_drv_exit);
MODULE_AUTHOR("Chen chunjian");
MODULE_LICENSE("GPL");
mp3_play.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
#include <linux/soundcard.h>
#include <time.h>
#define SINGLE 1
#define LOOP 2
#define RANDOM 3
#define SCAN 4
#define VOL_INIT 60
struct DuLNode
{
char num[100];
struct DuLNode *prior,*next;
};
struct DuLNode *head=NULL;
struct DuLNode *current_head=NULL;
pid_t ppid = 0;
pid_t pid = 0;
int play_mod = 0;
mp3_play.c
#include "../../include/mp3_play.h"
/***************************************************
函數名:handler
功能:信號處理程序
傳入參數:int signo
返回值:void
***************************************************/
void handler(int signo)
{
if(signo == SIGUSR1)
{
current_head = current_head->next;
printf("signo == SIGUSR1\n");
}
return ;
}
/***************************************************
函數名:interface
功能:邋MP3按鍵提示界面
傳入參數: void
返回值:void
***************************************************/
void interface()
{
printf("=======================MP3======================\n");
printf(" 1.play/stop 2.suspend/continue \n");
printf(" 3.previous song 4.next song \n");
printf(" 5.volume up 6.volume down \n");
printf("================================================\n");
}
/***************************************************
函數名:vol_init
功能:音量初始化
傳入參數: void
返回值:void
***************************************************/
void vol_init()
{
int MIX_FD;
int iLevel;
MIX_FD = open("/dev/mixer", O_WRONLY);
if (MIX_FD == -1)
{
perror("Error:open /dev/mixer error");
exit(1);
}
iLevel = (VOL_INIT << 8) + VOL_INIT;
ioctl(MIX_FD, MIXER_WRITE(SOUND_MIXER_VOLUME), &iLevel);
close(MIX_FD);
}
/***************************************************
函數名:vol_up
功能:音量增大
傳入參數: void
返回值:void
***************************************************/
void vol_up()
{
int MIX_FD;
int iLevel;
int vol;
MIX_FD= open("/dev/mixer", O_WRONLY);
if (MIX_FD == -1)
{
perror("Error:open /dev/mixer error");
exit(1);
}
ioctl(MIX_FD, MIXER_READ(SOUND_MIXER_VOLUME), &iLevel);
vol = iLevel & 0xff;
vol += 5;
if(vol > 100)
{
vol = 100;
}
iLevel = (vol << 8) + vol;
printf("vol is at %d %%\n", vol);
ioctl(MIX_FD, MIXER_WRITE(SOUND_MIXER_VOLUME), &iLevel);
close(MIX_FD);
interface();
}
/***************************************************
函數名:vol_down
功能:音量減小
傳入參數: void
返回值:void
***************************************************/
void vol_down()
{
int MIX_FD;
int iLevel;
int vol;
MIX_FD= open("/dev/mixer", O_WRONLY);
if (MIX_FD == -1)
{
perror("Error:open /dev/mixer error");
exit(1);
}
ioctl(MIX_FD, MIXER_READ(SOUND_MIXER_VOLUME), &iLevel);
vol = iLevel & 0xff;
vol -= 5;
if(vol < 0)
{
vol = 0;
}
iLevel = (vol << 8) + vol;
printf("vol is at %d %%\n", vol);
ioctl(MIX_FD, MIXER_WRITE(SOUND_MIXER_VOLUME), &iLevel);
close(MIX_FD);
interface();
}
/***************************************************
函數名:main
功能:主函數
傳入參數: void
返回值:int
***************************************************/
int main(void)
{
int buttons_fd;
int buttons[] = {0,0,0,0,0,0};
int play_flag = 0;
int stop_flag = 1;
time_t time_up,time_dowm;
buttons_fd = open("/dev/my_buttons", 0);
if (buttons_fd < 0)
{
perror("open device my_buttons");
exit(1);
}
DuLinkList_init();
vol_init();
if(signal(SIGUSR1,handler) == SIG_ERR) /*爲信號設置信號處理程序*/
{
perror("can not handler for SIGUSR1");
exit(1);
}
ppid = getpid();/*得到父進程的進程ID號*/
for (;;)
{
int i;
int current_buttons[6];
if( 0 == play_mod )
{
system("clear");
printf("=============play_mod=============\n");
printf(" 1.single 2.loop 3.random 4.scan\n");
printf("==================================\n");
}
if (read(buttons_fd, ¤t_buttons, sizeof current_buttons ) != sizeof current_buttons )
{
perror("read my_buttons:");
exit(1);
}
for (i = 0; i < sizeof (buttons) / sizeof (buttons[0]); i++)
{
if (buttons[i] != current_buttons[i])
{
buttons[i] = current_buttons[i];
if(buttons[i] == 1)
{
if((time_dowm = time(NULL)) == -1)
{
perror("time");
exit(1);
}
if( 0 == play_mod )/*設置播放模式*/
{
switch(i)
{
case 0:
{
play_mod = SINGLE;/*單曲循環*/
break;
}
case 1:
{
play_mod = LOOP;/*順序播放*/
break;
}
case 2:
{
play_mod = RANDOM;/*隨機播放*/
break;
}
case 3:
{
play_mod = SCAN;/*瀏覽播放*/
break;
}
default:
{
break;
}
}
i = 0;
}
play_show();
switch(i)
{
case 0:/*開始、停止*/
{
if((++play_flag)%2 == 0)
{
play_flag = 0;
if(kill(pid,SIGKILL) == -1)/*殺死子進程*/
{
perror("fail to send signal");
exit(1);
}
system("killall -9 madplay");/*停止播放*/
printf("stop!\n");
interface();
break;
}
pid = fork();/*創建子進程*/
if(pid<0)
{
perror("fork error!\n");
exit(1);
}
if(pid == 0)/*子進程*/
{
start_play(ppid);
exit(0);
}
else/*父進程*/
{
if(waitpid(pid,NULL,WNOHANG) == -1)
{
perror("fail to wait!\n");
exit(1);
}
}
break;
}
case 1:/*暫停、繼續*/
{
if((++stop_flag)%2 == 0)
{
stop_flag= 0;
system("killall -STOP madplay");/*暫停播放*/
printf("suspend...\n");
interface();
}
else
{
system("killall -CONT madplay");/*繼續播放*/
printf("continue...\n");
interface();
}
break;
}
case 2:/*播放上一首*/
{
if(kill(pid,SIGKILL) == -1)/*殺死進程*/
{
perror("fail to send signal");
exit(1);
}
system("killall -9 madplay");/*停止播放*/
current_head = current_head->prior;/*當前指針指向上一首*/
pid = fork();/*創建子進程*/
if(pid<0)
{
perror("fork error!\n");
exit(1);
}
if(pid == 0)/*子進程*/
{
start_play(ppid);
stop_flag = 1;
exit(0);
}
break;
}
case 3:/*播放下一首*/
{
if(kill(pid,SIGKILL) == -1)/*殺死進程*/
{
perror("fail to send signal");
exit(1);
}
system("killall -9 madplay");/*停止播放*/
current_head = current_head->next;/*當前指針指向下一首*/
pid = fork();/*創建子進程*/
if(pid<0)
{
perror("fork error!\n");
exit(1);
}
if(pid == 0)/*子進程*/
{
start_play(ppid);
stop_flag = 1;
exit(0);
}
break;
}
case 4:/*音量增大*/
{
vol_up();
break;
}
case 5:/*音量減小*/
{
vol_down();
break;
}
default:
{
break;
}
}
}
else
{
if((time_up = time(NULL)) == -1)
{
perror("time");
exit(1);
}
if((time_up - time_dowm) >3)
{
play_mod = 0;
}
}
}
}
}
close(buttons_fd);
return 0;
}
handle.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
#define SINGLE 1
#define LOOP 2
#define RANDOM 3
#define SCAN 4
extern struct DuLNode
{
char num[100];
struct DuLNode *prior,*next;
};
extern struct DuLNode *head;
extern struct DuLNode *current_head;
extern int play_mod;
handle.c
#include "../../include/handle.h"
/***************************************************
函數名:play
功能:播放mp3
傳入參數:struct DuLNode*current_head
返回值:int
***************************************************/
int play(struct DuLNode*current_head)
{
char str[100];
char this_song[100]="/mp3/song/";
int len;
strcat(this_song,current_head->num);
len = strlen(this_song);
this_song[len]='\0';
execl("/mp3/madplay","madplay",this_song,NULL);
return 0;
}
/***************************************************
函數名:play_show
功能:顯示播放信息
傳入參數:void
返回值:void
***************************************************/
void play_show()
{
int count;
count = count_DuLNode();/*獲得歌曲數目*/
system("clear");
printf("song amount:%d\n",count);
switch(play_mod)/*顯示播放模式*/
{
case SINGLE:
{
printf("play mod:SINGLE\n");
break;
}
case LOOP:
{
printf("play mod:LOOP\n");
break;
}
case RANDOM:
{
printf("play mod:RANDOM\n");
break;
}
case SCAN:
{
printf("play mod:SCAN\n");
break;
}
default:
{
break;
}
}
printf("[previous song]:%s\n",(current_head->prior)->num);/*顯示上一首*/
printf("[next song]:%s\n",(current_head->next)->num);/*顯示下一首*/
printf("[this song]:%s\n",current_head->num);/*顯示當前歌曲*/
}
/***************************************************
函數名:start_play
功能:開始播放
傳入參數:pid_t ppid
返回值:int
***************************************************/
int start_play(pid_t ppid)
{
int fd;
char buf[100];
pid_t pid;
while(1)
{
pid = fork();/*創建子進程*/
if(pid<0)
{
perror("fork error!\n");
exit(1);
}
else if(pid==0)/*子進程*/
{
play_show();
interface();
play(current_head);
exit(0);
}
else/*父進程*/
{
if( play_mod == SCAN)
{
int i = 0;
for(i = 0;i < 10;i++)
{
sleep(1);
}
system("killall -9 madplay");/*停止播放*/
}
if(wait(NULL) == -1)/*等待子進程退出*/
{
perror("fail to wait!\n");
exit(1);
}
switch(play_mod)/*根據播放模式,選擇下一首*/
{
case SINGLE:/*單曲循環*/
{
break;
}
case LOOP:/*順序播放*/
{
current_head = current_head->next;
if(kill(ppid,SIGUSR1) == -1)/*向父進程發送信號SIGUSR1*/
{
perror("fail to send signal");
exit(1);
}
break;
}
case RANDOM:/*隨機播放*/
{
int i;
int step;
srand((int)time(0));
step = 1+(int)(100.0*rand()/(RAND_MAX+1.0));
for(i=0;i<step;i++)
{
current_head = current_head->next;
if(kill(ppid,SIGUSR1) == -1)/*向父進程發送信號SIGUSR1*/
{
perror("fail to send signal");
exit(1);
}
}
break;
}
case SCAN:
{
current_head = current_head->next;
if(kill(ppid,SIGUSR1) == -1)/*向父進程發送信號SIGUSR1*/
{
perror("fail to send signal");
exit(1);
}
break;
}
default:
{
break;
}
}
}
}
return 0;
}
DuLinkList_file.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"unistd.h"
#include"sys/types.h"
#include"fcntl.h"
#include"dirent.h"
extern struct DuLNode
{
char num[100];
struct DuLNode *prior,*next;
};
extern struct DuLNode *head;
extern struct DuLNode *current_head;
DuLinkList_file.c
#include "../../include/DuLinkList_file.h"
/***************************************************
函數名:DuLinkList_init
功能:初始化
傳入參數:void
返回值:void
***************************************************/
void DuLinkList_init()
{
head = (struct DuLNode *)malloc(sizeof(struct DuLNode));
head->prior = head;
head->next = head;
current_head = head;
head->num[0] = '\0';
DIR *dp;
struct dirent *dirp;
//打開指定的目錄
if ((dp = opendir("./song")) == NULL)
{
printf("can't open \n");
exit(1);
}
//遍歷目錄
while ((dirp = readdir(dp)) != NULL)
{
if(strcmp(dirp->d_name,".")==0 || strcmp(dirp->d_name,"..")==0)
{
continue;
}
add_DuLNode(dirp->d_name);
}
//關閉目錄
closedir(dp);
}
/***************************************************
函數名:add_DuLNode
功能:插入結點
傳入參數:char *num
返回值:void
***************************************************/
void add_DuLNode(char *num)
{
if(head->num[0] == '\0')
{
strcpy(head->num,num);
}
else
{
struct DuLNode *ptr = (struct DuLNode *)malloc(sizeof(struct DuLNode));
strcpy(ptr->num,num);
ptr->next=head->next;
head->next=ptr;
ptr->prior=head;
ptr->next->prior=ptr;
}
}
/***************************************************
函數名:display_DuLNode
功能:遍歷鏈表
傳入參數:void
返回值:void
***************************************************/
void display_DuLNode()
{
struct DuLNode *p = head;
do
{
printf("%s\n",p->num);
p = p->next;
}while(p!=head);
}
/***************************************************
函數名:display_next_DuLNode
功能:顯示下一首歌曲
傳入參數:void
返回值:void
***************************************************/
void display_next_DuLNode()
{
current_head = current_head->next;
printf("%s\n",current_head->num);
}
/***************************************************
函數名:display_prior_DuLNode
功能:顯示上一首歌曲
傳入參數:void
返回值:void
***************************************************/
void display_prior_DuLNode()
{
current_head = current_head->prior;
printf("%s\n",current_head->num);
}
/***************************************************
函數名:count_DuLNode
功能:計算鏈表結點數目
傳入參數:void
返回值:int count
***************************************************/
int count_DuLNode()
{
struct DuLNode *p = head;
int count = 0;
do
{
count++;
p = p->next;
}while(p!=head);
return count;
}