static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, size_t count) { size_t offs = 0, max_offs; if (count < 1) return 0; if (tolower(buf[0]) == 'b') { /* binary mode, set the entire memory*/ size_t i; odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8; kfree(odev->buf); odev->buf = kmalloc(odev->buf_size, GFP_KERNEL); if (odev->buf == NULL) { odev->buf_size = 0; ; return -ENOMEM; } memset(odev->buf, 0xff, odev->buf_size); for (i = 1; i < count && i <= 32 * 32; i++) { odev->buf[i-1] = buf[i]; odev->buf_offs = i-1; } odev->width = odev->dev_width / 8; odev->height = ASUS_OLED_DISP_HEIGHT; odev->x_shift = 0; odev->y_shift = 0; odev->last_val = 0; send_data(odev); return count; } if (buf[0] == '<') { size_t i; size_t w = 0, h = 0; size_t w_mem, h_mem; if (count < 10 || buf[2] != ':') goto error_header; switch (tolower(buf[1])) { case ASUS_OLED_STATIC: case ASUS_OLED_ROLL: case ASUS_OLED_FLASH: odev->pic_mode = buf[1]; break; default: // printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n", ; return -EIO; break; } for (i = 3; i < count; ++i) { if (buf[i] >= '0' && buf[i] <= '9') { w = 10*w + (buf[i] - '0'); if (w > ASUS_OLED_MAX_WIDTH) goto error_width; } else if (tolower(buf[i]) == 'x') { break; } else { goto error_width; } } for (++i; i < count; ++i) { if (buf[i] >= '0' && buf[i] <= '9') { h = 10*h + (buf[i] - '0'); if (h > ASUS_OLED_DISP_HEIGHT) goto error_height; } else if (tolower(buf[i]) == '>') { break; } else { goto error_height; } } if (w < 1 || w > ASUS_OLED_MAX_WIDTH) goto error_width; if (h < 1 || h > ASUS_OLED_DISP_HEIGHT) goto error_height; if (i >= count || buf[i] != '>') goto error_header; offs = i+1; if (w % (odev->dev_width) != 0) w_mem = (w/(odev->dev_width) + 1)*(odev->dev_width); else w_mem = w; if (h < ASUS_OLED_DISP_HEIGHT) h_mem = ASUS_OLED_DISP_HEIGHT; else h_mem = h; odev->buf_size = w_mem * h_mem / 8; kfree(odev->buf); odev->buf = kmalloc(odev->buf_size, GFP_KERNEL); if (odev->buf == NULL) { odev->buf_size = 0; ; return -ENOMEM; } memset(odev->buf, 0xff, odev->buf_size); odev->buf_offs = 0; odev->width = w; odev->height = h; odev->x_shift = 0; odev->y_shift = 0; odev->last_val = 0; if (odev->pic_mode == ASUS_OLED_FLASH) { if (h < ASUS_OLED_DISP_HEIGHT/2) odev->y_shift = (ASUS_OLED_DISP_HEIGHT/2 - h)/2; } else { if (h < ASUS_OLED_DISP_HEIGHT) odev->y_shift = (ASUS_OLED_DISP_HEIGHT - h)/2; } if (w < (odev->dev_width)) odev->x_shift = ((odev->dev_width) - w)/2; } max_offs = odev->width * odev->height; while (offs < count && odev->buf_offs < max_offs) { int ret = 0; if (buf[offs] == '1' || buf[offs] == '#') { ret = append_values(odev, 1, 1); if (ret < 0) return ret; } else if (buf[offs] == '0' || buf[offs] == ' ') { ret = append_values(odev, 0, 1); if (ret < 0) return ret; } else if (buf[offs] == '\n') { /* New line detected. Lets assume, that all characters till the end of the line were equal to the last character in this line.*/ if (odev->buf_offs % odev->width != 0) ret = append_values(odev, odev->last_val, odev->width - (odev->buf_offs % odev->width)); if (ret < 0) return ret; } offs++; } if (odev->buf_offs >= max_offs) send_data(odev); return count; error_width: ; return -EIO; error_height: ; return -EIO; error_header: ; return -EIO; }
static ssize_t set_picture(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { size_t offs = 0, max_offs; struct usb_interface *intf = to_usb_interface(dev); struct asus_oled_dev *odev = usb_get_intfdata(intf); if (count < 1) return 0; if (buf[0] == '<') { size_t i; size_t w = 0, h = 0; size_t w_mem, h_mem; if (count < 10 || buf[2] != ':') { goto error_header; } switch(tolower(buf[1])) { case ASUS_OLED_STATIC: case ASUS_OLED_ROLL: case ASUS_OLED_FLASH: odev->pic_mode = buf[1]; break; default: printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n", buf[1]); return -EIO; break; } for (i = 3; i < count; ++i) { if (buf[i] >= '0' && buf[i] <= '9') { w = 10*w + (buf[i] - '0'); if (w > ASUS_OLED_MAX_WIDTH) goto error_width; } else if (tolower(buf[i]) == 'x') break; else goto error_width; } for (++i; i < count; ++i) { if (buf[i] >= '0' && buf[i] <= '9') { h = 10*h + (buf[i] - '0'); if (h > ASUS_OLED_DISP_HEIGHT) goto error_height; } else if (tolower(buf[i]) == '>') break; else goto error_height; } if (w < 1 || w > ASUS_OLED_MAX_WIDTH) goto error_width; if (h < 1 || h > ASUS_OLED_DISP_HEIGHT) goto error_height; if (i >= count || buf[i] != '>') goto error_header; offs = i+1; if (w % ASUS_OLED_DISP_WIDTH != 0) w_mem = (w/ASUS_OLED_DISP_WIDTH + 1)*ASUS_OLED_DISP_WIDTH; else w_mem = w; if (h < ASUS_OLED_DISP_HEIGHT) h_mem = ASUS_OLED_DISP_HEIGHT; else h_mem = h; odev->buf_size = w_mem * h_mem / 8; if (odev->buf) kfree(odev->buf); odev->buf = kmalloc(odev->buf_size, GFP_KERNEL); if (odev->buf == NULL) { odev->buf_size = 0; printk(ASUS_OLED_ERROR "Out of memory!\n"); return -ENOMEM; } memset(odev->buf, 0xff, odev->buf_size); odev->buf_offs = 0; odev->width = w; odev->height = h; odev->x_shift = 0; odev->y_shift = 0; odev->last_val = 0; if (odev->pic_mode == ASUS_OLED_FLASH) { if (h < ASUS_OLED_DISP_HEIGHT/2) odev->y_shift = (ASUS_OLED_DISP_HEIGHT/2 - h)/2; } else { if (h < ASUS_OLED_DISP_HEIGHT) odev->y_shift = (ASUS_OLED_DISP_HEIGHT - h)/2; } if (w < ASUS_OLED_DISP_WIDTH) odev->x_shift = (ASUS_OLED_DISP_WIDTH - w)/2; } max_offs = odev->width * odev->height; while (offs < count && odev->buf_offs < max_offs) { int ret; if (buf[offs] == '1' || buf[offs] == '#') { if ( (ret = append_values(odev, 1, 1)) < 0) return ret; } else if (buf[offs] == '0' || buf[offs] == ' ') { if ( (ret = append_values(odev, 0, 1)) < 0) return ret; } else if (buf[offs] == '\n') { // New line detected. Lets assume, that all characters till the end of the // line were equal to the last character in this line. if (odev->buf_offs % odev->width != 0) if ( (ret = append_values(odev, odev->last_val, odev->width - (odev->buf_offs % odev->width))) < 0) return ret; } offs++; } if (odev->buf_offs >= max_offs) send_data(odev); return count; error_width: printk(ASUS_OLED_ERROR "Wrong picture width specified.\n"); return -EIO; error_height: printk(ASUS_OLED_ERROR "Wrong picture height specified.\n"); return -EIO; error_header: printk(ASUS_OLED_ERROR "Wrong picture header.\n"); return -EIO; }