📄 tffsdrv26.c
字号:
/******************************************************************************* * * * r e a d _ b i o * * * * This routine handles single 'struct bio' READ operation using scatter * * buffer. * * * * Parameters: * * bio pointer to 'struct bio' to WRITE * * scatter pointer to scatter buffer * * pdisk disk pointer * * * * Returns: * * zero if success otherwise -EIO negative error code * * * *******************************************************************************/staticint read_bio ( struct bio * bio, struct scatter_t * scatter, DeviceInfo * pdisk ){ struct bio_vec * bv; int i, rc = 0; if ((tffs_sg_bufsize == 0) || (tffs_sg_read == FALSE)) { /* we don't use scatter buffer; do one I/O segment at a time */ rc = rw_bio_no_sg (bio, pdisk, READ); } else /* use gather buffer */ { bio_for_each_segment (bv, bio, i) { unsigned int n = bv->bv_len; /* bytes in this I/O segment */ unsigned int ns; char * p, * p2; /* If segment's data resides in high memory, bounce it * down into the temporary low memory buffer. */ p2 = p = __bio_kmap_atomic (bio, i, KM_USER0); for (; n >= scatter->remaining_bytes; ) { /* This I/O segment is larger then number of remaining bytes * in scatter buffer. Copy all these remaining bytes (making * scatter buffer empty), then re-fill scatter buffer from disk. */ if (scatter->remaining_bytes > 0) { memcpy (p, scatter->pcurrent, scatter->remaining_bytes); p += scatter->remaining_bytes; n -= scatter->remaining_bytes; } /* scatter buffer is empty now */ scatter->remaining_bytes = 0; scatter->pcurrent = scatter->buf; /* end of this request ? */ if ((ns = _MIN(scatter->sectors, (tffs_sg_bufsize >> 9))) == 0) break; /* re-fill scatter buffer from disk */ if( TffsRead (pdisk, scatter->buf, scatter->start_sector, ns) == 0 ) rc = -EIO; /* I/O error */ scatter->remaining_bytes = (ns << 9); scatter->sectors -= ns; scatter->start_sector += ns; } /* Remaining part of this segment can be entirely taken * from the scatter buffer. */ if (n > 0) { memcpy (p, scatter->pcurrent, n); scatter->pcurrent += n; scatter->remaining_bytes -= n; } __bio_kunmap_atomic (p2, KM_USER0); } } return rc;}/******************************************************************************* * * * r w _ b i o _ n o _ s g * * * * This routine handles single 'struct bio' without using scatter/gather * * buffers. It issues TrueFFS I/O call for each segment of this 'struct bio'. * * * * Parameters: * * bio pointer to 'struct bio' to handle * * pdisk disk pointer * * rw READ or WRITE * * * * Returns: * * zero if success otherwise -EIO negative error code * * * *******************************************************************************/staticint rw_bio_no_sg ( struct bio * bio, DeviceInfo * pdisk, int rw ){ sector_t sector = bio->bi_sector; /* starting disk sector for this bio */ struct bio_vec * bv; char * p; int i, rc = 0; unsigned int ns; bio_for_each_segment (bv, bio, i) { if ((ns = (bv->bv_len >> 9)) > 0) /* sectors in this segment */ { /* If segment's data resides in high memory, bounce it * down into temporary low memory buffer. */ p = __bio_kmap_atomic (bio, i, KM_USER0); if (rw == READ) { if( TffsRead (pdisk, p, sector, ns) == 0 ) rc = -EIO; /* I/O error */ } else { if( TffsWrite (pdisk, p, sector, ns) == 0 ) rc = -EIO; /* I/O error */ } __bio_kunmap_atomic (p, KM_USER0); sector += ns; } } return rc;}/******************************************************************************* * * * r e q u e s t s _ t o _ d o * * * * This routine checks if there are any requests in socket's request list. * * * * Parameters: * * psoc socket pointer * * * * Returns: * * FALSE if list is empty, otherwise TRUE * * * *******************************************************************************/staticint requests_to_do ( SocketInfo * psoc ){ unsigned long flags; int rc = FALSE; /* assume list is empty */ spin_lock_irqsave (&psoc->request_list_lock, flags); if( !list_empty(&psoc->requestsList) ) rc = TRUE; spin_unlock_irqrestore (&psoc->request_list_lock, flags); return rc;}/******************************************************************************* * * * t f f s _ s u s p e n d * * * * This routine is intended to be called by various Linux Power Managers to * * power down all DiskOnChip devices when system goes into powerdown mode. * * * * Parameters: none * * * * Returns: void * * * *******************************************************************************/void tffs_suspend (void){ SocketInfo * psoc; int i; for (i = 0; i < FL_SOCKETS; i++) { psoc = &tffsInfo.sockets[i]; if (psoc->fFound == 0) continue; /* Tell I/O thread to finish all outstanding I/O requests, put * up psoc->threadSemaphore (we'll wait for it), and exit. */ psoc->io_thread_state = 2; /* in case socket's I/O thread is currently sleeping, wake it up */ wake_up (&psoc->waitQueueHead); /* wait for I/O thread to exit */ down_interruptible (&psoc->threadSemaphore); /* tell TrueFFS to power down DiskOnChip */ TffsSuspend (psoc); } /* disable DiskOnChip interrupts */ if (tffs_irq >= 0) { tffs_irq_disable (TRUE); }}/******************************************************************************* * * * t f f s _ r e s u m e * * * * This routine is intended to be called by various Linux Power Managers to * * power up all DiskOnChip devices when system comes up from powerdown mode. * * * * Parameters: none * * * * Returns: void * * * *******************************************************************************/void tffs_resume (void){ SocketInfo * psoc; int i; /* We are doing 'resume' after previous power 'suspend', not * full scale board initialization, hence TRUE flag below. */ tffsarch_init (TRUE); /* enable DiskOnChip interrupts */ if (tffs_irq >= 0) { tffs_irq_enable (TRUE); } for (i = 0; i < FL_SOCKETS; i++) { psoc = &tffsInfo.sockets[i]; if (psoc->fFound == 0) continue; /* Tell TrueFFS to power up DiskOnChip. This call takes around 20 * milliseconds (DiskOnChip driver will not yield CPU during this time). */ TffsResume (psoc); /* restore multi-sector poleld I/O mode in DiskOnChip h3 devices */ TffsSetPIO (psoc); /* tell I/O thread to put up psoc->threadSemaphore when it starts */ psoc->io_thread_state = 2; /* start I/O thread */ kernel_thread (socket_io_thread, (void *)psoc, 0); /* wait for I/O thread to get running */ down_interruptible (&psoc->threadSemaphore); }}#ifdef CONFIG_PROC_FS/******************************************************************************* * * * p r o c f s _ r e g i s t e r * * * * Create disk's entry in /proc/<module-name>. * * * * Parameters: * * * * pdisk disk pointer * * * * Returns: zero if success otherwise negative error code. * * * *******************************************************************************/staticint /* __init */ procfs_register ( DeviceInfo * pdisk ){ char name[] = "a"; name[0] += (char)(pdisk->diskNo); if ((pdisk->pProcFile = create_proc_entry(name, 0, tffsInfo.pProcDir)) == NULL) { PrintkWarning("Can't create /proc/tffs/%s", name); return -EBUSY; } pdisk->pProcFile->read_proc = procfs_read; pdisk->pProcFile->write_proc = procfs_write; pdisk->pProcFile->data = pdisk; return 0;}/******************************************************************************* * * * p r o c f s _ u n r e g i s t e r * * * * Delete disk's entry in /proc/<module-name>. * * * * Parameters: * * * * pdisk disk pointer * * * * Returns: always zero (success). * * * ***************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -