static rtems_device_driver graes_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { struct graes_priv *pDev; struct drvmgr_dev *dev; rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; unsigned int *data = ioarg->buffer; int status; struct graes_ioc_config *cfg; struct graes_ioc_hw_status *hwregs; IRQ_GLOBAL_PREPARE(oldLevel); struct graes_list *chain; struct graes_block *curr; struct graes_ioc_hw *hwimpl; struct graes_ioc_stats *stats; struct graes_print_status *ps; int num,ret; FUNCDBG(); if ( drvmgr_get_dev(&graes_drv_info.general, minor, &dev) ) { return RTEMS_INVALID_NUMBER; } pDev = (struct graes_priv *)dev->priv; if (!ioarg) return RTEMS_INVALID_NAME; ioarg->ioctl_return = 0; switch(ioarg->command) { case GRAES_IOC_START: if ( pDev->running ) { return RTEMS_RESOURCE_IN_USE; /* EBUSY */ } if ( (status=graes_start(pDev)) != RTEMS_SUCCESSFUL ){ return status; } /* Register interrupt handler and unmask IRQ at IRQ ctrl */ drvmgr_interrupt_register(dev, 0, "graes", graes_interrupt, pDev); /* Read and write are now open... */ break; case GRAES_IOC_STOP: if ( !pDev->running ) { return RTEMS_RESOURCE_IN_USE; } /* Disable interrupts */ drvmgr_interrupt_unregister(dev, 0, graes_interrupt, pDev); graes_stop(pDev); pDev->running = 0; break; case GRAES_IOC_ISSTARTED: if ( !pDev->running ) { return RTEMS_RESOURCE_IN_USE; } break; case GRAES_IOC_SET_BLOCKING_MODE: if ( (unsigned int)data > GRAES_BLKMODE_BLK ) { return RTEMS_INVALID_NAME; } DBG("GRAES: Set blocking mode: %d\n",(unsigned int)data); pDev->config.blocking = (unsigned int)data; break; case GRAES_IOC_SET_TIMEOUT: DBG("GRAES: Timeout: %d\n",(unsigned int)data); pDev->config.timeout = (rtems_interval)data; break; case GRAES_IOC_SET_CONFIG: cfg = (struct graes_ioc_config *)data; if ( !cfg ) { return RTEMS_INVALID_NAME; } if ( pDev->running ) { return RTEMS_RESOURCE_IN_USE; } pDev->config = *cfg; break; case GRAES_IOC_GET_STATS: stats = (struct graes_ioc_stats *)data; if ( !stats ) { return RTEMS_INVALID_NAME; } memcpy(stats,&pDev->stats,sizeof(struct graes_ioc_stats)); break; case GRAES_IOC_CLR_STATS: memset(&pDev->stats,0,sizeof(struct graes_ioc_stats)); break; case GRAES_IOC_GET_CONFIG: cfg = (struct graes_ioc_config *)data; if ( !cfg ) { return RTEMS_INVALID_NAME; } *cfg = pDev->config; break; case GRAES_IOC_GET_HW_IMPL: hwimpl = (struct graes_ioc_hw *)data; if ( !hwimpl ) { return RTEMS_INVALID_NAME; } *hwimpl = pDev->hw_avail; break; case GRAES_IOC_GET_HW_STATUS: hwregs = (struct graes_ioc_hw_status *)data; if ( !hwregs ) { return RTEMS_INVALID_NAME; } /* We disable interrupt in order to get a snapshot of the registers */ IRQ_GLOBAL_DISABLE(oldLevel); IRQ_GLOBAL_ENABLE(oldLevel); break; case GRAES_IOC_PRINT_STATUS: ps = (struct graes_print_status *)data; graes_printstatus(pDev, ps); break; /* Put a chain of frames at the back of the "Ready frames" queue. This * triggers the driver to put frames from the Ready queue into unused * available descriptors. (Ready -> Scheduled) */ case GRAES_IOC_ENCRYPT: if ( !pDev->running ){ return RTEMS_RESOURCE_IN_USE; } num=0; /* Get pointer to frame chain wished be sent */ chain = (struct graes_list *)ioarg->buffer; if ( !chain ){ /* No new frames to send ==> just trigger hardware * to send previously made ready frames to be sent. */ pDev->handling_transmission = 1; goto trigger_transmission; } if ( !chain->tail || !chain->head ){ return RTEMS_INVALID_NAME; } /* Mark ready frames unsent by clearing GRAES_FLAGS_PROCESSED of all frames */ curr = chain->head; while(curr != chain->tail){ curr->flags = curr->flags & ~(GRAES_FLAGS_PROCESSED|GRRM_FLAGS_ERR); curr = curr->next; num++; } curr->flags = curr->flags & ~(GRAES_FLAGS_PROCESSED|GRRM_FLAGS_ERR); num++; DBG("GRAES_ENCRYPT: head: 0x%x, tail: 0x%x num: %d\n",chain->head,chain->tail, num); pDev->handling_transmission = 1; /* 1. Put frames into ready queue * (New Frames->READY) */ if ( pDev->ready.head ){ /* Frames already on ready queue (no free descriptors previously) ==> * Put frames at end of ready queue */ pDev->ready.tail->next = chain->head; pDev->ready.tail = chain->tail; chain->tail->next = NULL; }else{ /* All frames is put into the ready queue for later processing */ pDev->ready.head = chain->head; pDev->ready.tail = chain->tail; chain->tail->next = NULL; } pDev->ready_cnt += num; /* Added 'num' frames to ready queue */ trigger_transmission: /* 2. Free used descriptors and put the sent frame into the "Sent queue" * (SCHEDULED->SENT) */ num = graes_free_encrypted(pDev); pDev->scheduled_cnt -= num; pDev->sent_cnt += num; /* 3. Use all available free descriptors there are frames for * in the ready queue. * (READY->SCHEDULED) */ num = graes_schedule_ready(pDev,0); pDev->ready_cnt -= num; pDev->scheduled_cnt += num; pDev->handling_transmission = 0; break; /* Take all available sent frames from the "Sent frames" queue. * If no frames has been sent, the thread may get blocked if in blocking * mode. The blocking mode is not available if driver is not in running mode. * * Note this ioctl may return success even if the driver is not in STARTED mode. * This is because in case of a error (link error of similar) and the driver switch * from START to STOP mode we must still be able to get our frames back. * * Note in case the driver fails to send a frame for some reason (link error), * the sent flag is set to 0 indicating a failure. * */ case GRAES_IOC_RECLAIM: /* Get pointer to were to place reaped chain */ chain = (struct graes_list *)ioarg->buffer; if ( !chain ){ return RTEMS_INVALID_NAME; } /* Lock out interrupt handler */ pDev->handling_transmission = 1; do { /* Move sent frames from descriptors to Sent queue. This makes more * descriptors (BDs) available. */ num = graes_free_encrypted(pDev); pDev->scheduled_cnt -= num; pDev->sent_cnt += num; if ( pDev->running ){ /* Fill descriptors with as many frames from the ready list * as possible. */ num = graes_schedule_ready(pDev,0); pDev->ready_cnt -= num; pDev->scheduled_cnt += num; } /* Are there any frames on the sent queue waiting to be * reclaimed? */ if ( !pDev->sent.head ){ /* No frames to reclaim - no frame in sent queue. * Instead we block thread until frames have been sent * if in blocking mode. */ if ( pDev->running && pDev->config.blocking ){ ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,pDev->config.timeout); if ( ret == RTEMS_TIMEOUT ) { pDev->handling_transmission = 0; return RTEMS_TIMEOUT; } else if ( ret == RTEMS_SUCCESSFUL ) { /* There might be frames available, go check */ continue; } else { /* any error (driver closed, internal error etc.) */ pDev->handling_transmission = 0; return RTEMS_UNSATISFIED; } }else{ /* non-blocking mode, we quit */ chain->head = NULL; chain->tail = NULL; /* do not lock out interrupt handler any more */ pDev->handling_transmission = 0; return RTEMS_TIMEOUT; } }else{ /* Take all sent framess from sent queue to userspace queue */ chain->head = pDev->sent.head; chain->tail = pDev->sent.tail; chain->tail->next = NULL; /* Just for sure */ /* Mark no Sent */ graes_list_clr(&pDev->sent); DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail); break; } }while(1); /* do not lock out interrupt handler any more */ pDev->handling_transmission = 0; break; default: return RTEMS_NOT_DEFINED; } return RTEMS_SUCCESSFUL; }
static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { struct grtm_priv *pDev; struct drvmgr_dev *dev; rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; unsigned int *data; int status; struct grtm_ioc_config *cfg; struct grtm_ioc_hw_status *hwregs; struct grtm_list *chain; struct grtm_frame *curr; struct grtm_ioc_hw *hwimpl; struct grtm_ioc_stats *stats; int num,ret; FUNCDBG(); if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) { return RTEMS_INVALID_NUMBER; } pDev = (struct grtm_priv *)dev->priv; if (!ioarg) return RTEMS_INVALID_NAME; data = ioarg->buffer; ioarg->ioctl_return = 0; switch(ioarg->command) { case GRTM_IOC_START: if ( pDev->running ) { return RTEMS_RESOURCE_IN_USE; /* EBUSY */ } if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){ return status; } /* Register ISR & Enable interrupt */ drvmgr_interrupt_register(dev, 0, "grtm", grtm_interrupt, pDev); /* Read and write are now open... */ break; case GRTM_IOC_STOP: if ( !pDev->running ) { return RTEMS_RESOURCE_IN_USE; } /* Disable interrupts */ drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev); grtm_stop(pDev); pDev->running = 0; break; case GRTM_IOC_ISSTARTED: if ( !pDev->running ) { return RTEMS_RESOURCE_IN_USE; } break; case GRTM_IOC_SET_BLOCKING_MODE: if ( (unsigned int)data > GRTM_BLKMODE_BLK ) { return RTEMS_INVALID_NAME; } DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data); pDev->config.blocking = (unsigned int)data; break; case GRTM_IOC_SET_TIMEOUT: DBG("GRTM: Timeout: %d\n",(unsigned int)data); pDev->config.timeout = (rtems_interval)data; break; case GRTM_IOC_SET_CONFIG: cfg = (struct grtm_ioc_config *)data; if ( !cfg ) { return RTEMS_INVALID_NAME; } if ( pDev->running ) { return RTEMS_RESOURCE_IN_USE; } pDev->config = *cfg; break; case GRTM_IOC_GET_STATS: stats = (struct grtm_ioc_stats *)data; if ( !stats ) { return RTEMS_INVALID_NAME; } memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats)); break; case GRTM_IOC_CLR_STATS: memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats)); break; case GRTM_IOC_GET_CONFIG: cfg = (struct grtm_ioc_config *)data; if ( !cfg ) { return RTEMS_INVALID_NAME; } *cfg = pDev->config; break; case GRTM_IOC_GET_OCFREG: if ( !pDev->hw_avail.ocf ) { /* Hardware does not implement the OCF register */ return RTEMS_NOT_DEFINED; } if ( !data ) { return RTEMS_INVALID_NAME; } *(unsigned int **)data = (unsigned int *)&pDev->regs->ocf; break; case GRTM_IOC_GET_HW_IMPL: hwimpl = (struct grtm_ioc_hw *)data; if ( !hwimpl ) { return RTEMS_INVALID_NAME; } *hwimpl = pDev->hw_avail; break; case GRTM_IOC_GET_HW_STATUS: hwregs = (struct grtm_ioc_hw_status *)data; if ( !hwregs ) { return RTEMS_INVALID_NAME; } /* We disable interrupt in order to get a snapshot of the registers */ /* TODO: implement hwregs */ break; /* Put a chain of frames at the back of the "Ready frames" queue. This * triggers the driver to put frames from the Ready queue into unused * available descriptors. (Ready -> Scheduled) */ case GRTM_IOC_SEND: if ( !pDev->running ){ return RTEMS_RESOURCE_IN_USE; } /* Get pointer to frame chain wished be sent */ chain = (struct grtm_list *)ioarg->buffer; if ( !chain ){ /* No new frames to send ==> just trigger hardware * to send previously made ready frames to be sent. * If someone else is processing the DMA we igore the * request. */ if (grtm_request_txlock(pDev, 0)) { grtm_tx_process(pDev); grtm_release_txlock(pDev); } break; } if ( !chain->tail || !chain->head ){ return RTEMS_INVALID_NAME; } DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail); /* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */ num = 0; curr = chain->head; while(curr != chain->tail){ curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR); curr = curr->next; num++; } curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR); num++; /* wait until we get the device lock */ grtm_request_txlock(pDev, 1); /* 1. Put frames into ready queue * (New Frames->READY) */ if ( pDev->ready.head ){ /* Frames already on ready queue (no free descriptors previously) ==> * Put frames at end of ready queue */ pDev->ready.tail->next = chain->head; pDev->ready.tail = chain->tail; chain->tail->next = NULL; }else{ /* All frames is put into the ready queue for later processing */ pDev->ready.head = chain->head; pDev->ready.tail = chain->tail; chain->tail->next = NULL; } pDev->ready_cnt += num; /* Added 'num' frames to ready queue */ /* 2. SCHEDULED->SENT * 3. READY->SCHEDULED */ grtm_tx_process(pDev); grtm_release_txlock(pDev); break; /* Take all available sent frames from the "Sent frames" queue. * If no frames has been sent, the thread may get blocked if in blocking * mode. The blocking mode is not available if driver is not in running mode. * * Note this ioctl may return success even if the driver is not in STARTED mode. * This is because in case of a error (link error of similar) and the driver switch * from START to STOP mode we must still be able to get our frames back. * * Note in case the driver fails to send a frame for some reason (link error), * the sent flag is set to 0 indicating a failure. * */ case GRTM_IOC_RECLAIM: /* Get pointer to were to place reaped chain */ chain = (struct grtm_list *)ioarg->buffer; if ( !chain ){ return RTEMS_INVALID_NAME; } /* Lock out interrupt handler */ grtm_request_txlock(pDev, 1); do { /* Process descriptor table and populate with new * buffers: * * SCHEDULED->SENT * * READY->SCHEDULED */ grtm_tx_process(pDev); /* Are there any frames on the sent queue waiting to be * reclaimed? */ if ( !pDev->sent.head ){ /* No frames to reclaim - no frame in sent queue. * Instead we block thread until frames have been sent * if in blocking mode. */ if ( pDev->running && pDev->config.blocking ){ ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout); if ( ret == RTEMS_TIMEOUT ) { grtm_release_txlock(pDev); return RTEMS_TIMEOUT; } else if ( ret == RTEMS_SUCCESSFUL ) { /* There might be frames available, go check */ continue; } else { /* any error (driver closed, internal error etc.) */ grtm_release_txlock(pDev); return RTEMS_UNSATISFIED; } }else{ /* non-blocking mode, we quit */ chain->head = NULL; chain->tail = NULL; /* do not lock out interrupt handler any more */ grtm_release_txlock(pDev); return RTEMS_TIMEOUT; } }else{ /* Take all sent framess from sent queue to userspace queue */ chain->head = pDev->sent.head; chain->tail = pDev->sent.tail; chain->tail->next = NULL; /* Just for sure */ /* Mark no Sent */ grtm_list_clr(&pDev->sent); pDev->sent_cnt = 0; DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail); break; } }while(1); /* do not lock out interrupt handler any more */ grtm_release_txlock(pDev); break; default: return RTEMS_NOT_DEFINED; } return RTEMS_SUCCESSFUL; }