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
00059 #include <linux/pci.h>
00060 #include <linux/types.h>
00061 #include <linux/major.h>
00062 #include <linux/errno.h>
00063 #include <linux/signal.h>
00064 #include <linux/fcntl.h>
00065 #include <linux/interrupt.h>
00066 #include <linux/devpts_fs.h>
00067 #include <linux/file.h>
00068 #include <linux/console.h>
00069 #include <linux/timer.h>
00070 #include <linux/ctype.h>
00071 #include <linux/kd.h>
00072 #include <linux/mm.h>
00073 #include <linux/string.h>
00074 #include <linux/malloc.h>
00075 #include <linux/poll.h>
00076 #include <linux/proc_fs.h>
00077 #include <linux/init.h>
00078
00079 #include <asm/io.h>
00080 #include <asm/uaccess.h>
00081 #include <asm/system.h>
00082 #include <asm/bitops.h>
00083
00084 #ifdef __SMP__
00085 #include <asm/pgtable.h>
00086 #include <linux/smp_lock.h>
00087 #endif
00088
00089
00090 #define __KERNEL_SYSCALLS__
00091 #include <linux/unistd.h>
00092
00093
00094 #include "dbgstuff.h"
00095 #include "pcsim.h"
00096
00097
00098
00099
00100
00101 static int pcdsp_major;
00102
00103 static int opened;
00104
00105
00106 static char *pcdsp_dprambaseptr;
00107
00108
00109 static int wakeups = -1;
00110 static struct wait_queue *waitq = NULL;
00111
00112
00113 struct dspsim_thread_data {
00114
00115 struct task_struct *thread;
00116 struct wait_queue *wq;
00117 int active, rmmod;
00118
00119 char *virtual_dpram;
00120 int SrvReqAck;
00121 int ReqDAck;
00122 };
00123
00124 struct dspsim_thread_data dspsim_td;
00125
00126 #define ACKD_DSP dspsim_td.SrvReqAck
00127 #define REQD_DSP dspsim_td.ReqDAck
00128
00129
00130
00131
00132
00133
00134 #define TIMEOUT_TICKS 19
00135 #define JIFFIES_SEM 2
00136 #define MAXWAKEUPS_SEM 10
00137 #define MAXWAKEUPS_WMBOX 10
00138 #define MAXWAKEUPS_RMBOX 10
00139
00140
00141
00142 static void timeout(unsigned long ignore);
00143 void mysleep(unsigned long myjiffies);
00144
00145 int InitEmu(struct dspsim_thread_data *dsp);
00146 void ExitEmu(void);
00147 void ServiceRequest(struct dspsim_thread_data *dsp);
00148
00149 int BoxFull(int wait);
00150 int BoxEmpty(int wait);
00151 int ChkBoxEmpty(int wait);
00152 int WriteBox(unsigned long data, int wait);
00153 int ChkBoxFull(int wait);
00154 int ReadBox(unsigned long *data, int wait);
00155
00156
00157 static loff_t pcdsp_seek (struct file *, loff_t, int);
00158 static ssize_t pcdsp_read (struct file *, char *, size_t, loff_t *);
00159 static ssize_t pcdsp_write (struct file *, const char *, size_t, loff_t *);
00160 static int pcdsp_release (struct inode *, struct file *);
00161 static int pcdsp_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
00162
00163
00164 int pcdsp_initialize(void);
00165 inline void pcdsp_quit(void);
00166
00167 int init_module(void);
00168 void cleanup_module(void);
00169
00170
00171
00172
00173
00174 static int dspsim_thread(void *data);
00175 void start_dsp(struct dspsim_thread_data *dsp);
00176 void stop_dsp(struct dspsim_thread_data *dsp);
00177
00178 #ifdef EMULATE_A_SPALEED
00179 # include "spaleed_emu.c"
00180 #else
00181 # ifdef EMULATE_DSP_BB_SPALEED
00182 # include "spaleed_bb.c"
00183 # else
00184
00185
00186 int InitEmu(struct dspsim_thread_data *dsp){ return 0; }
00187 void ExitEmu(){}
00188 void ServiceRequest(struct dspsim_thread_data *dsp){
00189 switch(((unsigned char) *dsp->virtual_dpram) & 0xff){
00190 case DSP_CMD_xxxxx:
00191 ACKD_DSP = TRUE;
00192 break;
00193 default:
00194 ACKD_DSP = TRUE;
00195 break;
00196 }
00197 REQD_DSP = FALSE;
00198 }
00199
00200 # endif
00201 #endif
00202
00203
00204
00205
00206
00207
00208
00209 static int dspsim_thread(void *data)
00210 {
00211 struct dspsim_thread_data *dsp = data;
00212
00213 #ifdef __SMP__
00214 lock_kernel();
00215 #endif
00216
00217 exit_mm(current);
00218 current->session = 1;
00219 current->pgrp = 1;
00220 sigfillset(¤t->blocked);
00221 current->fs->umask = 0;
00222 strcpy(current->comm,"dspemu");
00223
00224 dsp->thread = current;
00225 dsp->active = -1;
00226
00227 #ifdef __SMP__
00228 unlock_kernel();
00229 #endif
00230
00231 KDEBUG("DSP Simulating daemon: started\n");
00232
00233 for (;;) {
00234 dsp->active = 0;
00235 interruptible_sleep_on(&dsp->wq);
00236 dsp->active = 1;
00237 KDEBUG_L3("DSP Simulating daemon: wakeup\n");
00238 if (dsp->rmmod)
00239 goto done;
00240
00241 ServiceRequest(dsp);
00242 }
00243
00244 done:
00245 KDEBUG("DSP Simulating thread: exit\n");
00246 dsp->active = -1;
00247 dsp->thread = NULL;
00248
00249 return 0;
00250 }
00251
00252 void start_dsp(struct dspsim_thread_data *dsp){
00253
00254 dsp->wq = NULL;
00255 dsp->thread = NULL;
00256 dsp->rmmod = 0;
00257 kernel_thread(dspsim_thread, (void *)dsp, 0);
00258
00259 }
00260
00261 void stop_dsp(struct dspsim_thread_data *dsp){
00262
00263 if (dsp->thread)
00264 {
00265
00266 while( dsp->active )
00267 mysleep(100);
00268 dsp->rmmod = 1;
00269 wake_up_interruptible(&dsp->wq);
00270 }
00271
00272 KDEBUG("waiting until thread has finished...\n");
00273 while(dsp->thread){
00274 mysleep(5);
00275 if(dsp->thread)
00276 KDEBUG("still waiting\n");
00277 }
00278 }
00279
00280
00281
00282
00283
00284 static void timeout(unsigned long ignore){
00285 KDEBUG_L3("tmout wakeups %d\n", wakeups);
00286 wake_up_interruptible(&waitq);
00287 }
00288
00289 void mysleep(unsigned long myjiffies){
00290 static struct timer_list timeout_tmr = { NULL, NULL, 0, 0, timeout };
00291 del_timer(&timeout_tmr);
00292 timeout_tmr.expires = jiffies + myjiffies;
00293 add_timer(&timeout_tmr);
00294 interruptible_sleep_on(&waitq);
00295 }
00296
00297
00298
00299
00300
00301 int BoxFull(int wait){
00302 static struct timer_list timeout_tmr = { NULL, NULL, 0, 0, timeout };
00303 KDEBUG_L2("BoxFull ?\n");
00304 wakeups=0;
00305 while(!(ACKD_DSP) && wakeups < MAXWAKEUPS_RMBOX){
00306 if(!wait)
00307 return FALSE;
00308 del_timer(&timeout_tmr);
00309 timeout_tmr.expires = jiffies + TIMEOUT_TICKS;
00310 add_timer(&timeout_tmr);
00311 interruptible_sleep_on(&waitq);
00312 wakeups++;
00313 }
00314 KDEBUG_L2("BoxFull wakeups %d\n",wakeups);
00315 if(wakeups == MAXWAKEUPS_WMBOX){
00316 KDEBUG_L2("BoxFull timeout\n");
00317 return FALSE;
00318 }
00319 KDEBUG_L2("BoxFull OK\n");
00320 return TRUE;
00321 }
00322
00323 int BoxEmpty(int wait){
00324 static struct timer_list timeout_tmr = { NULL, NULL, 0, 0, timeout };
00325 KDEBUG_L2("BoxEmpty ?\n");
00326 wakeups=0;
00327 while(REQD_DSP && wakeups < MAXWAKEUPS_RMBOX){
00328 if(!wait)
00329 return FALSE;
00330 del_timer(&timeout_tmr);
00331 timeout_tmr.expires = jiffies + TIMEOUT_TICKS;
00332 add_timer(&timeout_tmr);
00333 interruptible_sleep_on(&waitq);
00334 wakeups++;
00335 }
00336 KDEBUG_L2("BoxEmpty wakeups %d\n",wakeups);
00337 if(wakeups == MAXWAKEUPS_WMBOX){
00338 KDEBUG_L2("BoxEmpty timeout\n");
00339 return FALSE;
00340 }
00341 KDEBUG_L2("BoxEmpty OK\n");
00342 return TRUE;
00343 }
00344
00345 int ChkBoxEmpty(int wait){
00346 if(BoxEmpty(wait)){
00347 return TRUE;
00348 }
00349 return FALSE;
00350 }
00351
00352 int WriteBox(unsigned long data, int wait){
00353 if(BoxEmpty(wait)){
00354 if( dspsim_td.active ){
00355 KDEBUG("Warning: WriteBox called, but dspemu is busy, ignoreing this call!");
00356 return FALSE;
00357 }else{
00358 REQD_DSP = TRUE;
00359 ACKD_DSP = FALSE;
00360 wake_up_interruptible(&dspsim_td.wq);
00361 return TRUE;
00362 }
00363 }
00364 return FALSE;
00365 }
00366
00367 int ChkBoxFull(int wait){
00368 if(BoxFull(wait)){
00369 return TRUE;
00370 }
00371 return FALSE;
00372 }
00373
00374 int ReadBox(unsigned long *data, int wait){
00375 if(BoxFull(wait)){
00376 *data = 0;
00377
00378 return TRUE;
00379 }
00380 return FALSE;
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 #define SEEK_SET 0
00395 #define SEEK_CUR 1
00396 #define SEEK_END 2
00397
00398
00399 static loff_t pcdsp_seek(struct file *f, loff_t offset, int orig)
00400 {
00401 switch(orig){
00402 case SEEK_SET: f->f_pos = offset; break;
00403 case SEEK_CUR: f->f_pos += offset; break;
00404 case SEEK_END: return EBADF;
00405 }
00406 if( f->f_pos < 0
00407 || f->f_pos >= PCDSP_DPRAM_SIZE)
00408 f->f_pos = 0;
00409
00410 KDEBUG("seek to: %04x\n", (int)(f->f_pos));
00411 return f->f_pos;
00412 }
00413
00414
00415 static ssize_t pcdsp_read(struct file *f, char *buf, size_t count, loff_t *ppos)
00416 {
00417 if( ((unsigned int)f->f_pos + count) < PCDSP_DPRAM_SIZE){
00418 KDEBUG_L2("%d bytes at %x\n", count, f->f_pos);
00419 copy_to_user(buf, pcdsp_dprambaseptr + (unsigned int)f->f_pos, count);
00420 return 0;
00421 }
00422 return -EINVAL;
00423 }
00424
00425
00426 static ssize_t pcdsp_write(struct file *f, const char *buf, size_t count, loff_t *ppos)
00427 {
00428 if( ((unsigned int)f->f_pos + count) < PCDSP_DPRAM_SIZE){
00429 KDEBUG_L2("write %d bytes at %x\n", count, f->f_pos);
00430 copy_from_user(pcdsp_dprambaseptr + (unsigned int)f->f_pos, buf, count);
00431 return 0;
00432 }
00433 return -EINVAL;
00434 }
00435
00436 static int pcdsp_open(struct inode *inode, struct file *f){
00437 MOD_INC_USE_COUNT;
00438 opened++;
00439 f->f_pos=0;
00440 KDEBUG("Opened %d times\n",opened);
00441 return 0;
00442 }
00443
00444 static int pcdsp_release (struct inode *inode, struct file *f ){
00445 KDEBUG("release, still open:%d\n", opened-1);
00446 MOD_DEC_USE_COUNT;
00447 opened--;
00448 return 0;
00449 }
00450
00451 static int pcdsp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, unsigned long arg){
00452
00453 switch(cmd){
00454 case PCDSP_MBOX_FULL:
00455 return ChkBoxFull((int)arg);
00456
00457 case PCDSP_MBOX_READ_WAIT:
00458 ReadBox(&arg, TRUE);
00459 return (int)(arg&0x00ffffff);
00460 case PCDSP_MBOX_READ_NOWAIT:
00461 ReadBox(&arg, FALSE);
00462 return (int)(arg&0x00ffffff);
00463
00464 case PCDSP_MBOX_EMPTY:
00465 return ChkBoxEmpty((int)arg);
00466 case PCDSP_MBOX_WRITE_WAIT:
00467 return WriteBox(arg, TRUE);
00468 case PCDSP_MBOX_WRITE_NOWAIT:
00469 return WriteBox(arg, FALSE);
00470
00471 case PCDSP_PUT_SPEED:
00472 return 0;
00473 case PCDSP_RESET:
00474 KDEBUG("reset\n");
00475 return 0;
00476 case PCDSP_HALT:
00477 KDEBUG("halt\n");
00478 return 0;
00479 case PCDSP_RUN:
00480 KDEBUG("run\n");
00481 return 0;
00482
00483 case PCDSP_GETMODID:
00484 return MODID;
00485
00486 default:
00487 return -1;
00488 }
00489 return 0;
00490 }
00491
00492
00493
00494
00495 int pcdsp_initialize(){
00496 opened=0;
00497
00498 dspsim_td.SrvReqAck=FALSE;
00499 dspsim_td.virtual_dpram=NULL;
00500
00501
00502 dspsim_td.virtual_dpram = (void *)kmalloc (PCDSP_DPRAM_SIZE, GFP_KERNEL);
00503 if (dspsim_td.virtual_dpram == NULL){
00504 KDEBUG("Could not allocate Memory !\n");
00505 return 1;
00506 }
00507
00508 memset(dspsim_td.virtual_dpram, 0, PCDSP_DPRAM_SIZE);
00509 pcdsp_dprambaseptr = dspsim_td.virtual_dpram;
00510
00511 KDEBUG_L1("Driver %s\n", PCDSP_VERSION);
00512
00513 start_dsp(&dspsim_td);
00514 dspsim_td.SrvReqAck=TRUE;
00515 dspsim_td.ReqDAck =FALSE;
00516
00517 if( InitEmu(&dspsim_td) )
00518 return 1;
00519
00520
00521 return 0;
00522 }
00523
00524 inline void pcdsp_quit(){
00525
00526 ExitEmu();
00527
00528 stop_dsp(&dspsim_td);
00529
00530 kfree(dspsim_td.virtual_dpram);
00531 dspsim_td.virtual_dpram=NULL;
00532 KDEBUG("Simulation Driver deinstalled\n");
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 struct file_operations pcdsp_fops = {
00559 pcdsp_seek,
00560 pcdsp_read,
00561 pcdsp_write,
00562 NULL,
00563 NULL,
00564 pcdsp_ioctl,
00565 NULL,
00566 pcdsp_open,
00567 NULL,
00568 pcdsp_release,
00569 NULL,
00570 NULL,
00571 NULL,
00572 NULL,
00573 NULL
00574 };
00575
00576 int init_module(void){
00577 KDEBUG("init_module PCDSP:\n");
00578
00579 if ((pcdsp_major = register_chrdev (0, PCDSP_DEVICE_NAME, &pcdsp_fops)) == -EBUSY){
00580 KDEBUG("unable to get major for pcdsp device: %s\n", PCDSP_DEVICE_NAME);
00581 return -EIO;
00582 }
00583 KDEBUG("Major number :%i \n", pcdsp_major);
00584
00585 if(pcdsp_initialize())
00586 return -1;
00587
00588 KDEBUG("init_module PCDSP done.\n");
00589 return 0;
00590 }
00591
00592 void cleanup_module(void){
00593 KDEBUG("Module PCDSP cleanup:\n");
00594 pcdsp_quit();
00595 unregister_chrdev(pcdsp_major, PCDSP_DEVICE_NAME);
00596 KDEBUG("Module PCDSP unregistered.\n");
00597 }