// Set a new PWM value for a given pin // Primarily this consists of updating the PWMValue and then // re-sorting the list of active pins by removing and then adding // the pin to the linked list. int32_t SoftPWMServoRawWrite(uint32_t Pin, uint32_t Value, bool PinType) { int i; int32_t intr; // Insert our ISR handler, if it's not already there if (!Initalized) { SoftPWMServoInit(); } // Limit check the inputs if (Value > FrameTime) { Value = FrameTime; } if (Pin > SOFTPWMSERVO_MAX_PINS) { return SOFTPWMSERVO_ERROR; } // And if this pin already has this PWM Value, then don't do anything. if (Value == Chan[ActiveBuffer][Pin].PWMValue) { return SOFTPWMSERVO_OK; } // The easy way to prevent the ISR from doing a buffer swap while // we're in the middle of this is to disable interrupts during // the time that we're mucking with the list. // TODO: Switch to using 3 buffers - one 'active' that the ISR // is currently using, one 'primed' that the mainline code doesn't // touch but has updates and is ready to be swapped before the // next rising edge, and then 'inactive' which is the one we modify // with here. Maybe we wouldn't need to disable interrupts then. intr = disableInterrupts(); // If needed, copy the values from the previously active buffer // into the inactive buffer before we begin work on it. CopyBuffers(); // Always make sure this pin's enabled SoftPWMServoPinEnable(Pin, PinType); // Update the PWM value for this pin Chan[InactiveBuffer][Pin].PWMValue = Value; Chan[InactiveBuffer][Pin].IsServo = PinType; // Remove it from the list Remove(Pin); // And add it back in the list, in the right place (in time) Add(Pin); restoreInterrupts(intr); return SOFTPWMSERVO_OK; }
// Disable the SoftPWM functionality on a particular pin number int32_t SoftPWMServoPinDisable(uint32_t Pin) { int32_t intr; intr = disableInterrupts(); CopyBuffers(); // Pull this one out of the linked list of active channels Remove(Pin); // Mark it as unused Chan[InactiveBuffer][Pin].SetPort = NULL; Chan[InactiveBuffer][Pin].ClearPort = NULL; restoreInterrupts(intr); return SOFTPWMSERVO_OK; }
int mme_user_send_command (mme_user_t *instance, void *arg) { int res = 0; MME_ERROR status = MME_INTERNAL_ERROR; MME_TransformerHandle_t handle; mme_send_command_t *sendCommand = (mme_send_command_t *)arg; mme_user_command_t *intCommand; MME_Command_t* command; mme_user_trans_t *trans; int type, cpuNum, ver, idx; /* Allocate an internal Command desc */ _ICS_OS_ZALLOC(intCommand, sizeof(*intCommand)); if (intCommand == NULL) { status = MME_NOMEM; res = -ENOMEM; goto exit; } /* Get address of embedded MME_Command_t */ command = &intCommand->command; /* Bugzilla 4956 * We set the reference count of this data structure to 2 so that it * will not be freed by on completion until we have done the * copy_to_user() below */ atomic_set(&intCommand->refCount, 2); INIT_LIST_HEAD(&intCommand->list); /* Copy in transformer handle and CommandInfo from userspace */ if (get_user(handle, &(sendCommand->handle)) || get_user(intCommand->userCommand, &(sendCommand->command)) || copy_from_user(command, intCommand->userCommand, sizeof(*command))) { res = -EFAULT; goto errorFreeCmd; } /* Decode the supplied transformer handle */ _MME_DECODE_HDL(handle, type, cpuNum, ver, idx); if (handle == 0 || type != _MME_TYPE_TRANSFORMER || idx >= _MME_TRANSFORMER_INSTANCES) { res = -EINVAL; status = MME_INVALID_HANDLE; goto errorFreeCmd; } /* Get a handle into the local transformer table */ trans = instance->insTrans[idx]; if (trans == NULL) { res = -EINVAL; status = MME_INVALID_HANDLE; goto errorFreeCmd; } if (sizeof(MME_Command_t) != command->StructSize) { res = -EINVAL; status = MME_INVALID_HANDLE; goto errorFreeCmd; } /* Allocate kernel mem for the user private data and copy across */ if (command->Param_p && command->ParamSize) { void* userParam_p = command->Param_p; command->Param_p = _ICS_OS_MALLOC(command->ParamSize); if (NULL == command->Param_p) { status = MME_NOMEM; res = -ENOMEM; goto errorFreeCmd; } if (copy_from_user(command->Param_p, userParam_p, command->ParamSize)) { res = -EFAULT; goto errorFreeParam; } } /* Allocate kernel mem for the AddionalInfo data and copy across */ if (command->CmdStatus.AdditionalInfo_p && command->CmdStatus.AdditionalInfoSize) { /* Need the user address to copy back when the command completes */ intCommand->userAdditionalInfo = command->CmdStatus.AdditionalInfo_p; command->CmdStatus.AdditionalInfo_p = _ICS_OS_MALLOC(command->CmdStatus.AdditionalInfoSize); if (NULL == command->CmdStatus.AdditionalInfo_p) { status = MME_NOMEM; res = -ENOMEM; goto errorFreeParam; } if (copy_from_user(command->CmdStatus.AdditionalInfo_p, intCommand->userAdditionalInfo, command->CmdStatus.AdditionalInfoSize)) { res = -EFAULT; goto errorFree; } } /* Copy in all the data buffer information from userspace */ res = CopyBuffers(command); if (0 != res) { if (-ENOMEM == res) { status = MME_NOMEM; } goto errorFree; } /* * Unless we are using MME_WaitCommand() then we require * the internal Command callback to occur (mme_user_help_callback) */ if (command->CmdEnd != MME_COMMAND_END_RETURN_WAKE) command->CmdEnd = MME_COMMAND_END_RETURN_NOTIFY; /* Call the MME api */ status = MME_SendCommand(handle, command); if (MME_SUCCESS != status) { goto errorFree; } /* Copy the command status structure back - contains command id, state etc */ if (copy_to_user(&(intCommand->userCommand->CmdStatus), &(command->CmdStatus), offsetof(MME_CommandStatus_t, AdditionalInfo_p))) { /* Yuk - need to improve this */ res = -EFAULT; } _ICS_OS_MUTEX_TAKE(&instance->ulock); /* Add to list of currently executing commands */ list_add_tail(&intCommand->list, &trans->issuedCmds); _ICS_OS_MUTEX_RELEASE(&instance->ulock); /* Now call command_free which will * only free the structure when the refCount hits 0 * Command completion will also call it and the winner will * free off the memory */ mme_user_command_free(instance, intCommand); goto exit; errorFree: if (command->CmdStatus.AdditionalInfo_p && command->CmdStatus.AdditionalInfoSize) { _ICS_OS_FREE(command->CmdStatus.AdditionalInfo_p); } errorFreeParam: if (command->Param_p && command->ParamSize) { _ICS_OS_FREE(command->Param_p); } errorFreeCmd: _ICS_OS_FREE(intCommand); exit: /* Write back MME status to caller */ if (put_user(status, &(sendCommand->status))) { res = -EFAULT; } return res; }