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_write (int dev, struct fileinfo *file, const char *buf, int count) { unsigned long flags; if (count < 4) { printk ("PATMGR%d: Write count < 4\n", dev); return -(EIO); } memcpy_fromfs ((char *) mbox[dev], &(buf)[0], 4); if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE) { int tmp_dev; tmp_dev = ((unsigned short *) mbox[dev])[2]; if (tmp_dev != dev) return -(ENXIO); return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev], buf, 4, count, 1); } if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid write count\n", dev); return -(EIO); } /* * If everything went OK, there should be a preallocated buffer in the * mailbox and a client waiting. */ save_flags (flags); cli (); if (mbox[dev] && !msg_direction[dev]) { memcpy_fromfs (&((char *) mbox[dev])[4], &(buf)[4], count - 4); msg_direction[dev] = S_TO_A; if ((appl_wait_flag.flags & WK_SLEEP)) { { appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } } restore_flags (flags); return count; }
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; }
void pmgr_release (int dev) { if (mbox[dev]) /* * Killed in action. Inform the client */ { mbox[dev]->key = PM_ERROR; mbox[dev]->parm1 = -(EIO); if ((appl_wait_flag.flags & WK_SLEEP)) { appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } pmgr_opened[dev] = 0; }
void sscapeintr (int irq, void *dev_id, struct pt_regs *dummy) { unsigned char bits, tmp; static int debug = 0; bits = sscape_read (devc, GA_INTSTAT_REG); if ((sscape_sleep_flag.flags & WK_SLEEP)) { { sscape_sleep_flag.flags = WK_WAKEUP; module_wake_up (&sscape_sleeper); }; } if (bits & 0x02) /* Host interface interrupt */ { printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); } #if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) if (bits & 0x01) { mpuintr (irq, NULL, NULL); if (debug++ > 10) /* Temporary debugging hack */ { sscape_write (devc, GA_INTENA_REG, 0x00); /* Disable all interrupts */ } } #endif /* * Acknowledge interrupts (toggle the interrupt bits) */ tmp = sscape_read (devc, GA_INTENA_REG); sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1)); }
/* 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 }