ssize_t nidas_circbuf_read_nowait(struct file *filp, char __user* buf, size_t count, struct dsm_sample_circ_buf* cbuf, struct sample_read_state* state) { size_t countreq = count; struct dsm_sample* insamp; size_t bytesLeft = state->bytesLeft; char* samplePtr = state->samplePtr; size_t n; for ( ; count; ) { if ((n = min(bytesLeft,count)) > 0) { if (copy_to_user(buf,samplePtr,n)) return -EFAULT; bytesLeft -= n; count -= n; samplePtr += n; buf += n; if (bytesLeft > 0) break; // user buffer filled samplePtr = 0; INCREMENT_TAIL(*cbuf,cbuf->size); } insamp = GET_TAIL(*cbuf,cbuf->size); if (!insamp) break; // no more samples samplePtr = (char*)insamp; bytesLeft = insamp->length + SIZEOF_DSM_SAMPLE_HEADER; KLOG_DEBUG("bytes left=%zd\n",bytesLeft); } state->samplePtr = samplePtr; state->bytesLeft = bytesLeft; KLOG_DEBUG("read return = %u\n",countreq - count); return countreq - count; }
/* * The proc filesystem: function to read */ static int pcmcom8_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int i, j, len = 0; int limit = count - 80; /* Don't print more than this */ int result = 0; KLOG_DEBUG("read_proc, count=%d\n",count); for (i = 0; i < pcmcom8_nr_ok && len <= limit; i++) { pcmcom8_board *brd = pcmcom8_boards + i; KLOG_DEBUG("read_proc, i=%d, device=0x%lx\n",i,(unsigned long)brd); if ((result = PCMCOM8_LOCK(&brd->mutex))) return result; pcmcom8_read_config(brd); len += sprintf(buf+len,"\nWinSystems PCMCOM8 board %i: ioport %x\n", i, brd->ioport); /* loop over serial ports */ for (j = 0; len <= limit && j < PCMCOM8_NR_PORTS; j++) { len += sprintf(buf+len, " port %d, ioport=%x,irq=%d\n", j,brd->config.ports[j].ioport,brd->config.ports[j].irq); } PCMCOM8_UNLOCK(&brd->mutex); } *eof = 1; return len; }
ssize_t nidas_circbuf_read(struct file *filp, char __user* buf, size_t count, struct dsm_sample_circ_buf* cbuf, struct sample_read_state* state, wait_queue_head_t* readq) { while(state->bytesLeft == 0 && ACCESS_ONCE(cbuf->head) == cbuf->tail) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; KLOG_DEBUG("waiting for data,head=%d,tail=%d\n",cbuf->head,cbuf->tail); if (wait_event_interruptible(*readq,(ACCESS_ONCE(cbuf->head) != cbuf->tail))) return -ERESTARTSYS; KLOG_DEBUG("woken\n"); } return nidas_circbuf_read_nowait(filp,buf,count,cbuf,state); }
static void pcmcom8_create_proc(void) { KLOG_DEBUG("within pcmcom8_create_proc\n"); create_proc_read_entry(DRIVER_NAME, 0644 /* default mode */, NULL /* parent dir */, pcmcom8_read_procmem, NULL /* client data */); }
static void klog_file_log(void) { klog_file_level = LOG_INFO; int result = klog_init_file(LOG_PATH, strlen(LOG_PATH), 256, 1); TEST_ASSERT_EQUAL_INT(result, 0); KLOG_INFO("test", "123:%d", 456); KLOG_WARN("logger", "hi"); KLOG_ERR("o", "error"); KLOG_DEBUG("b", "debug"); klog_cleanup(); FILE *log_file = fopen(LOG_PATH ".000", "r"); TEST_ASSERT_NOT_NULL(log_file); char buffer[256]; char lines[4][64]; int i = 0; fread(buffer, 1, 256, log_file); for (char *token = strtok(buffer, "\n"); token; token = strtok(NULL, "\n"), i++) { strcpy(lines[i], token); } ASSERT_STRING_STARTS_WITH(&lines[0][14], " test:I 123:456"); ASSERT_STRING_STARTS_WITH(&lines[1][14], " logger:W hi"); ASSERT_STRING_STARTS_WITH(&lines[2][14], " o:E error"); TEST_ASSERT_EQUAL_INT(i, 4); }
static int pcmcom8_wait_eedone(pcmcom8_board* brd) { int cnt; unsigned char status; cnt = 10; while (--cnt) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); status = inb(brd->addr + PCMCOM8_STA); if ((status & 0xc0) == 0x80) break; } KLOG_DEBUG("read EEPROM cnt=%d\n",cnt); if (cnt == 0) { KLOG_ERR("read EEPROM timeout\n"); return -ETIMEDOUT; } return 0; }
/* Don't add __exit macro to the declaration of this cleanup function * since it is also called at init time, if init fails. */ static void viper_dio_cleanup(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) int i; for (i = 0; i < _ngpio; i++) gpio_free(VIPER_PL9_OUT0 + i); #endif if (viper_dio.vclass && !IS_ERR(viper_dio.vclass)) { if (viper_dio.device && !IS_ERR(viper_dio.device)) device_destroy(viper_dio.vclass, viper_dio.cdev.dev); class_destroy(viper_dio.vclass); } if (MAJOR(viper_dio.cdev.dev) != 0) { cdev_del(&viper_dio.cdev); viper_dio.cdev.dev = MKDEV(0,0); unregister_chrdev_region(viper_dio.cdev.dev,1); } viper_dio.vclass = 0; KLOG_DEBUG("complete\n"); }
static int __init pcmcom8_init_module(void) { int result, ib,itmp; dev_t devno; KLOG_NOTICE("version: %s\n", REPO_REVISION); for (ib = 0; ib < PCMCOM8_MAX_NR_DEVS; ib++) if (ioports[ib] == 0) break; pcmcom8_numboards = ib; KLOG_DEBUG("numboards=%d\n",pcmcom8_numboards); /* * Register your major, and accept a dynamic number. This is the * first thing to do, in order to avoid releasing other module's * fops in pcmcom8_cleanup_module() */ result = alloc_chrdev_region(&pcmcom8_device, 0, pcmcom8_numboards,DRIVER_NAME); if (result < 0) goto fail; /* * allocate the board structures */ pcmcom8_boards = kmalloc(pcmcom8_numboards * sizeof(pcmcom8_board), GFP_KERNEL); if (!pcmcom8_boards) { result = -ENOMEM; goto fail; } memset(pcmcom8_boards, 0, pcmcom8_numboards * sizeof(pcmcom8_board)); pcmcom8_class = class_create(THIS_MODULE, DRIVER_NAME); if (IS_ERR(pcmcom8_class)) { result = PTR_ERR(pcmcom8_class); goto fail; } for (ib = 0; ib < pcmcom8_numboards; ib++) { pcmcom8_board* brd = pcmcom8_boards + ib; if (!request_region(ioports[ib],PCMCOM8_IO_REGION_SIZE,DRIVER_NAME)) { result = -ENODEV; goto fail; } brd->ioport = ioports[ib]; brd->addr = brd->ioport + ioport_base; brd->region_req = 1; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) mutex_init(&brd->mutex); #else init_MUTEX(&brd->mutex); #endif /* * Read EEPROM configuration. If it doesn't return * -ETIMEDOUT then it looks like there is a board at * the given address. */ if (!pcmcom8_read_eeconfig(brd,&brd->config,0)) { pcmcom8_nr_ok = ib + 1; itmp = pcmcom8_check_config(&brd->config); KLOG_INFO("EEPROM config for board %d,ioport %#x=%s\n", ib,brd->ioport,(itmp ? "OK":"looks invalid")); } else { release_region(brd->ioport, PCMCOM8_IO_REGION_SIZE); brd->ioport = 0; brd->region_req = 0; break; } cdev_init(&brd->cdev,&pcmcom8_fops); brd->cdev.owner = THIS_MODULE; devno = MKDEV(MAJOR(pcmcom8_device),ib); // after calling cdev_add the device is ready for operations result = cdev_add(&brd->cdev,devno,1); if (result) goto fail; brd->device = device_create_x(pcmcom8_class, NULL, devno, DRIVER_NAME "_%d", ib); if (IS_ERR(brd->device)) { result = PTR_ERR(brd->device); goto fail; } } if (pcmcom8_nr_ok == 0) { result = -ENODEV; goto fail; } #ifdef DEBUG /* only when debugging */ KLOG_DEBUG("create_proc\n"); pcmcom8_create_proc(); #endif return result; /* succeed */ fail: pcmcom8_cleanup_module(); return result; }
static int __init viper_dio_init(void) { int result = -EINVAL; int i; dev_t devno = MKDEV(0,0); KLOG_NOTICE("version: %s\n",REPO_REVISION); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) for (i = 0; i < 8; i++) { result = gpio_request(VIPER_PL9_OUT0 + i, "GPIO"); if (result) { KLOG_ERR("gpio_request failed for GPIO %d\n",VIPER_PL9_OUT0 + i); goto err; } _ngpio = i + 1; result = gpio_direction_output(VIPER_PL9_OUT0, 0); if (result) { KLOG_ERR("gpio_direction_output failed for GPIO %d\n",VIPER_PL9_OUT0 + i); goto err; } } #endif result = alloc_chrdev_region(&devno,0,1,"viper_dio"); if (result < 0) goto err; mutex_init(&viper_dio.reg_mutex); // for informational messages only at this point sprintf(viper_dio.deviceName,"/dev/viper_dio%d",0); viper_dio.vclass = class_create(THIS_MODULE, "viper_dio"); if (IS_ERR(viper_dio.vclass)) { result = PTR_ERR(viper_dio.vclass); goto err; } cdev_init(&viper_dio.cdev,&viper_dio_fops); viper_dio.cdev.owner = THIS_MODULE; /* After calling cdev_all the device is "live" * and ready for user operation. */ result = cdev_add(&viper_dio.cdev, devno, 1); if (result) goto err; viper_dio.device = device_create_x(viper_dio.vclass, NULL, devno, "viper_dio%d", 0); if (IS_ERR(viper_dio.device)) { result = PTR_ERR(viper_dio.device); goto err; } KLOG_DEBUG("complete.\n"); return 0; err: viper_dio_cleanup(); return result; }
/* * Allocate a circular buffer of dsm_samples. If the size of one * sample is less than PAGE_SIZE, they are allocated in blocks of * size up to PAGE_SIZE. * dlen: length in bytes of the data portion of each sample. * blen: number of samples in the circular buffer. */ int alloc_dsm_circ_buf(struct dsm_sample_circ_buf* c,size_t dlen,int blen) { int isamp = 0; int samps_per_page; int j,n; char *sp; /* count number of bits set, which should be one for a * power of 2. Or check if first bit set * is the same as the last bit set: ffs(blen) == fls(blen) */ if (blen == 0 || ffs(blen) != fls(blen)) { KLOG_ERR("circular buffer size=%d is not a power of 2\n",blen); return -EINVAL; } c->head = c->tail = c->size = c->npages = 0; c->pages = 0; KLOG_DEBUG("kmalloc %u bytes\n",blen * sizeof(void*)); if (!(c->buf = kmalloc(blen * sizeof(void*),GFP_KERNEL))) return -ENOMEM; memset(c->buf,0,blen * sizeof(void*)); /* Total size of a sample. Make it a multiple of sizeof(int) * so that samples are aligned to an int */ dlen += SIZEOF_DSM_SAMPLE_HEADER; n = dlen % sizeof(int); if (n) dlen += sizeof(int) - n; samps_per_page = PAGE_SIZE / dlen; if (samps_per_page < 1) samps_per_page = 1; /* number of pages to allocate */ n = (blen - 1) / samps_per_page + 1; if (!(c->pages = kmalloc(n * sizeof(void*),GFP_KERNEL))) { kfree(c->buf); c->buf = 0; return -ENOMEM; } memset(c->pages,0,n * sizeof(void*)); c->npages = n; KLOG_INFO("sample len=%zu, buf len=%d, samps_per_page=%d, npages=%d\n", dlen,blen,samps_per_page,n); for (n = 0; n < c->npages; n++) { j = blen - isamp; /* left to allocate */ if (j > samps_per_page) j = samps_per_page; sp = kmalloc(dlen * j,GFP_KERNEL); if (!sp) { for (j = 0; j < n; j++) kfree(c->pages[j]); kfree(c->pages); c->pages = 0; c->npages = 0; kfree(c->buf); c->buf = 0; return -ENOMEM; } c->pages[n] = sp; for (j = 0; j < samps_per_page && isamp < blen; j++) { c->buf[isamp++] = (struct dsm_sample*) sp; sp += dlen; } } c->size = blen; smp_mb(); return 0; }
static void __exit nidas_util_cleanup(void) { KLOG_DEBUG("nidas_util done\n"); return; }