int pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, unsigned long p3, unsigned long p4) { unsigned long flags; int err = 0; struct patmgr_info *tmp_mbox; if (!pmgr_opened[dev]) return 0; tmp_mbox = (struct patmgr_info *) vmalloc (sizeof (struct patmgr_info)); if (tmp_mbox == NULL) { printk ("pmgr: Couldn't allocate memory for a message\n"); return 0; } save_flags (flags); cli (); if (mbox[dev]) printk (" PATMGR: Server %d mbox full. Why?\n", dev); else { mbox[dev] = tmp_mbox; mbox[dev]->key = PM_K_EVENT; mbox[dev]->command = event; mbox[dev]->parm1 = p1; mbox[dev]->parm2 = p2; mbox[dev]->parm3 = p3; msg_direction[dev] = A_TO_S; if ((server_wait_flag[dev].flags & WK_SLEEP)) { { server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); appl_wait_flag.flags &= ~WK_SLEEP;; mbox[dev] = NULL; msg_direction[dev] = 0; } restore_flags (flags); vfree (tmp_mbox); return err; }
int pmgr_access (int dev, struct patmgr_info *rec) { unsigned long flags; int err = 0; save_flags (flags); cli (); if (mbox[dev]) printk (" PATMGR: Server %d mbox full. Why?\n", dev); else { rec->key = PM_K_COMMAND; mbox[dev] = rec; msg_direction[dev] = A_TO_S; if ((server_wait_flag[dev].flags & WK_SLEEP)) { { server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); appl_wait_flag.flags &= ~WK_SLEEP;; if (msg_direction[dev] != S_TO_A) { rec->key = PM_ERROR; rec->parm1 = -(EIO); } else if (rec->key == PM_ERROR) { err = rec->parm1; if (err > 0) err = -err; } mbox[dev] = NULL; msg_direction[dev] = 0; } restore_flags (flags); return err; }
int pmgr_read (int dev, struct fileinfo *file, char *buf, int count) { unsigned long flags; int ok = 0; if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid read count\n", dev); return -(EIO); } while (!ok && !current_got_fatal_signal ()) { save_flags (flags); cli (); while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && !current_got_fatal_signal ()) { server_wait_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&server_procs[dev]); server_wait_flag[dev].flags &= ~WK_SLEEP;; } if (mbox[dev] && msg_direction[dev] == A_TO_S) { memcpy_tofs (&(buf)[0], (char *) mbox[dev], count); msg_direction[dev] = 0; ok = 1; } restore_flags (flags); } if (!ok) return -(EINTR); return count; }
/* Llamado cuando el fichero /proc se abre */ static int module_open(struct inode *inode, struct file *file) { /* Si las banderas del fichero incluyen O_NONBLOCK, esto * significa que el proceso no quiere esperar al fichero. * En este caso, si el fichero ya está abierto, deberemos * fallar con -EAGAIN, significando que "tienes que intentarlo * otra vez", en vez de bloquear un proceso que tendría que * estar despierto. */ if ((file->f_flags & O_NONBLOCK) && Already_Open) return -EAGAIN; /* Este es el sitio correcto para MOD_INC_USE_COUNT * porque si un proceso está en el bucle, que * está dentro del módulo, el módulo del núcleo no * debería ser quitado. */ MOD_INC_USE_COUNT; /* Si el fichero ya está abierto, espera hasta que no lo esté */ while (Already_Open) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) int i, is_sig=0; #endif /* Esta función pone el proceso actual, * incluyendo algunas llamada al sistema, como nosotros, * a dormir. La ejecución será retomada correctamente después * de la llamada a la función, o porque alguien * llamó a wake_up(&WaitQ) (sólo module_close hace esto, * cuando el fichero se cierra) o cuando una señal, como * Ctrl-C, es enviada al proceso */ module_interruptible_sleep_on(&WaitQ); /* Si despertamos porque tenemos una señal no estamos * bloqueando, retornamos -EINTR (falla la llamada al * sistema). Esto permite a los procesos ser matados o * parados. */ /* * Emmanuel Papirakis: * * Esta es una pequeña actualización para trabajar con 2.2.*. Las * señales son ahora contenidas en dos palabras (64 bits) y son * almacenadas en una estructura que contiene un array de dos * unsigned longs. Ahora tenemos que realizar 2 chequeos en nuestro if. * * Ori Pomerantz: * * Nadie me prometió que no usarían nunca más de 64 bits, o * que este libro no sería usado para una versión de Linux * con un tamaño de palabra de 16 bits. En cualquier caso este * código debería de funcionar. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) for(i=0; i<_NSIG_WORDS && !is_sig; i++) is_sig = current->signal.sig[i] & ~current->blocked.sig[i]; if (is_sig) { #else if (current->signal & ~current->blocked) { #endif /* Es importante poner MOD_DEC_USE_COUNT aquí. * porque los procesos dónde open es interrumpido * no tendrán nunca un close correspondiente. Si * no decrementamos el contador de uso aquí, lo dejaremos * con un valor positivo el cual no nos dará * la oportunidad de llegar hasta 0, dándonos un módulo inmortal, * que sólo se puede matar reiniciando la máquina. */ MOD_DEC_USE_COUNT; return -EINTR; } } /* Si estamos aquí, Already_Open debe ser cero */ /* Abre el fichero */ Already_Open = 1; return 0; /* Permite el acceso */ } /* Llamado cuando el fichero /proc se cierra*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) int module_close(struct inode *inode, struct file *file) #else void module_close(struct inode *inode, struct file *file) #endif { /* Establece Already_Open a cero, por lo tanto uno de los procesos * en WaitQ será capaz de establecer Already_Open otra vez a uno y * abrir el fichero. Todos los otros procesos serán llamados cuando * Already_Open vuelva a ser uno, por lo tanto volverán a * dormir. */ Already_Open = 0; /* Despertamos a todos los procesos en WaitQ, por lo tanto si * alguien está esperando por el fichero, lo puede tener. */ module_wake_up(&WaitQ); MOD_DEC_USE_COUNT; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) return 0; /* finalizado con éxito */ #endif }
static int sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) { unsigned long flags; unsigned char temp; int done, timeout_val; static unsigned char codec_dma_bits = 0; if (flag & CPF_FIRST) { /* * First block. Have to allocate DMA and to reset the board * before continuing. */ save_flags (flags); cli (); codec_dma_bits = sscape_read (devc, GA_CDCFG_REG); #if 0 sscape_write (devc, GA_CDCFG_REG, codec_dma_bits & ~0x08); /* Disable codec DMA */ #endif if (devc->dma_allocated == 0) { devc->dma_allocated = 1; } restore_flags (flags); sscape_write (devc, GA_HMCTL_REG, (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ for (timeout_val = 10000; timeout_val > 0; timeout_val--) sscape_read (devc, GA_HMCTL_REG); /* Delay */ /* Take board out of reset */ sscape_write (devc, GA_HMCTL_REG, (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); } /* * Transfer one code block using DMA */ memcpy (audio_devs[devc->my_audiodev]->dmap_out->raw_buf, block, size); save_flags (flags); cli (); /******** INTERRUPTS DISABLED NOW ********/ do_dma (devc, SSCAPE_DMA_A, audio_devs[devc->my_audiodev]->dmap_out->raw_buf_phys, size, DMA_MODE_WRITE); /* * Wait until transfer completes. */ sscape_sleep_flag.flags = WK_NONE; done = 0; timeout_val = 100; while (!done && timeout_val-- > 0) { int resid; { unsigned long tlimit; if (1) current_set_timeout (tlimit = jiffies + (1)); else tlimit = (unsigned long) -1; sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { if (jiffies >= tlimit) sscape_sleep_flag.flags |= WK_TIMEOUT; } sscape_sleep_flag.flags &= ~WK_SLEEP; }; clear_dma_ff (devc->dma); if ((resid = get_dma_residue (devc->dma)) == 0) { done = 1; } } restore_flags (flags); if (!done) return 0; if (flag & CPF_LAST) { /* * Take the board out of reset */ outb (0x00, PORT (HOST_CTRL)); outb (0x00, PORT (MIDI_CTRL)); temp = sscape_read (devc, GA_HMCTL_REG); temp |= 0x40; sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ /* * Wait until the ODB wakes up */ save_flags (flags); cli (); done = 0; timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) { { unsigned long tlimit; if (1) current_set_timeout (tlimit = jiffies + (1)); else tlimit = (unsigned long) -1; sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { if (jiffies >= tlimit) sscape_sleep_flag.flags |= WK_TIMEOUT; } sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ done = 1; } sscape_write (devc, GA_CDCFG_REG, codec_dma_bits); restore_flags (flags); if (!done) { printk ("SoundScape: The OBP didn't respond after code download\n"); return 0; } save_flags (flags); cli (); done = 0; timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) { { unsigned long tlimit; if (1) current_set_timeout (tlimit = jiffies + (1)); else tlimit = (unsigned long) -1; sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { if (jiffies >= tlimit) sscape_sleep_flag.flags |= WK_TIMEOUT; } sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; } restore_flags (flags); if (!done) { printk ("SoundScape: OBP Initialization failed.\n"); return 0; } printk ("SoundScape board of type %d initialized OK\n", get_board_type (devc)); set_control (devc, CTL_MASTER_VOL, 100); set_control (devc, CTL_SYNTH_VOL, 100); #ifdef SSCAPE_DEBUG3 /* * Temporary debugging aid. Print contents of the registers after * downloading the code. */ { int i; for (i = 0; i < 13; i++) printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); } #endif } return 1; }