static void akm8975_ecs_close_done(struct akm8975_data *akm) { FUNCDBG("called"); mutex_lock(&akm->flags_lock); mv_flag = 1; mutex_unlock(&akm->flags_lock); }
static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { struct grtm_priv *pDev; struct drvmgr_dev *dev; FUNCDBG(); if ( drvmgr_get_dev(&grtm_rmap_drv_info.general, minor, &dev) ) { return RTEMS_INVALID_NUMBER; } pDev = (struct grtm_priv *)dev->priv; if ( pDev->running ){ grtm_stop(pDev); pDev->running = 0; } /* Reset core */ grtm_hw_reset(pDev); /* Clear descriptor area just for sure */ MEMSET(pDev, pDev->bds, 0, 0x400); /* Mark not open */ pDev->open = 0; return RTEMS_SUCCESSFUL; }
static int akm_aot_release(struct inode *inode, struct file *file) { FUNCDBG("called"); atomic_set(&open_flag, 0); wake_up(&open_wq); return 0; }
static int akmd_release(struct inode *inode, struct file *file) { struct akm8975_data *akm = file->private_data; FUNCDBG("called"); akm8975_ecs_close_done(akm); return 0; }
static irqreturn_t akm8975_interrupt(int irq, void *dev_id) { struct akm8975_data *akm = dev_id; FUNCDBG("called"); complete(&akm->data_ready); return IRQ_HANDLED; }
static int akm_aot_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *) arg; short flag; struct akm8975_data *akm = file->private_data; FUNCDBG("called"); switch (cmd) { case ECS_IOCTL_APP_SET_MVFLAG: if (copy_from_user(&flag, argp, sizeof(flag))) return -EFAULT; if (flag < 0 || flag > 1) return -EINVAL; break; case ECS_IOCTL_APP_SET_DELAY: if (copy_from_user(&flag, argp, sizeof(flag))) return -EFAULT; break; default: break; } mutex_lock(&akm->flags_lock); switch (cmd) { case ECS_IOCTL_APP_SET_MVFLAG: mv_flag = flag; break; case ECS_IOCTL_APP_GET_MVFLAG: flag = mv_flag; break; case ECS_IOCTL_APP_SET_DELAY: akmd_delay = flag; break; case ECS_IOCTL_APP_GET_DELAY: flag = akmd_delay; break; default: return -ENOTTY; } mutex_unlock(&akm->flags_lock); switch (cmd) { case ECS_IOCTL_APP_GET_MVFLAG: case ECS_IOCTL_APP_GET_DELAY: if (copy_to_user(argp, &flag, sizeof(flag))) return -EFAULT; break; default: break; } return 0; }
static int akmd_open(struct inode *inode, struct file *file) { int err = 0; FUNCDBG("called"); err = nonseekable_open(inode, file); if (err) return err; file->private_data = akmd_data; return 0; }
static rtems_device_driver grtm_open( rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { struct grtm_priv *pDev; struct drvmgr_dev *dev; FUNCDBG(); if ( drvmgr_get_dev(&grtm_rmap_drv_info.general, minor, &dev) ) { DBG("Wrong minor %d\n", minor); return RTEMS_INVALID_NUMBER; } pDev = (struct grtm_priv *)dev->priv; /* Wait until we get semaphore */ if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){ return RTEMS_INTERNAL_ERROR; } /* Is device in use? */ if ( pDev->open ){ rtems_semaphore_release(grtm_dev_sem); return RTEMS_RESOURCE_IN_USE; } /* Mark device taken */ pDev->open = 1; rtems_semaphore_release(grtm_dev_sem); DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev); /* Set defaults */ pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */ pDev->config.blocking = 0; /* polling mode */ pDev->running = 0; /* not in running mode yet */ memset(&pDev->config,0,sizeof(pDev->config)); /* The core has been reset when we execute here, so it is possible * to read out what HW is implemented from core. */ grtm_hw_get_implementation(pDev, &pDev->hw_avail); /* Get default modes */ grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail); return RTEMS_SUCCESSFUL; }
static int __devexit akm8975_remove(struct i2c_client *client) { struct akm8975_data *akm = i2c_get_clientdata(client); FUNCDBG("called"); gpio_free(irq_to_gpio(client->irq)); free_irq(client->irq, NULL); input_unregister_device(akm->input_dev); misc_deregister(&akmd_device); misc_deregister(&akm_aot_device); akm8975_power_off(akm); kfree(akm); return 0; }
static int akm_aot_open(struct inode *inode, struct file *file) { int ret = -1; FUNCDBG("called"); if (atomic_cmpxchg(&open_flag, 0, 1) == 0) { wake_up(&open_wq); ret = 0; } ret = nonseekable_open(inode, file); if (ret) return ret; file->private_data = akmd_data; return ret; }
static void akm8975_ecs_report_value(struct akm8975_data *akm, int *rbuf) { struct akm8975_data *data = i2c_get_clientdata(akm->this_client); FUNCDBG("called"); #if AK8975DRV_DATA_DBG pr_info("Magnetic: x = %d , y = %d , z = %d \n\n", rbuf[0], rbuf[1], rbuf[2]); #endif mutex_lock(&akm->flags_lock); if (mv_flag) { input_report_abs(data->input_dev, ABS_HAT0X, rbuf[0]); input_report_abs(data->input_dev, ABS_HAT0Y, rbuf[1]); input_report_abs(data->input_dev, ABS_BRAKE, rbuf[2]); } mutex_unlock(&akm->flags_lock); input_sync(data->input_dev); }
/* * Helper function to write to the I2C device's registers. */ static int akm8975_i2c_txdata(struct akm8975_data *akm, u8 reg, u8 val) { struct i2c_msg msg; u8 w_data[2]; int ret = 0; w_data[0] = reg; w_data[1] = val; msg.addr = akm->this_client->addr; msg.flags = 0; msg.len = 2; msg.buf = w_data; FUNCDBG("called"); ret = i2c_transfer(akm->this_client->adapter, &msg, 1); if (ret < 0) { dev_err(&akm->this_client->dev, "Write to device fails status %x\n", ret); } return ret; }
int akm8975_probe(struct i2c_client *client, const struct i2c_device_id *devid) { struct akm8975_data *akm; int err; FUNCDBG("called"); if (client->dev.platform_data == NULL) { dev_err(&client->dev, "platform data is NULL. exiting.\n"); err = -ENODEV; goto exit_platform_data_null; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "platform data is NULL. exiting.\n"); err = -ENODEV; goto exit_check_functionality_failed; } akm = kzalloc(sizeof(struct akm8975_data), GFP_KERNEL); if (!akm) { dev_err(&client->dev, "failed to allocate memory for module data\n"); err = -ENOMEM; goto exit_alloc_data_failed; } akm->pdata = client->dev.platform_data; mutex_init(&akm->flags_lock); init_completion(&akm->data_ready); i2c_set_clientdata(client, akm); err = akm8975_power_on(akm); if (err < 0) goto exit_power_on_failed; akm8975_init_client(client); akm->this_client = client; akmd_data = akm; akm->input_dev = input_allocate_device(); if (!akm->input_dev) { err = -ENOMEM; dev_err(&akm->this_client->dev, "input device allocate failed\n"); goto exit_input_dev_alloc_failed; } set_bit(EV_ABS, akm->input_dev->evbit); /* x-axis of raw magnetic vector */ input_set_abs_params(akm->input_dev, ABS_HAT0X, -4096, 4095, 0, 0); /* y-axis of raw magnetic vector */ input_set_abs_params(akm->input_dev, ABS_HAT0Y, -4096, 4095, 0, 0); /* z-axis of raw magnetic vector */ input_set_abs_params(akm->input_dev, ABS_BRAKE, -4096, 4095, 0, 0); akm->input_dev->name = "compass"; err = input_register_device(akm->input_dev); if (err) { pr_err("akm8975_probe: Unable to register input device: %s\n", akm->input_dev->name); goto exit_input_register_device_failed; } err = misc_register(&akmd_device); if (err) { pr_err("akm8975_probe: akmd_device register failed\n"); goto exit_misc_device_register_failed; } err = misc_register(&akm_aot_device); if (err) { pr_err("akm8975_probe: akm_aot_device register failed\n"); goto exit_misc_device_register_failed; } err = device_create_file(&client->dev, &dev_attr_akm_ms1); #ifdef CONFIG_HAS_EARLYSUSPEND akm->early_suspend.suspend = akm8975_early_suspend; akm->early_suspend.resume = akm8975_early_resume; register_early_suspend(&akm->early_suspend); #endif return 0; exit_misc_device_register_failed: exit_input_register_device_failed: input_free_device(akm->input_dev); exit_input_dev_alloc_failed: akm8975_power_off(akm); exit_power_on_failed: kfree(akm); exit_alloc_data_failed: exit_check_functionality_failed: exit_platform_data_null: return err; }
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 = ioarg->buffer; int status; struct grtm_ioc_config *cfg; struct grtm_ioc_hw_status *hwregs; IRQ_GLOBAL_PREPARE(oldLevel); 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_rmap_drv_info.general, minor, &dev) ) { return RTEMS_INVALID_NUMBER; } pDev = (struct grtm_priv *)dev->priv; if (!ioarg) return RTEMS_INVALID_NAME; 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_rmap", 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; } #warning THIS IOCTL COPY THE REMOTE ADDRESS *(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 */ IRQ_GLOBAL_DISABLE(oldLevel); #warning IMPLEMENT HWREGS HERE IRQ_GLOBAL_ENABLE(oldLevel); 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; } num=0; /* 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. */ rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT); goto trigger_transmission; } 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 */ 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++; rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT); /* 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 = grtm_free_sent(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 = grtm_schedule_ready(pDev,0); pDev->ready_cnt -= num; pDev->scheduled_cnt += num; rtems_semaphore_release(pDev->handling_transmission); 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 */ rtems_semaphore_obtain(pDev->handling_transmission, RTEMS_WAIT, RTEMS_NO_TIMEOUT); do { /* Move sent frames from descriptors to Sent queue. This makes more * descriptors (BDs) available. */ num = grtm_free_sent(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 = grtm_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_tx,RTEMS_WAIT,pDev->config.timeout); if ( ret == RTEMS_TIMEOUT ) { /* do not lock out interrupt handler any more */ rtems_semaphore_release(pDev->handling_transmission); return RTEMS_TIMEOUT; } else if ( ret == RTEMS_SUCCESSFUL ) { /* There might be frames available, go check */ continue; } else { /* any error (driver closed, internal error etc.) */ rtems_semaphore_release(pDev->handling_transmission); return RTEMS_UNSATISFIED; } }else{ /* non-blocking mode, we quit */ chain->head = NULL; chain->tail = NULL; /* do not lock out interrupt handler any more */ rtems_semaphore_release(pDev->handling_transmission); 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); 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 */ rtems_semaphore_release(pDev->handling_transmission); break; default: return RTEMS_NOT_DEFINED; } return RTEMS_SUCCESSFUL; }
static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { FUNCDBG(); return RTEMS_NOT_IMPLEMENTED; }
static int akmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *) arg; char rwbuf[16]; char databuf[RBUFF_SIZE]; int ret = -1; int status; int value[3]; short delay; short mode; struct akm8975_data *akm = file->private_data; FUNCDBG("called"); switch (cmd) { case ECS_IOCTL_READ: case ECS_IOCTL_WRITE: if (copy_from_user(&rwbuf, argp, sizeof(rwbuf))) return -EFAULT; break; case ECS_IOCTL_SET_MODE: if (copy_from_user(&mode, argp, sizeof(mode))) return -EFAULT; break; case ECS_IOCTL_SET_YPR: if (copy_from_user(&value, argp, sizeof(value))) return -EFAULT; break; default: break; } switch (cmd) { case ECS_IOCTL_READ: if ((rwbuf[0] > AK8975_FUSE_ASAZ) || (rwbuf[1] < 1) || (rwbuf[1] > 3)) { pr_err("AKM8975 IOCTL_READ invalid argument: %d, %d\n", (int)rwbuf[0], (int)rwbuf[1]); return -EINVAL; } ret = akm8975_i2c_rxdata(akm, rwbuf[0], rwbuf[1], &rwbuf[2]); if (ret < 0) return ret; break; case ECS_IOCTL_WRITE: if (rwbuf[0] < 2) return -EINVAL; ret = akm8975_i2c_txdata(akm, rwbuf[0], rwbuf[1]); if (ret < 0) return ret; break; case ECS_IOCTL_SET_MODE: ret = akm8975_ecs_set_mode(akm, (char) mode); if (ret < 0) return ret; if (mode == AK8975_MODE_SNG_MEASURE) { /* wait for data to become ready */ ret = wait_for_completion_interruptible_timeout(&akm->data_ready, msecs_to_jiffies(AK8975_MAX_CONVERSION_TIMEOUT)); if (ret < 0) { pr_err("AKM8975 conversion timeout happened\n"); return -EINVAL; } } break; case ECS_IOCTL_GETDATA: ret = akm8975_ecs_get_data(akm, RBUFF_SIZE, databuf); if (ret < 0) return ret; case ECS_IOCTL_SET_YPR: akm8975_ecs_report_value(akm, value); break; case ECS_IOCTL_GET_OPEN_STATUS: wait_event_interruptible(open_wq, (atomic_read(&open_flag) != 0)); status = atomic_read(&open_flag); break; case ECS_IOCTL_GET_CLOSE_STATUS: wait_event_interruptible(open_wq, (atomic_read(&open_flag) == 0)); status = atomic_read(&open_flag); break; case ECS_IOCTL_GET_DELAY: delay = akmd_delay; break; default: FUNCDBG("Unknown cmd\n"); return -ENOTTY; } switch (cmd) { case ECS_IOCTL_READ: if (copy_to_user(argp, &rwbuf[2], rwbuf[1])) return -EFAULT; break; case ECS_IOCTL_GETDATA: if (copy_to_user(argp, &databuf, RBUFF_SIZE)) return -EFAULT; break; case ECS_IOCTL_GET_OPEN_STATUS: case ECS_IOCTL_GET_CLOSE_STATUS: if (copy_to_user(argp, &status, sizeof(status))) return -EFAULT; break; case ECS_IOCTL_GET_DELAY: if (copy_to_user(argp, &delay, sizeof(delay))) return -EFAULT; break; default: break; } return 0; }
static void __exit akm8975_exit(void) { FUNCDBG("AK8975 compass driver: exit\n"); i2c_del_driver(&akm8975_driver); }
static int __init akm8975_init(void) { pr_info("AK8975 compass driver: init\n"); FUNCDBG("AK8975 compass driver: init\n"); return i2c_add_driver(&akm8975_driver); }