#define MODULE #define __KERNEL__ #include #include #include #include #include #include #include #include #include #define ROBARM_DEV_MAJOR 23 #define ROBARM_IDENT "Robot Arm Device Driver" #define ROBARM "RobotArm" #define MAX_SESSIONS 1 #define NUM_MOTORS 4 #define BASE 0 #define BICEP 1 #define FOREARM 2 #define CLAW 3 atomic_t mutex; int sessions; /** * Keeps track of the position, direction, and movement of * each motor. */ struct motor_status{ int on; //on = 1, off = 0 int dir; //right = 0, left = 1, up = 2, down = 3 int pos; }; /* * Motor numbers for commands * * base == 0 * bicep == 1 * forearm == 2 * claw == 3 */ struct motor_status baseMotorStatus; struct motor_status bicepMotorStatus; struct motor_status forearmMotorStatus; struct motor_status clawMotorStatus; struct motor_status motorStatuss[NUM_MOTORS]; // Interrupt handlers void forearm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { if (forearmMotorStatus.dir == 1) { forearmMotorStatus.pos += 1; } else { forearmMotorStatus.pos -= 1; } } void bicep_interrupt(int irq, void *dev_id, struct pt_regs *reqs) { if (bicepMotorStatus.dir == 1) { bicepMotorStatus.pos += 1; } else { bicepMotorStatus.pos -= 1; } } void base_interrupt(int irq, void *dev_id, struct pt_regs *reqs) { if (baseMotorStatus.dir == 1) { baseMotorStatus.pos += 1; } else { baseMotorStatus.pos -= 1; } } /*void claw_interrupt(int irq, void *dev_id, struct pt_regs *reqs) { if (clawMotorStatus.dir == 1) { clawMotorStatus.pos = 600; printk("<1>dir == 1\n"); } else { clawMotorStatus.pos = 0; printk("<1>dir == 0\n"); } }*/ /** * Registers all the interrupts. */ void registerInterrupts() { if (request_irq(IRQ_GPIO9, forearm_interrupt, 0, "forearm_interrupt", NULL)) { printk("<1>Couldn't register interrupt\n"); } if (request_irq(IRQ_GPIO_11_27(11), bicep_interrupt, 0, "bicep_interrupt", NULL)) { printk("<1>Couldn't register bicep interrupt\n"); } if (request_irq(IRQ_GPIO_11_27(13), base_interrupt, 0, "base_interrupt", NULL)) { printk("<1>Couldn't register base interrupt\n"); } /*if (request_irq(IRQ_GPIO8, claw_interrupt, 0, "claw_interrupt", NULL)) { printk("<1>Couldn't register claw interrupt\n"); }*/ } /** * Un-registers all interrupts */ void unregisterInterrupts() { free_irq(IRQ_GPIO9, NULL); //free_irq(IRQ_GPIO8, NULL); free_irq(IRQ_GPIO_11_27(11), NULL); free_irq(IRQ_GPIO_11_27(13), NULL); } /** * the order that the motors status' will be checked: base, bicep, forearm, claw. * the order that each motors status' will be checked: on, direction, position. * * This puts an array of 12 integers in the supplied char buffer. The 12 integers * correspond to the motor's status. */ static ssize_t arm_read(struct file* file, char* buffer, size_t count, loff_t* ppos) { int intBuf[12]; char *charBuf; if (count != (12 * sizeof(int))) { return 1; } intBuf[0] = baseMotorStatus.on; intBuf[1] = baseMotorStatus.dir; intBuf[2] = baseMotorStatus.pos; intBuf[3] = bicepMotorStatus.on; intBuf[4] = bicepMotorStatus.dir; intBuf[5] = bicepMotorStatus.pos; intBuf[6] = forearmMotorStatus.on; intBuf[7] = forearmMotorStatus.dir; intBuf[8] = forearmMotorStatus.pos; intBuf[9] = clawMotorStatus.on; intBuf[10] = clawMotorStatus.dir; intBuf[11] = clawMotorStatus.pos; charBuf = (char*) intBuf; //copy from user space to kernel space. if return value is > 0, indicate a failure. if (__copy_to_user(buffer, charBuf, count) > 0) { return 0; } else { return count; } } /** * Sends a command to the Evil Robot Arm using GPIO pins. */ int execute_motor_command(int motor, int on, int direction){ switch (motor) { case BASE: GPSR |= GPIO_GPIO4; GPSR |= GPIO_GPIO5; baseMotorStatus.dir = direction; baseMotorStatus.on = on; break; case BICEP: GPCR |= GPIO_GPIO4; GPSR |= GPIO_GPIO5; bicepMotorStatus.dir = direction; bicepMotorStatus.on = on; break; case FOREARM: GPSR |= GPIO_GPIO4; GPCR |= GPIO_GPIO5; forearmMotorStatus.dir = direction; forearmMotorStatus.on = on; break; case CLAW: GPCR |= GPIO_GPIO4; GPCR |= GPIO_GPIO5; clawMotorStatus.dir = direction; clawMotorStatus.on = on; break; default: return 0; } if (on == 1) { GPSR |= GPIO_GPIO6; } else { GPCR |= GPIO_GPIO6; } if (direction == 1) { GPSR |= GPIO_GPIO7; } else { GPCR |= GPIO_GPIO7; } return 1; } /** * Takes a command in the form of , or it takes a begin or end session * command, or it resets the session count. */ static ssize_t arm_write(struct file* file, const char* buffer, size_t count, loff_t *ppos) { int motor, on, direction; // first check if this is a session-oriented command if (strncmp(buffer, "start session", count) == 0) { //if (atomic_dec_and_test(&mutex) > 0) { if (sessions < MAX_SESSIONS) { sessions++; registerInterrupts(); return count; } else { //atomic_inc(&mutex); return -1; } } if (strncmp(buffer, "end session", count) == 0) { //atomic_inc(&mutex); sessions--; unregisterInterrupts(); return count; } if (strncmp(buffer, "reset session count", count) == 0) { sessions = 0; return count; } // if it's not a session command, then it better only be 3 characters // (a motor, a direction, and on or off). if(count != 3){ printk("<1>Error [count != 3] [%s]", buffer); return count; } //motor status of base, bicep, forearm, or claw motor motor = buffer[0] - '0'; on = buffer[1] - '0'; direction = buffer[2] - '0'; if (execute_motor_command(/*BASE, 1, 1*/motor, on, direction) == 0) { // failure return 0; } else { // success return count; } } int arm_open(struct inode* inode, struct file* file) { return 0; } int arm_release(struct inode* inode, struct file* file) { return 0; } static struct file_operations robarm_file_ops = {NULL, NULL, arm_read, arm_write, NULL, NULL, NULL, NULL, arm_open, NULL, arm_release, NULL, NULL}; int init_module(void) { int i; if (register_chrdev(ROBARM_DEV_MAJOR, ROBARM, &robarm_file_ops)) { printk("<1>%s, cannot register major device %d\n", ROBARM_IDENT, ROBARM_DEV_MAJOR); return 1; } /* * Remember to set S2, S3, S4, and S5 on DIP Switch S3. This controls * the GPIO buffer directions and output enables. * * Let's use port 1 for output and port 2 for input. */ //// begin initialize GPIO /////////////////////////////////////////// // set port 1 on the CerfBoard to be output GPDR |= 0x000000FF; // set port 2 for input GPDR &= 0xFFFF00FF; /* * Port 1 output * * baseMotor GPIO4 * bicepMotro GPIO5 * forearmMotor GPIO6 * clawMotor GPIO7 */ /* * Port 2 input * * clawButton GPIO8 * forearmIR GPIO9 * forearmButton GPIO10 * * bicepIR GPIO11 * bicepButton GPIO12 * baseIR GPIO13 * baseButton GPIO14 */ /* * IR interrupts will be set on high to low transitions. * clawButton interrupts will be set on low to high transitions. * all other Buttons will interrupt on high to low transitions. */ set_GPIO_IRQ_edge(GPIO_GPIO8, GPIO_RISING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO9, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO10, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO11, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO12, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO13, GPIO_FALLING_EDGE); set_GPIO_IRQ_edge(GPIO_GPIO14, GPIO_FALLING_EDGE); //// end initialize GPIO ///////////////////////////////////////////// // initialize the mutex sessions = 0; // initialize the motor status' motorStatuss[0] = baseMotorStatus; motorStatuss[1] = bicepMotorStatus; motorStatuss[2] = forearmMotorStatus; motorStatuss[3] = clawMotorStatus; for (i = 0; i < NUM_MOTORS; i++) { motorStatuss[i].on = 0; motorStatuss[i].dir = 0; motorStatuss[i].pos = 0; } printk("<1>%s, Done.\n", ROBARM_IDENT); return 0; } void cleanup_module(void) { printk("<1>Goodbye un-cruel world\n"); unregister_chrdev (ROBARM_DEV_MAJOR, ROBARM); }