00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #define PCDSP_VERSION "V0.1 (C) P.Zahl 2000"
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <linux/config.h>
00054 #include <linux/module.h>
00055 #include <linux/version.h>
00056 #include <linux/kernel.h>
00057 #include <linux/sched.h>
00058 #include <linux/smp_lock.h>
00059 #include <linux/devfs_fs_kernel.h>
00060
00061 #include <linux/pci.h>
00062 #include <linux/types.h>
00063 #include <linux/major.h>
00064 #include <linux/errno.h>
00065 #include <linux/signal.h>
00066 #include <linux/fcntl.h>
00067 #include <linux/interrupt.h>
00068 #include <linux/devpts_fs.h>
00069 #include <linux/file.h>
00070 #include <linux/console.h>
00071 #include <linux/timer.h>
00072 #include <linux/ctype.h>
00073 #include <linux/kd.h>
00074 #include <linux/mm.h>
00075 #include <linux/string.h>
00076 #include <linux/slab.h>
00077 #include <linux/poll.h>
00078 #include <linux/proc_fs.h>
00079 #include <linux/init.h>
00080 #include <linux/proc_fs.h>
00081
00082 #include <asm/io.h>
00083 #include <asm/uaccess.h>
00084 #include <asm/system.h>
00085 #include <asm/bitops.h>
00086
00087 #ifdef __SMP__
00088 #include <asm/pgtable.h>
00089 #include <linux/smp_lock.h>
00090 #endif
00091
00092
00093 #define __KERNEL_SYSCALLS__
00094 #include <linux/unistd.h>
00095
00096
00097 #include "dbgstuff.h"
00098 #include "pcsim.h"
00099
00100
00101
00102
00103
00104 static devfs_handle_t devfs_handle = NULL;
00105
00106 static int opened;
00107
00108
00109 static char *pcdsp_dprambaseptr;
00110
00111
00112 static int wakeups = -1;
00113 static DECLARE_WAIT_QUEUE_HEAD(waitq);
00114
00115
00116
00117
00118
00119 static DECLARE_MUTEX_LOCKED(dspsimd_exited);
00120
00121 struct dspsim_thread_data {
00122
00123 int thread;
00124 wait_queue_head_t wq;
00125 int active;
00126
00127 char *virtual_dpram;
00128 int SrvReqAck;
00129 int ReqDAck;
00130 };
00131
00132 struct dspsim_thread_data dspsim_td;
00133
00134 #define ACKD_DSP dspsim_td.SrvReqAck
00135 #define REQD_DSP dspsim_td.ReqDAck
00136
00137
00138
00139
00140
00141
00142 #define TIMEOUT_TICKS 19
00143 #define JIFFIES_SEM 2
00144 #define MAXWAKEUPS_SEM 10
00145 #define MAXWAKEUPS_WMBOX 10
00146 #define MAXWAKEUPS_RMBOX 10
00147
00148
00149
00150 static void timeout(unsigned long ignore);
00151 void mysleep(unsigned long myjiffies);
00152
00153 int InitEmu(struct dspsim_thread_data *dsp);
00154 void ExitEmu(void);
00155 void ServiceRequest(struct dspsim_thread_data *dsp);
00156
00157 int BoxFull(int wait);
00158 int BoxEmpty(int wait);
00159 int ChkBoxEmpty(int wait);
00160 int WriteBox(unsigned long data, int wait);
00161 int ChkBoxFull(int wait);
00162 int ReadBox(unsigned long *data, int wait);
00163
00164
00165 static loff_t pcdsp_seek (struct file *, loff_t, int);
00166 static ssize_t pcdsp_read (struct file *, char *, size_t, loff_t *);
00167 static ssize_t pcdsp_write (struct file *, const char *, size_t, loff_t *);
00168 static int pcdsp_release (struct inode *, struct file *);
00169 static int pcdsp_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
00170
00171
00172 int pcdsp_initialize(void);
00173 inline void pcdsp_quit(void);
00174
00175 int init_module(void);
00176 void cleanup_module(void);
00177
00178
00179
00180
00181
00182 static int dspsim_thread(void *data);
00183 void start_dsp(struct dspsim_thread_data *dsp);
00184 void stop_dsp(struct dspsim_thread_data *dsp);
00185
00186 #ifdef EMULATE_A_SPALEED
00187 # include "spaleed_emu.c"
00188 #elif EMULATE_DSP_BB_SPALEED
00189 # include "spaleed_bb.c"
00190 #elif EMULATE_DSP_SPM
00191 # include "spm_emu.c"
00192 #else
00193
00194
00195 int InitEmu(struct dspsim_thread_data *dsp){ return 0; }
00196 void ExitEmu(){}
00197 void ServiceRequest(struct dspsim_thread_data *dsp){
00198 switch(((unsigned char) *dsp->virtual_dpram) & 0xff){
00199 case DSP_CMD_xxxxx:
00200 ACKD_DSP = TRUE;
00201 break;
00202 default:
00203 ACKD_DSP = TRUE;
00204 break;
00205 }
00206 REQD_DSP = FALSE;
00207 }
00208
00209 #endif
00210
00211
00212
00213
00214
00215
00216
00217 static int dspsim_thread(void *data)
00218 {
00219 struct dspsim_thread_data *dsp = data;
00220
00221 lock_kernel();
00222 daemonize();
00223
00224 strcpy(current->comm,"dspemud");
00225
00226 dsp->active = -1;
00227
00228 KDEBUG("DSP Simulating daemon: started\n");
00229
00230 do {
00231 dsp->active = 0;
00232 interruptible_sleep_on(&dsp->wq);
00233 dsp->active = 1;
00234 KDEBUG_L3("DSP Simulating daemon: wakeup\n");
00235 ServiceRequest(dsp);
00236 } while (!signal_pending(current));
00237
00238 KDEBUG("DSP Simulating thread: exit\n");
00239 dsp->active = -1;
00240
00241
00242 up(&dspsimd_exited);
00243 return 0;
00244 }
00245
00246 void start_dsp(struct dspsim_thread_data *dsp){
00247
00248 int pid;
00249 init_waitqueue_head(&dsp->wq);
00250 dsp->active = -1;
00251 dsp->thread = -1;
00252 pid = kernel_thread(dspsim_thread, (void *)dsp,
00253 CLONE_FS | CLONE_FILES | CLONE_SIGHAND );
00254 if( pid >= 0 ){
00255 dsp->thread = pid;
00256 KDEBUG("DSP thread started\n");
00257 return;
00258 }
00259 KDEBUG("Error starting DSP thread!\n");
00260
00261 }
00262
00263 void stop_dsp(struct dspsim_thread_data *dsp){
00264
00265 if (dsp->thread >= 0){
00266 KDEBUG("Sending SIGTERM to DSP Thread.\n");
00267 kill_proc( dsp->thread, SIGTERM, 1);
00268
00269
00270 KDEBUG("waiting until thread has finished...\n");
00271 while(dsp->active >= 0){
00272 mysleep(5);
00273 if(dsp->active >= 0)
00274 KDEBUG("still waiting\n");
00275 }
00276 return;
00277 }
00278 KDEBUG("Error: no DSP thread to terminate!\n");
00279 }
00280
00281
00282 static void timeout(unsigned long ignore){
00283 KDEBUG_L3("tmout wakeups %d\n", wakeups);
00284 wake_up_interruptible(&waitq);
00285 }
00286
00287 #define MAKE_MY_TIMEOUT_TMR(tmr) \
00288 struct timer_list tmr; \
00289 init_timer(&tmr); \
00290 tmr.function = timeout; \
00291 tmr.data = 0
00292
00293
00294 void mysleep(unsigned long myjiffies){
00295 MAKE_MY_TIMEOUT_TMR(timeout_tmr);
00296
00297 del_timer(&timeout_tmr);
00298 timeout_tmr.expires = jiffies + myjiffies;
00299 add_timer(&timeout_tmr);
00300 interruptible_sleep_on(&waitq);
00301 }
00302
00303
00304
00305
00306
00307 int BoxFull(int wait){
00308 MAKE_MY_TIMEOUT_TMR(timeout_tmr);
00309
00310 KDEBUG_L2("BoxFull ?\n");
00311 wakeups=0;
00312 while(!(ACKD_DSP) && wakeups < MAXWAKEUPS_RMBOX){
00313 if(!wait)
00314 return FALSE;
00315 del_timer(&timeout_tmr);
00316 timeout_tmr.expires = jiffies + TIMEOUT_TICKS;
00317 add_timer(&timeout_tmr);
00318 interruptible_sleep_on(&waitq);
00319 wakeups++;
00320 }
00321 KDEBUG_L2("BoxFull wakeups %d\n",wakeups);
00322 if(wakeups == MAXWAKEUPS_WMBOX){
00323 KDEBUG_L2("BoxFull timeout\n");
00324 return FALSE;
00325 }
00326 KDEBUG_L2("BoxFull OK\n");
00327 return TRUE;
00328 }
00329
00330 int BoxEmpty(int wait){
00331 MAKE_MY_TIMEOUT_TMR(timeout_tmr);
00332
00333 KDEBUG_L2("BoxEmpty ?\n");
00334 wakeups=0;
00335 while(REQD_DSP && wakeups < MAXWAKEUPS_RMBOX){
00336 if(!wait)
00337 return FALSE;
00338 del_timer(&timeout_tmr);
00339 timeout_tmr.expires = jiffies + TIMEOUT_TICKS;
00340 add_timer(&timeout_tmr);
00341 interruptible_sleep_on(&waitq);
00342 wakeups++;
00343 }
00344 KDEBUG_L2("BoxEmpty wakeups %d\n",wakeups);
00345 if(wakeups == MAXWAKEUPS_WMBOX){
00346 KDEBUG_L2("BoxEmpty timeout\n");
00347 return FALSE;
00348 }
00349 KDEBUG_L2("BoxEmpty OK\n");
00350 return TRUE;
00351 }
00352
00353 int ChkBoxEmpty(int wait){
00354 if(BoxEmpty(wait)){
00355 return TRUE;
00356 }
00357 return FALSE;
00358 }
00359
00360 int WriteBox(unsigned long data, int wait){
00361 if(BoxEmpty(wait)){
00362 if( dspsim_td.active ){
00363 KDEBUG("Warning: WriteBox called, but dspemu is busy, ignoreing this call!");
00364 return FALSE;
00365 }else{
00366 REQD_DSP = TRUE;
00367 ACKD_DSP = FALSE;
00368 wake_up_interruptible(&dspsim_td.wq);
00369 return TRUE;
00370 }
00371 }
00372 return FALSE;
00373 }
00374
00375 int ChkBoxFull(int wait){
00376 if(BoxFull(wait)){
00377 return TRUE;
00378 }
00379 return FALSE;
00380 }
00381
00382 int ReadBox(unsigned long *data, int wait){
00383 if(BoxFull(wait)){
00384 *data = 0;
00385
00386 return TRUE;
00387 }
00388 return FALSE;
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 #define SEEK_SET 0
00403 #define SEEK_CUR 1
00404 #define SEEK_END 2
00405
00406
00407 static loff_t pcdsp_seek(struct file *f, loff_t offset, int orig)
00408 {
00409 switch(orig){
00410 case SEEK_SET: f->f_pos = offset; break;
00411 case SEEK_CUR: f->f_pos += offset; break;
00412 case SEEK_END: return EBADF;
00413 }
00414 if( f->f_pos < 0
00415 || f->f_pos >= PCDSP_DPRAM_SIZE)
00416 f->f_pos = 0;
00417
00418 KDEBUG("seek to: %04x\n", (int)(f->f_pos));
00419 return f->f_pos;
00420 }
00421
00422
00423 static ssize_t pcdsp_read(struct file *f, char *buf, size_t count, loff_t *ppos)
00424 {
00425 if( ((unsigned int)f->f_pos + count) < PCDSP_DPRAM_SIZE){
00426 KDEBUG_L2("%d bytes at %x\n", count, f->f_pos);
00427 copy_to_user(buf, pcdsp_dprambaseptr + (unsigned int)f->f_pos, count);
00428 return 0;
00429 }
00430 return -EINVAL;
00431 }
00432
00433
00434 static ssize_t pcdsp_write(struct file *f, const char *buf, size_t count, loff_t *ppos)
00435 {
00436 if( ((unsigned int)f->f_pos + count) < PCDSP_DPRAM_SIZE){
00437 KDEBUG_L2("write %d bytes at %x\n", count, f->f_pos);
00438 copy_from_user(pcdsp_dprambaseptr + (unsigned int)f->f_pos, buf, count);
00439 return 0;
00440 }
00441 return -EINVAL;
00442 }
00443
00444 static int pcdsp_open(struct inode *inode, struct file *f){
00445 MOD_INC_USE_COUNT;
00446 opened++;
00447 f->f_pos=0;
00448 KDEBUG("Opened %d times\n",opened);
00449 return 0;
00450 }
00451
00452 static int pcdsp_release (struct inode *inode, struct file *f ){
00453 KDEBUG("release, still open:%d\n", opened-1);
00454 MOD_DEC_USE_COUNT;
00455 opened--;
00456 return 0;
00457 }
00458
00459 static int pcdsp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, unsigned long arg){
00460
00461 switch(cmd){
00462 case PCDSP_MBOX_FULL:
00463 return ChkBoxFull((int)arg);
00464
00465 case PCDSP_MBOX_READ_WAIT:
00466 ReadBox(&arg, TRUE);
00467 return (int)(arg&0x00ffffff);
00468 case PCDSP_MBOX_READ_NOWAIT:
00469 ReadBox(&arg, FALSE);
00470 return (int)(arg&0x00ffffff);
00471
00472 case PCDSP_MBOX_EMPTY:
00473 return ChkBoxEmpty((int)arg);
00474 case PCDSP_MBOX_WRITE_WAIT:
00475 return WriteBox(arg, TRUE);
00476 case PCDSP_MBOX_WRITE_NOWAIT:
00477 return WriteBox(arg, FALSE);
00478
00479 case PCDSP_PUT_SPEED:
00480 return 0;
00481 case PCDSP_RESET:
00482 KDEBUG("reset\n");
00483 return 0;
00484 case PCDSP_HALT:
00485 KDEBUG("halt\n");
00486 return 0;
00487 case PCDSP_RUN:
00488 KDEBUG("run\n");
00489 return 0;
00490
00491 case PCDSP_GETMODID:
00492 return MODID;
00493
00494 default:
00495 return -1;
00496 }
00497 return 0;
00498 }
00499
00500
00501
00502
00503 int pcdsp_initialize(){
00504 opened=0;
00505
00506 dspsim_td.SrvReqAck=FALSE;
00507 dspsim_td.virtual_dpram=NULL;
00508
00509
00510 dspsim_td.virtual_dpram = (void *)kmalloc (PCDSP_DPRAM_SIZE, GFP_KERNEL);
00511 if (dspsim_td.virtual_dpram == NULL){
00512 KDEBUG("Could not allocate Memory !\n");
00513 return 1;
00514 }
00515
00516 memset(dspsim_td.virtual_dpram, 0, PCDSP_DPRAM_SIZE);
00517 pcdsp_dprambaseptr = dspsim_td.virtual_dpram;
00518
00519 KDEBUG_L1("Driver %s\n", PCDSP_VERSION);
00520
00521 start_dsp(&dspsim_td);
00522 dspsim_td.SrvReqAck=TRUE;
00523 dspsim_td.ReqDAck =FALSE;
00524
00525 if( InitEmu(&dspsim_td) )
00526 return 1;
00527
00528
00529 return 0;
00530 }
00531
00532 inline void pcdsp_quit(){
00533
00534 ExitEmu();
00535
00536 stop_dsp(&dspsim_td);
00537
00538 kfree(dspsim_td.virtual_dpram);
00539 dspsim_td.virtual_dpram=NULL;
00540 KDEBUG("Simulation Driver deinstalled\n");
00541 }
00542
00543 int pcdsp_read_proc(char *page,
00544 char **start,
00545 off_t off,
00546 int count,
00547 int *eof,
00548 void *data)
00549 {
00550 int len;
00551
00552
00553
00554 static char pcdsp_proc_buffer[256];
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 if (off > 0)
00567 return 0;
00568
00569
00570 len = sprintf(pcdsp_proc_buffer,
00571 "PCDSP simulation module status:\n"
00572 "opened: %d\n"
00573 "LCD: %16s\n"
00574 "LCD: %16s\n",
00575 opened,
00576 dspsim_td.virtual_dpram+4*DSP_LCDBUFFER,
00577 dspsim_td.virtual_dpram+4*DSP_LCDBUFFER+16
00578 );
00579
00580
00581
00582
00583 *start = pcdsp_proc_buffer;
00584
00585
00586 return len;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 struct file_operations pcdsp_fops = {
00616 llseek: pcdsp_seek,
00617 read: pcdsp_read,
00618 write: pcdsp_write,
00619
00620
00621 ioctl: pcdsp_ioctl,
00622
00623 open: pcdsp_open,
00624
00625 release: pcdsp_release,
00626
00627
00628
00629
00630
00631 };
00632
00633 int init_module(void){
00634 struct proc_dir_entry *ent;
00635
00636 KDEBUG("init_module PCDSP:\n");
00637
00638 if ( devfs_register_chrdev (PCDSP_MAJOR, PCDSP_DEVICE_NAME, &pcdsp_fops) ){
00639 KDEBUG("unable create devfs entry for pcdsp device: %s, major: %d\n", PCDSP_DEVICE_NAME, PCDSP_MAJOR);
00640 return -EIO;
00641 }
00642 KDEBUG("Major number :%i \n", PCDSP_MAJOR);
00643
00644 devfs_handle = devfs_mk_dir (NULL, PCDSP_DEVFS_DIR, NULL);
00645
00646 devfs_register (devfs_handle, PCDSP_DEVICE_NAME,
00647 DEVFS_FL_DEFAULT, PCDSP_MAJOR, 0,
00648 S_IFCHR | S_IRUGO | S_IWUGO,
00649 &pcdsp_fops, NULL);
00650
00651 if(pcdsp_initialize())
00652 return -1;
00653
00654 if ((ent = create_proc_entry("pcdsp", S_IRUGO | S_IWUSR, NULL)) != NULL) {
00655 ent->read_proc = pcdsp_read_proc;
00656
00657 }
00658
00659 KDEBUG("init_module PCDSP done.\n");
00660
00661 return 0;
00662 }
00663
00664 void cleanup_module(void){
00665 KDEBUG("Module PCDSP cleanup:\n");
00666 pcdsp_quit();
00667
00668 devfs_unregister (devfs_handle);
00669 devfs_unregister_chrdev(PCDSP_MAJOR, PCDSP_DEVICE_NAME);
00670
00671 remove_proc_entry("pcdsp", NULL);
00672
00673 KDEBUG("Module PCDSP unregistered.\n");
00674 }