Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'auxdisplay-for-linus-v5.16' of git://github.com/ojeda/linux

Pull auxdisplay updates from Miguel Ojeda:

- 4-digit 7-segment and quad alphanumeric display support for the
ht16k33 driver, allowing the user to display and scroll text
messages, from Geert Uytterhoeven.

- An assortment of fixes and cleanups from Geert Uytterhoeven.

- Header cleanups from Mianhan Liu.

- Whitespace cleanup from Huiquan Deng.

* tag 'auxdisplay-for-linus-v5.16' of git://github.com/ojeda/linux: (26 commits)
MAINTAINERS: Add DT Bindings for Auxiliary Display Drivers
auxdisplay: cfag12864bfb: code indent should use tabs where possible
auxdisplay: ht16k33: remove superfluous header files
auxdisplay: ks0108: remove superfluous header files
auxdisplay: cfag12864bfb: remove superfluous header files
auxdisplay: ht16k33: Make use of device properties
auxdisplay: ht16k33: Add LED support
dt-bindings: auxdisplay: ht16k33: Document LED subnode
auxdisplay: ht16k33: Add support for segment displays
auxdisplay: ht16k33: Extract frame buffer probing
auxdisplay: ht16k33: Extract ht16k33_brightness_set()
auxdisplay: ht16k33: Move delayed work
auxdisplay: ht16k33: Add helper variable dev
auxdisplay: ht16k33: Convert to simple i2c probe function
auxdisplay: ht16k33: Remove unneeded error check in keypad probe()
auxdisplay: ht16k33: Use HT16K33_FB_SIZE in ht16k33_initialize()
auxdisplay: ht16k33: Fix frame buffer device blanking
auxdisplay: ht16k33: Connect backlight to fbdev
auxdisplay: linedisp: Add support for changing scroll rate
auxdisplay: linedisp: Use kmemdup_nul() helper
...

+1030 -293
+29 -3
Documentation/devicetree/bindings/auxdisplay/holtek,ht16k33.yaml
··· 14 14 15 15 properties: 16 16 compatible: 17 - const: holtek,ht16k33 17 + oneOf: 18 + - items: 19 + - enum: 20 + - adafruit,3108 # 0.56" 4-Digit 7-Segment FeatherWing Display (Red) 21 + - adafruit,3130 # 0.54" Quad Alphanumeric FeatherWing Display (Red) 22 + - const: holtek,ht16k33 23 + 24 + - const: holtek,ht16k33 # Generic 16*8 LED controller with dot-matrix display 18 25 19 26 reg: 20 27 maxItems: 1 21 28 22 29 refresh-rate-hz: 23 30 maxItems: 1 24 - description: Display update interval in Hertz 31 + description: Display update interval in Hertz for dot-matrix displays 25 32 26 33 interrupts: 27 34 maxItems: 1 ··· 48 41 default: 16 49 42 description: Initial brightness level 50 43 44 + led: 45 + type: object 46 + $ref: /schemas/leds/common.yaml# 47 + unevaluatedProperties: false 48 + 51 49 required: 52 50 - compatible 53 51 - reg 54 - - refresh-rate-hz 52 + 53 + if: 54 + properties: 55 + compatible: 56 + const: holtek,ht16k33 57 + then: 58 + required: 59 + - refresh-rate-hz 55 60 56 61 additionalProperties: false 57 62 ··· 71 52 - | 72 53 #include <dt-bindings/interrupt-controller/irq.h> 73 54 #include <dt-bindings/input/input.h> 55 + #include <dt-bindings/leds/common.h> 74 56 i2c1 { 75 57 #address-cells = <1>; 76 58 #size-cells = <0>; ··· 93 73 <MATRIX_KEY(4, 1, KEY_F9)>, 94 74 <MATRIX_KEY(5, 1, KEY_F3)>, 95 75 <MATRIX_KEY(6, 1, KEY_F1)>; 76 + 77 + led { 78 + color = <LED_COLOR_ID_RED>; 79 + function = LED_FUNCTION_BACKLIGHT; 80 + linux,default-trigger = "backlight"; 81 + }; 96 82 }; 97 83 };
+1
MAINTAINERS
··· 3170 3170 AUXILIARY DISPLAY DRIVERS 3171 3171 M: Miguel Ojeda <ojeda@kernel.org> 3172 3172 S: Maintained 3173 + F: Documentation/devicetree/bindings/auxdisplay/ 3173 3174 F: drivers/auxdisplay/ 3174 3175 F: include/linux/cfag12864b.h 3175 3176
+11 -1
drivers/auxdisplay/Kconfig
··· 25 25 This is some character LCD core interface that multiple drivers can 26 26 use. 27 27 28 + config LINEDISP 29 + tristate "Character line display core support" if COMPILE_TEST 30 + help 31 + This is the core support for single-line character displays, to be 32 + selected by drivers that use it. 33 + 28 34 config HD44780_COMMON 29 35 tristate "Common functions for HD44780 (and compatibles) LCD displays" if COMPILE_TEST 30 36 select CHARLCD ··· 161 155 depends on HAS_IOMEM 162 156 default y if MIPS_MALTA 163 157 select MFD_SYSCON 158 + select LINEDISP 164 159 help 165 160 Enable this to support the simple ASCII LCD displays found on 166 161 development boards such as the MIPS Boston, MIPS Malta & MIPS SEAD3 ··· 169 162 170 163 config HT16K33 171 164 tristate "Holtek Ht16K33 LED controller with keyscan" 172 - depends on FB && OF && I2C && INPUT 165 + depends on FB && I2C && INPUT 173 166 select FB_SYS_FOPS 174 167 select FB_SYS_FILLRECT 175 168 select FB_SYS_COPYAREA 176 169 select FB_SYS_IMAGEBLIT 177 170 select INPUT_MATRIXKMAP 178 171 select FB_BACKLIGHT 172 + select NEW_LEDS 173 + select LEDS_CLASS 174 + select LINEDISP 179 175 help 180 176 Say yes here to add support for Holtek HT16K33, RAM mapping 16*8 181 177 LED controller driver with keyscan.
+1
drivers/auxdisplay/Makefile
··· 13 13 obj-$(CONFIG_HT16K33) += ht16k33.o 14 14 obj-$(CONFIG_PARPORT_PANEL) += panel.o 15 15 obj-$(CONFIG_LCD2S) += lcd2s.o 16 + obj-$(CONFIG_LINEDISP) += line-display.o
+3 -6
drivers/auxdisplay/cfag12864bfb.c
··· 12 12 #include <linux/init.h> 13 13 #include <linux/module.h> 14 14 #include <linux/kernel.h> 15 - #include <linux/delay.h> 16 15 #include <linux/errno.h> 17 16 #include <linux/fb.h> 18 17 #include <linux/mm.h> 19 18 #include <linux/platform_device.h> 20 - #include <linux/string.h> 21 - #include <linux/uaccess.h> 22 19 #include <linux/cfag12864b.h> 23 20 24 21 #define CFAG12864BFB_NAME "cfag12864bfb" ··· 38 41 .yres_virtual = CFAG12864B_HEIGHT, 39 42 .bits_per_pixel = 1, 40 43 .red = { 0, 1, 0 }, 41 - .green = { 0, 1, 0 }, 42 - .blue = { 0, 1, 0 }, 44 + .green = { 0, 1, 0 }, 45 + .blue = { 0, 1, 0 }, 43 46 .left_margin = 0, 44 47 .right_margin = 0, 45 48 .upper_margin = 0, ··· 67 70 static int cfag12864bfb_probe(struct platform_device *device) 68 71 { 69 72 int ret = -EINVAL; 70 - struct fb_info *info = framebuffer_alloc(0, &device->dev); 73 + struct fb_info *info = framebuffer_alloc(0, &device->dev); 71 74 72 75 if (!info) 73 76 goto none;
+404 -109
drivers/auxdisplay/ht16k33.c
··· 5 5 * Author: Robin van der Gracht <robin@protonic.nl> 6 6 * 7 7 * Copyright: (C) 2016 Protonic Holland. 8 + * Copyright (C) 2021 Glider bv 8 9 */ 9 10 10 11 #include <linux/kernel.h> 11 12 #include <linux/module.h> 12 13 #include <linux/interrupt.h> 13 14 #include <linux/i2c.h> 14 - #include <linux/of.h> 15 + #include <linux/property.h> 15 16 #include <linux/fb.h> 16 - #include <linux/slab.h> 17 17 #include <linux/backlight.h> 18 18 #include <linux/input.h> 19 19 #include <linux/input/matrix_keypad.h> 20 + #include <linux/leds.h> 20 21 #include <linux/workqueue.h> 21 22 #include <linux/mm.h> 23 + 24 + #include <linux/map_to_7segment.h> 25 + #include <linux/map_to_14segment.h> 26 + 27 + #include <asm/unaligned.h> 28 + 29 + #include "line-display.h" 22 30 23 31 /* Registers */ 24 32 #define REG_SYSTEM_SETUP 0x20 ··· 34 26 35 27 #define REG_DISPLAY_SETUP 0x80 36 28 #define REG_DISPLAY_SETUP_ON BIT(0) 29 + #define REG_DISPLAY_SETUP_BLINK_OFF (0 << 1) 30 + #define REG_DISPLAY_SETUP_BLINK_2HZ (1 << 1) 31 + #define REG_DISPLAY_SETUP_BLINK_1HZ (2 << 1) 32 + #define REG_DISPLAY_SETUP_BLINK_0HZ5 (3 << 1) 37 33 38 34 #define REG_ROWINT_SET 0xA0 39 35 #define REG_ROWINT_SET_INT_EN BIT(0) ··· 59 47 #define BYTES_PER_ROW (HT16K33_MATRIX_LED_MAX_ROWS / 8) 60 48 #define HT16K33_FB_SIZE (HT16K33_MATRIX_LED_MAX_COLS * BYTES_PER_ROW) 61 49 50 + enum display_type { 51 + DISP_MATRIX = 0, 52 + DISP_QUAD_7SEG, 53 + DISP_QUAD_14SEG, 54 + }; 55 + 62 56 struct ht16k33_keypad { 63 57 struct i2c_client *client; 64 58 struct input_dev *dev; ··· 83 65 uint32_t refresh_rate; 84 66 uint8_t *buffer; 85 67 uint8_t *cache; 86 - struct delayed_work work; 68 + }; 69 + 70 + struct ht16k33_seg { 71 + struct linedisp linedisp; 72 + union { 73 + struct seg7_conversion_map seg7; 74 + struct seg14_conversion_map seg14; 75 + } map; 76 + unsigned int map_size; 77 + char curr[4]; 87 78 }; 88 79 89 80 struct ht16k33_priv { 90 81 struct i2c_client *client; 82 + struct delayed_work work; 83 + struct led_classdev led; 91 84 struct ht16k33_keypad keypad; 92 - struct ht16k33_fbdev fbdev; 85 + union { 86 + struct ht16k33_fbdev fbdev; 87 + struct ht16k33_seg seg; 88 + }; 89 + enum display_type type; 90 + uint8_t blink; 93 91 }; 94 92 95 93 static const struct fb_fix_screeninfo ht16k33_fb_fix = { ··· 135 101 .vmode = FB_VMODE_NONINTERLACED, 136 102 }; 137 103 104 + static const SEG7_DEFAULT_MAP(initial_map_seg7); 105 + static const SEG14_DEFAULT_MAP(initial_map_seg14); 106 + 107 + static ssize_t map_seg_show(struct device *dev, struct device_attribute *attr, 108 + char *buf) 109 + { 110 + struct ht16k33_priv *priv = dev_get_drvdata(dev); 111 + 112 + memcpy(buf, &priv->seg.map, priv->seg.map_size); 113 + return priv->seg.map_size; 114 + } 115 + 116 + static ssize_t map_seg_store(struct device *dev, struct device_attribute *attr, 117 + const char *buf, size_t cnt) 118 + { 119 + struct ht16k33_priv *priv = dev_get_drvdata(dev); 120 + 121 + if (cnt != priv->seg.map_size) 122 + return -EINVAL; 123 + 124 + memcpy(&priv->seg.map, buf, cnt); 125 + return cnt; 126 + } 127 + 128 + static DEVICE_ATTR(map_seg7, 0644, map_seg_show, map_seg_store); 129 + static DEVICE_ATTR(map_seg14, 0644, map_seg_show, map_seg_store); 130 + 138 131 static int ht16k33_display_on(struct ht16k33_priv *priv) 139 132 { 140 - uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON; 133 + uint8_t data = REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON | priv->blink; 141 134 142 135 return i2c_smbus_write_byte(priv->client, data); 143 136 } ··· 174 113 return i2c_smbus_write_byte(priv->client, REG_DISPLAY_SETUP); 175 114 } 176 115 116 + static int ht16k33_brightness_set(struct ht16k33_priv *priv, 117 + unsigned int brightness) 118 + { 119 + int err; 120 + 121 + if (brightness == 0) { 122 + priv->blink = REG_DISPLAY_SETUP_BLINK_OFF; 123 + return ht16k33_display_off(priv); 124 + } 125 + 126 + err = ht16k33_display_on(priv); 127 + if (err) 128 + return err; 129 + 130 + return i2c_smbus_write_byte(priv->client, 131 + REG_BRIGHTNESS | (brightness - 1)); 132 + } 133 + 134 + static int ht16k33_brightness_set_blocking(struct led_classdev *led_cdev, 135 + enum led_brightness brightness) 136 + { 137 + struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv, 138 + led); 139 + 140 + return ht16k33_brightness_set(priv, brightness); 141 + } 142 + 143 + static int ht16k33_blink_set(struct led_classdev *led_cdev, 144 + unsigned long *delay_on, unsigned long *delay_off) 145 + { 146 + struct ht16k33_priv *priv = container_of(led_cdev, struct ht16k33_priv, 147 + led); 148 + unsigned int delay; 149 + uint8_t blink; 150 + int err; 151 + 152 + if (!*delay_on && !*delay_off) { 153 + blink = REG_DISPLAY_SETUP_BLINK_1HZ; 154 + delay = 1000; 155 + } else if (*delay_on <= 750) { 156 + blink = REG_DISPLAY_SETUP_BLINK_2HZ; 157 + delay = 500; 158 + } else if (*delay_on <= 1500) { 159 + blink = REG_DISPLAY_SETUP_BLINK_1HZ; 160 + delay = 1000; 161 + } else { 162 + blink = REG_DISPLAY_SETUP_BLINK_0HZ5; 163 + delay = 2000; 164 + } 165 + 166 + err = i2c_smbus_write_byte(priv->client, 167 + REG_DISPLAY_SETUP | REG_DISPLAY_SETUP_ON | 168 + blink); 169 + if (err) 170 + return err; 171 + 172 + priv->blink = blink; 173 + *delay_on = *delay_off = delay; 174 + return 0; 175 + } 176 + 177 177 static void ht16k33_fb_queue(struct ht16k33_priv *priv) 178 178 { 179 179 struct ht16k33_fbdev *fbdev = &priv->fbdev; 180 180 181 - schedule_delayed_work(&fbdev->work, HZ / fbdev->refresh_rate); 181 + schedule_delayed_work(&priv->work, HZ / fbdev->refresh_rate); 182 182 } 183 183 184 184 /* ··· 247 125 */ 248 126 static void ht16k33_fb_update(struct work_struct *work) 249 127 { 250 - struct ht16k33_fbdev *fbdev = 251 - container_of(work, struct ht16k33_fbdev, work.work); 252 - struct ht16k33_priv *priv = 253 - container_of(fbdev, struct ht16k33_priv, fbdev); 128 + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, 129 + work.work); 130 + struct ht16k33_fbdev *fbdev = &priv->fbdev; 254 131 255 132 uint8_t *p1, *p2; 256 133 int len, pos = 0, first = -1; ··· 289 168 290 169 static int ht16k33_initialize(struct ht16k33_priv *priv) 291 170 { 171 + uint8_t data[HT16K33_FB_SIZE]; 292 172 uint8_t byte; 293 173 int err; 294 - uint8_t data[HT16K33_MATRIX_LED_MAX_COLS * 2]; 295 174 296 175 /* Clear RAM (8 * 16 bits) */ 297 176 memset(data, 0, sizeof(data)); ··· 319 198 320 199 if (bl->props.power != FB_BLANK_UNBLANK || 321 200 bl->props.fb_blank != FB_BLANK_UNBLANK || 322 - bl->props.state & BL_CORE_FBBLANK || brightness == 0) { 323 - return ht16k33_display_off(priv); 324 - } 201 + bl->props.state & BL_CORE_FBBLANK) 202 + brightness = 0; 325 203 326 - ht16k33_display_on(priv); 327 - return i2c_smbus_write_byte(priv->client, 328 - REG_BRIGHTNESS | (brightness - 1)); 204 + return ht16k33_brightness_set(priv, brightness); 329 205 } 330 206 331 207 static int ht16k33_bl_check_fb(struct backlight_device *bl, struct fb_info *fi) ··· 337 219 .check_fb = ht16k33_bl_check_fb, 338 220 }; 339 221 222 + /* 223 + * Blank events will be passed to the actual device handling the backlight when 224 + * we return zero here. 225 + */ 226 + static int ht16k33_blank(int blank, struct fb_info *info) 227 + { 228 + return 0; 229 + } 230 + 340 231 static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) 341 232 { 342 233 struct ht16k33_priv *priv = info->par; ··· 358 231 .owner = THIS_MODULE, 359 232 .fb_read = fb_sys_read, 360 233 .fb_write = fb_sys_write, 234 + .fb_blank = ht16k33_blank, 361 235 .fb_fillrect = sys_fillrect, 362 236 .fb_copyarea = sys_copyarea, 363 237 .fb_imageblit = sys_imageblit, ··· 441 313 disable_irq(keypad->client->irq); 442 314 } 443 315 316 + static void ht16k33_linedisp_update(struct linedisp *linedisp) 317 + { 318 + struct ht16k33_priv *priv = container_of(linedisp, struct ht16k33_priv, 319 + seg.linedisp); 320 + 321 + schedule_delayed_work(&priv->work, 0); 322 + } 323 + 324 + static void ht16k33_seg7_update(struct work_struct *work) 325 + { 326 + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, 327 + work.work); 328 + struct ht16k33_seg *seg = &priv->seg; 329 + char *s = seg->curr; 330 + uint8_t buf[9]; 331 + 332 + buf[0] = map_to_seg7(&seg->map.seg7, *s++); 333 + buf[1] = 0; 334 + buf[2] = map_to_seg7(&seg->map.seg7, *s++); 335 + buf[3] = 0; 336 + buf[4] = 0; 337 + buf[5] = 0; 338 + buf[6] = map_to_seg7(&seg->map.seg7, *s++); 339 + buf[7] = 0; 340 + buf[8] = map_to_seg7(&seg->map.seg7, *s++); 341 + 342 + i2c_smbus_write_i2c_block_data(priv->client, 0, ARRAY_SIZE(buf), buf); 343 + } 344 + 345 + static void ht16k33_seg14_update(struct work_struct *work) 346 + { 347 + struct ht16k33_priv *priv = container_of(work, struct ht16k33_priv, 348 + work.work); 349 + struct ht16k33_seg *seg = &priv->seg; 350 + char *s = seg->curr; 351 + uint8_t buf[8]; 352 + 353 + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf); 354 + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 2); 355 + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 4); 356 + put_unaligned_le16(map_to_seg14(&seg->map.seg14, *s++), buf + 6); 357 + 358 + i2c_smbus_write_i2c_block_data(priv->client, 0, ARRAY_SIZE(buf), buf); 359 + } 360 + 361 + static int ht16k33_led_probe(struct device *dev, struct led_classdev *led, 362 + unsigned int brightness) 363 + { 364 + struct led_init_data init_data = {}; 365 + int err; 366 + 367 + /* The LED is optional */ 368 + init_data.fwnode = device_get_named_child_node(dev, "led"); 369 + if (!init_data.fwnode) 370 + return 0; 371 + 372 + init_data.devicename = "auxdisplay"; 373 + init_data.devname_mandatory = true; 374 + 375 + led->brightness_set_blocking = ht16k33_brightness_set_blocking; 376 + led->blink_set = ht16k33_blink_set; 377 + led->flags = LED_CORE_SUSPENDRESUME; 378 + led->brightness = brightness; 379 + led->max_brightness = MAX_BRIGHTNESS; 380 + 381 + err = devm_led_classdev_register_ext(dev, led, &init_data); 382 + if (err) 383 + dev_err(dev, "Failed to register LED\n"); 384 + 385 + return err; 386 + } 387 + 444 388 static int ht16k33_keypad_probe(struct i2c_client *client, 445 389 struct ht16k33_keypad *keypad) 446 390 { 447 - struct device_node *node = client->dev.of_node; 391 + struct device *dev = &client->dev; 448 392 u32 rows = HT16K33_MATRIX_KEYPAD_MAX_ROWS; 449 393 u32 cols = HT16K33_MATRIX_KEYPAD_MAX_COLS; 450 394 int err; ··· 524 324 keypad->client = client; 525 325 init_waitqueue_head(&keypad->wait); 526 326 527 - keypad->dev = devm_input_allocate_device(&client->dev); 327 + keypad->dev = devm_input_allocate_device(dev); 528 328 if (!keypad->dev) 529 329 return -ENOMEM; 530 330 ··· 535 335 keypad->dev->open = ht16k33_keypad_start; 536 336 keypad->dev->close = ht16k33_keypad_stop; 537 337 538 - if (!of_get_property(node, "linux,no-autorepeat", NULL)) 338 + if (!device_property_read_bool(dev, "linux,no-autorepeat")) 539 339 __set_bit(EV_REP, keypad->dev->evbit); 540 340 541 - err = of_property_read_u32(node, "debounce-delay-ms", 542 - &keypad->debounce_ms); 341 + err = device_property_read_u32(dev, "debounce-delay-ms", 342 + &keypad->debounce_ms); 543 343 if (err) { 544 - dev_err(&client->dev, "key debounce delay not specified\n"); 344 + dev_err(dev, "key debounce delay not specified\n"); 545 345 return err; 546 346 } 547 347 548 - err = matrix_keypad_parse_of_params(&client->dev, &rows, &cols); 348 + err = matrix_keypad_parse_properties(dev, &rows, &cols); 549 349 if (err) 550 350 return err; 551 351 if (rows > HT16K33_MATRIX_KEYPAD_MAX_ROWS || 552 352 cols > HT16K33_MATRIX_KEYPAD_MAX_COLS) { 553 - dev_err(&client->dev, "%u rows or %u cols out of range in DT\n", 554 - rows, cols); 353 + dev_err(dev, "%u rows or %u cols out of range in DT\n", rows, 354 + cols); 555 355 return -ERANGE; 556 356 } 557 357 ··· 562 362 err = matrix_keypad_build_keymap(NULL, NULL, rows, cols, NULL, 563 363 keypad->dev); 564 364 if (err) { 565 - dev_err(&client->dev, "failed to build keymap\n"); 365 + dev_err(dev, "failed to build keymap\n"); 566 366 return err; 567 367 } 568 368 569 - err = devm_request_threaded_irq(&client->dev, client->irq, 570 - NULL, ht16k33_keypad_irq_thread, 369 + err = devm_request_threaded_irq(dev, client->irq, NULL, 370 + ht16k33_keypad_irq_thread, 571 371 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 572 372 DRIVER_NAME, keypad); 573 373 if (err) { 574 - dev_err(&client->dev, "irq request failed %d, error %d\n", 575 - client->irq, err); 374 + dev_err(dev, "irq request failed %d, error %d\n", client->irq, 375 + err); 576 376 return err; 577 377 } 578 378 579 379 ht16k33_keypad_stop(keypad->dev); 580 380 581 - err = input_register_device(keypad->dev); 582 - if (err) 583 - return err; 584 - 585 - return 0; 381 + return input_register_device(keypad->dev); 586 382 } 587 383 588 - static int ht16k33_probe(struct i2c_client *client, 589 - const struct i2c_device_id *id) 384 + static int ht16k33_fbdev_probe(struct device *dev, struct ht16k33_priv *priv, 385 + uint32_t brightness) 590 386 { 387 + struct ht16k33_fbdev *fbdev = &priv->fbdev; 388 + struct backlight_device *bl = NULL; 591 389 int err; 592 - uint32_t dft_brightness; 593 - struct backlight_device *bl; 594 - struct backlight_properties bl_props; 595 - struct ht16k33_priv *priv; 596 - struct ht16k33_fbdev *fbdev; 597 - struct device_node *node = client->dev.of_node; 598 390 599 - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 600 - dev_err(&client->dev, "i2c_check_functionality error\n"); 601 - return -EIO; 391 + if (priv->led.dev) { 392 + err = ht16k33_brightness_set(priv, brightness); 393 + if (err) 394 + return err; 395 + } else { 396 + /* backwards compatibility with DT lacking an led subnode */ 397 + struct backlight_properties bl_props; 398 + 399 + memset(&bl_props, 0, sizeof(struct backlight_properties)); 400 + bl_props.type = BACKLIGHT_RAW; 401 + bl_props.max_brightness = MAX_BRIGHTNESS; 402 + 403 + bl = devm_backlight_device_register(dev, DRIVER_NAME"-bl", dev, 404 + priv, &ht16k33_bl_ops, 405 + &bl_props); 406 + if (IS_ERR(bl)) { 407 + dev_err(dev, "failed to register backlight\n"); 408 + return PTR_ERR(bl); 409 + } 410 + 411 + bl->props.brightness = brightness; 412 + ht16k33_bl_update_status(bl); 602 413 } 603 - 604 - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 605 - if (!priv) 606 - return -ENOMEM; 607 - 608 - priv->client = client; 609 - i2c_set_clientdata(client, priv); 610 - fbdev = &priv->fbdev; 611 - 612 - err = ht16k33_initialize(priv); 613 - if (err) 614 - return err; 615 414 616 415 /* Framebuffer (2 bytes per column) */ 617 416 BUILD_BUG_ON(PAGE_SIZE < HT16K33_FB_SIZE); ··· 618 419 if (!fbdev->buffer) 619 420 return -ENOMEM; 620 421 621 - fbdev->cache = devm_kmalloc(&client->dev, HT16K33_FB_SIZE, GFP_KERNEL); 422 + fbdev->cache = devm_kmalloc(dev, HT16K33_FB_SIZE, GFP_KERNEL); 622 423 if (!fbdev->cache) { 623 424 err = -ENOMEM; 624 425 goto err_fbdev_buffer; 625 426 } 626 427 627 - fbdev->info = framebuffer_alloc(0, &client->dev); 428 + fbdev->info = framebuffer_alloc(0, dev); 628 429 if (!fbdev->info) { 629 430 err = -ENOMEM; 630 431 goto err_fbdev_buffer; 631 432 } 632 433 633 - err = of_property_read_u32(node, "refresh-rate-hz", 634 - &fbdev->refresh_rate); 434 + err = device_property_read_u32(dev, "refresh-rate-hz", 435 + &fbdev->refresh_rate); 635 436 if (err) { 636 - dev_err(&client->dev, "refresh rate not specified\n"); 437 + dev_err(dev, "refresh rate not specified\n"); 637 438 goto err_fbdev_info; 638 439 } 639 440 fb_bl_default_curve(fbdev->info, 0, MIN_BRIGHTNESS, MAX_BRIGHTNESS); 640 441 641 - INIT_DELAYED_WORK(&fbdev->work, ht16k33_fb_update); 442 + INIT_DELAYED_WORK(&priv->work, ht16k33_fb_update); 642 443 fbdev->info->fbops = &ht16k33_fb_ops; 643 444 fbdev->info->screen_base = (char __iomem *) fbdev->buffer; 644 445 fbdev->info->screen_size = HT16K33_FB_SIZE; 645 446 fbdev->info->fix = ht16k33_fb_fix; 646 447 fbdev->info->var = ht16k33_fb_var; 448 + fbdev->info->bl_dev = bl; 647 449 fbdev->info->pseudo_palette = NULL; 648 450 fbdev->info->flags = FBINFO_FLAG_DEFAULT; 649 451 fbdev->info->par = priv; ··· 653 453 if (err) 654 454 goto err_fbdev_info; 655 455 656 - /* Keypad */ 657 - if (client->irq > 0) { 658 - err = ht16k33_keypad_probe(client, &priv->keypad); 659 - if (err) 660 - goto err_fbdev_unregister; 661 - } 662 - 663 - /* Backlight */ 664 - memset(&bl_props, 0, sizeof(struct backlight_properties)); 665 - bl_props.type = BACKLIGHT_RAW; 666 - bl_props.max_brightness = MAX_BRIGHTNESS; 667 - 668 - bl = devm_backlight_device_register(&client->dev, DRIVER_NAME"-bl", 669 - &client->dev, priv, 670 - &ht16k33_bl_ops, &bl_props); 671 - if (IS_ERR(bl)) { 672 - dev_err(&client->dev, "failed to register backlight\n"); 673 - err = PTR_ERR(bl); 674 - goto err_fbdev_unregister; 675 - } 676 - 677 - err = of_property_read_u32(node, "default-brightness-level", 678 - &dft_brightness); 679 - if (err) { 680 - dft_brightness = MAX_BRIGHTNESS; 681 - } else if (dft_brightness > MAX_BRIGHTNESS) { 682 - dev_warn(&client->dev, 683 - "invalid default brightness level: %u, using %u\n", 684 - dft_brightness, MAX_BRIGHTNESS); 685 - dft_brightness = MAX_BRIGHTNESS; 686 - } 687 - 688 - bl->props.brightness = dft_brightness; 689 - ht16k33_bl_update_status(bl); 690 - 691 456 ht16k33_fb_queue(priv); 692 457 return 0; 693 458 694 - err_fbdev_unregister: 695 - unregister_framebuffer(fbdev->info); 696 459 err_fbdev_info: 697 460 framebuffer_release(fbdev->info); 698 461 err_fbdev_buffer: ··· 664 501 return err; 665 502 } 666 503 504 + static int ht16k33_seg_probe(struct device *dev, struct ht16k33_priv *priv, 505 + uint32_t brightness) 506 + { 507 + struct ht16k33_seg *seg = &priv->seg; 508 + int err; 509 + 510 + err = ht16k33_brightness_set(priv, brightness); 511 + if (err) 512 + return err; 513 + 514 + switch (priv->type) { 515 + case DISP_MATRIX: 516 + /* not handled here */ 517 + err = -EINVAL; 518 + break; 519 + 520 + case DISP_QUAD_7SEG: 521 + INIT_DELAYED_WORK(&priv->work, ht16k33_seg7_update); 522 + seg->map.seg7 = initial_map_seg7; 523 + seg->map_size = sizeof(seg->map.seg7); 524 + err = device_create_file(dev, &dev_attr_map_seg7); 525 + break; 526 + 527 + case DISP_QUAD_14SEG: 528 + INIT_DELAYED_WORK(&priv->work, ht16k33_seg14_update); 529 + seg->map.seg14 = initial_map_seg14; 530 + seg->map_size = sizeof(seg->map.seg14); 531 + err = device_create_file(dev, &dev_attr_map_seg14); 532 + break; 533 + } 534 + if (err) 535 + return err; 536 + 537 + err = linedisp_register(&seg->linedisp, dev, 4, seg->curr, 538 + ht16k33_linedisp_update); 539 + if (err) 540 + goto err_remove_map_file; 541 + 542 + return 0; 543 + 544 + err_remove_map_file: 545 + device_remove_file(dev, &dev_attr_map_seg7); 546 + device_remove_file(dev, &dev_attr_map_seg14); 547 + return err; 548 + } 549 + 550 + static int ht16k33_probe(struct i2c_client *client) 551 + { 552 + struct device *dev = &client->dev; 553 + const struct of_device_id *id; 554 + struct ht16k33_priv *priv; 555 + uint32_t dft_brightness; 556 + int err; 557 + 558 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 559 + dev_err(dev, "i2c_check_functionality error\n"); 560 + return -EIO; 561 + } 562 + 563 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 564 + if (!priv) 565 + return -ENOMEM; 566 + 567 + priv->client = client; 568 + id = i2c_of_match_device(dev->driver->of_match_table, client); 569 + if (id) 570 + priv->type = (uintptr_t)id->data; 571 + i2c_set_clientdata(client, priv); 572 + 573 + err = ht16k33_initialize(priv); 574 + if (err) 575 + return err; 576 + 577 + err = device_property_read_u32(dev, "default-brightness-level", 578 + &dft_brightness); 579 + if (err) { 580 + dft_brightness = MAX_BRIGHTNESS; 581 + } else if (dft_brightness > MAX_BRIGHTNESS) { 582 + dev_warn(dev, 583 + "invalid default brightness level: %u, using %u\n", 584 + dft_brightness, MAX_BRIGHTNESS); 585 + dft_brightness = MAX_BRIGHTNESS; 586 + } 587 + 588 + /* LED */ 589 + err = ht16k33_led_probe(dev, &priv->led, dft_brightness); 590 + if (err) 591 + return err; 592 + 593 + /* Keypad */ 594 + if (client->irq > 0) { 595 + err = ht16k33_keypad_probe(client, &priv->keypad); 596 + if (err) 597 + return err; 598 + } 599 + 600 + switch (priv->type) { 601 + case DISP_MATRIX: 602 + /* Frame Buffer Display */ 603 + err = ht16k33_fbdev_probe(dev, priv, dft_brightness); 604 + break; 605 + 606 + case DISP_QUAD_7SEG: 607 + case DISP_QUAD_14SEG: 608 + /* Segment Display */ 609 + err = ht16k33_seg_probe(dev, priv, dft_brightness); 610 + break; 611 + } 612 + return err; 613 + } 614 + 667 615 static int ht16k33_remove(struct i2c_client *client) 668 616 { 669 617 struct ht16k33_priv *priv = i2c_get_clientdata(client); 670 618 struct ht16k33_fbdev *fbdev = &priv->fbdev; 671 619 672 - cancel_delayed_work_sync(&fbdev->work); 673 - unregister_framebuffer(fbdev->info); 674 - framebuffer_release(fbdev->info); 675 - free_page((unsigned long) fbdev->buffer); 620 + cancel_delayed_work_sync(&priv->work); 621 + 622 + switch (priv->type) { 623 + case DISP_MATRIX: 624 + unregister_framebuffer(fbdev->info); 625 + framebuffer_release(fbdev->info); 626 + free_page((unsigned long)fbdev->buffer); 627 + break; 628 + 629 + case DISP_QUAD_7SEG: 630 + case DISP_QUAD_14SEG: 631 + linedisp_unregister(&priv->seg.linedisp); 632 + device_remove_file(&client->dev, &dev_attr_map_seg7); 633 + device_remove_file(&client->dev, &dev_attr_map_seg14); 634 + break; 635 + } 676 636 677 637 return 0; 678 638 } ··· 807 521 MODULE_DEVICE_TABLE(i2c, ht16k33_i2c_match); 808 522 809 523 static const struct of_device_id ht16k33_of_match[] = { 810 - { .compatible = "holtek,ht16k33", }, 524 + { 525 + /* 0.56" 4-Digit 7-Segment FeatherWing Display (Red) */ 526 + .compatible = "adafruit,3108", .data = (void *)DISP_QUAD_7SEG, 527 + }, { 528 + /* 0.54" Quad Alphanumeric FeatherWing Display (Red) */ 529 + .compatible = "adafruit,3130", .data = (void *)DISP_QUAD_14SEG, 530 + }, { 531 + /* Generic, assumed Dot-Matrix Display */ 532 + .compatible = "holtek,ht16k33", .data = (void *)DISP_MATRIX, 533 + }, 811 534 { } 812 535 }; 813 536 MODULE_DEVICE_TABLE(of, ht16k33_of_match); 814 537 815 538 static struct i2c_driver ht16k33_driver = { 816 - .probe = ht16k33_probe, 539 + .probe_new = ht16k33_probe, 817 540 .remove = ht16k33_remove, 818 541 .driver = { 819 542 .name = DRIVER_NAME, 820 - .of_match_table = of_match_ptr(ht16k33_of_match), 543 + .of_match_table = ht16k33_of_match, 821 544 }, 822 545 .id_table = ht16k33_i2c_match, 823 546 };
+36 -171
drivers/auxdisplay/img-ascii-lcd.c
··· 4 4 * Author: Paul Burton <paul.burton@mips.com> 5 5 */ 6 6 7 - #include <generated/utsrelease.h> 8 7 #include <linux/kernel.h> 9 8 #include <linux/io.h> 10 9 #include <linux/mfd/syscon.h> ··· 13 14 #include <linux/platform_device.h> 14 15 #include <linux/regmap.h> 15 16 #include <linux/slab.h> 16 - #include <linux/sysfs.h> 17 + 18 + #include "line-display.h" 17 19 18 20 struct img_ascii_lcd_ctx; 19 21 ··· 27 27 struct img_ascii_lcd_config { 28 28 unsigned int num_chars; 29 29 bool external_regmap; 30 - void (*update)(struct img_ascii_lcd_ctx *ctx); 30 + void (*update)(struct linedisp *linedisp); 31 31 }; 32 32 33 33 /** 34 34 * struct img_ascii_lcd_ctx - Private data structure 35 - * @pdev: the ASCII LCD platform device 36 35 * @base: the base address of the LCD registers 37 36 * @regmap: the regmap through which LCD registers are accessed 38 37 * @offset: the offset within regmap to the start of the LCD registers 39 38 * @cfg: pointer to the LCD model configuration 40 - * @message: the full message to display or scroll on the LCD 41 - * @message_len: the length of the @message string 42 - * @scroll_pos: index of the first character of @message currently displayed 43 - * @scroll_rate: scroll interval in jiffies 44 - * @timer: timer used to implement scrolling 39 + * @linedisp: line display structure 45 40 * @curr: the string currently displayed on the LCD 46 41 */ 47 42 struct img_ascii_lcd_ctx { 48 - struct platform_device *pdev; 49 43 union { 50 44 void __iomem *base; 51 45 struct regmap *regmap; 52 46 }; 53 47 u32 offset; 54 48 const struct img_ascii_lcd_config *cfg; 55 - char *message; 56 - unsigned int message_len; 57 - unsigned int scroll_pos; 58 - unsigned int scroll_rate; 59 - struct timer_list timer; 49 + struct linedisp linedisp; 60 50 char curr[] __aligned(8); 61 51 }; 62 52 ··· 54 64 * MIPS Boston development board 55 65 */ 56 66 57 - static void boston_update(struct img_ascii_lcd_ctx *ctx) 67 + static void boston_update(struct linedisp *linedisp) 58 68 { 69 + struct img_ascii_lcd_ctx *ctx = 70 + container_of(linedisp, struct img_ascii_lcd_ctx, linedisp); 59 71 ulong val; 60 72 61 73 #if BITS_PER_LONG == 64 ··· 82 90 * MIPS Malta development board 83 91 */ 84 92 85 - static void malta_update(struct img_ascii_lcd_ctx *ctx) 93 + static void malta_update(struct linedisp *linedisp) 86 94 { 95 + struct img_ascii_lcd_ctx *ctx = 96 + container_of(linedisp, struct img_ascii_lcd_ctx, linedisp); 87 97 unsigned int i; 88 98 int err = 0; 89 99 90 - for (i = 0; i < ctx->cfg->num_chars; i++) { 100 + for (i = 0; i < linedisp->num_chars; i++) { 91 101 err = regmap_write(ctx->regmap, 92 102 ctx->offset + (i * 8), ctx->curr[i]); 93 103 if (err) ··· 167 173 return 0; 168 174 } 169 175 170 - static void sead3_update(struct img_ascii_lcd_ctx *ctx) 176 + static void sead3_update(struct linedisp *linedisp) 171 177 { 178 + struct img_ascii_lcd_ctx *ctx = 179 + container_of(linedisp, struct img_ascii_lcd_ctx, linedisp); 172 180 unsigned int i; 173 181 int err = 0; 174 182 175 - for (i = 0; i < ctx->cfg->num_chars; i++) { 183 + for (i = 0; i < linedisp->num_chars; i++) { 176 184 err = sead3_wait_lcd_idle(ctx); 177 185 if (err) 178 186 break; ··· 215 219 MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches); 216 220 217 221 /** 218 - * img_ascii_lcd_scroll() - scroll the display by a character 219 - * @t: really a pointer to the private data structure 220 - * 221 - * Scroll the current message along the LCD by one character, rearming the 222 - * timer if required. 223 - */ 224 - static void img_ascii_lcd_scroll(struct timer_list *t) 225 - { 226 - struct img_ascii_lcd_ctx *ctx = from_timer(ctx, t, timer); 227 - unsigned int i, ch = ctx->scroll_pos; 228 - unsigned int num_chars = ctx->cfg->num_chars; 229 - 230 - /* update the current message string */ 231 - for (i = 0; i < num_chars;) { 232 - /* copy as many characters from the string as possible */ 233 - for (; i < num_chars && ch < ctx->message_len; i++, ch++) 234 - ctx->curr[i] = ctx->message[ch]; 235 - 236 - /* wrap around to the start of the string */ 237 - ch = 0; 238 - } 239 - 240 - /* update the LCD */ 241 - ctx->cfg->update(ctx); 242 - 243 - /* move on to the next character */ 244 - ctx->scroll_pos++; 245 - ctx->scroll_pos %= ctx->message_len; 246 - 247 - /* rearm the timer */ 248 - if (ctx->message_len > ctx->cfg->num_chars) 249 - mod_timer(&ctx->timer, jiffies + ctx->scroll_rate); 250 - } 251 - 252 - /** 253 - * img_ascii_lcd_display() - set the message to be displayed 254 - * @ctx: pointer to the private data structure 255 - * @msg: the message to display 256 - * @count: length of msg, or -1 257 - * 258 - * Display a new message @msg on the LCD. @msg can be longer than the number of 259 - * characters the LCD can display, in which case it will begin scrolling across 260 - * the LCD display. 261 - * 262 - * Return: 0 on success, -ENOMEM on memory allocation failure 263 - */ 264 - static int img_ascii_lcd_display(struct img_ascii_lcd_ctx *ctx, 265 - const char *msg, ssize_t count) 266 - { 267 - char *new_msg; 268 - 269 - /* stop the scroll timer */ 270 - del_timer_sync(&ctx->timer); 271 - 272 - if (count == -1) 273 - count = strlen(msg); 274 - 275 - /* if the string ends with a newline, trim it */ 276 - if (msg[count - 1] == '\n') 277 - count--; 278 - 279 - new_msg = devm_kmalloc(&ctx->pdev->dev, count + 1, GFP_KERNEL); 280 - if (!new_msg) 281 - return -ENOMEM; 282 - 283 - memcpy(new_msg, msg, count); 284 - new_msg[count] = 0; 285 - 286 - if (ctx->message) 287 - devm_kfree(&ctx->pdev->dev, ctx->message); 288 - 289 - ctx->message = new_msg; 290 - ctx->message_len = count; 291 - ctx->scroll_pos = 0; 292 - 293 - /* update the LCD */ 294 - img_ascii_lcd_scroll(&ctx->timer); 295 - 296 - return 0; 297 - } 298 - 299 - /** 300 - * message_show() - read message via sysfs 301 - * @dev: the LCD device 302 - * @attr: the LCD message attribute 303 - * @buf: the buffer to read the message into 304 - * 305 - * Read the current message being displayed or scrolled across the LCD display 306 - * into @buf, for reads from sysfs. 307 - * 308 - * Return: the number of characters written to @buf 309 - */ 310 - static ssize_t message_show(struct device *dev, struct device_attribute *attr, 311 - char *buf) 312 - { 313 - struct img_ascii_lcd_ctx *ctx = dev_get_drvdata(dev); 314 - 315 - return sprintf(buf, "%s\n", ctx->message); 316 - } 317 - 318 - /** 319 - * message_store() - write a new message via sysfs 320 - * @dev: the LCD device 321 - * @attr: the LCD message attribute 322 - * @buf: the buffer containing the new message 323 - * @count: the size of the message in @buf 324 - * 325 - * Write a new message to display or scroll across the LCD display from sysfs. 326 - * 327 - * Return: the size of the message on success, else -ERRNO 328 - */ 329 - static ssize_t message_store(struct device *dev, struct device_attribute *attr, 330 - const char *buf, size_t count) 331 - { 332 - struct img_ascii_lcd_ctx *ctx = dev_get_drvdata(dev); 333 - int err; 334 - 335 - err = img_ascii_lcd_display(ctx, buf, count); 336 - return err ?: count; 337 - } 338 - 339 - static DEVICE_ATTR_RW(message); 340 - 341 - /** 342 222 * img_ascii_lcd_probe() - probe an LCD display device 343 223 * @pdev: the LCD platform device 344 224 * ··· 227 355 { 228 356 const struct of_device_id *match; 229 357 const struct img_ascii_lcd_config *cfg; 358 + struct device *dev = &pdev->dev; 230 359 struct img_ascii_lcd_ctx *ctx; 231 360 int err; 232 361 233 - match = of_match_device(img_ascii_lcd_matches, &pdev->dev); 362 + match = of_match_device(img_ascii_lcd_matches, dev); 234 363 if (!match) 235 364 return -ENODEV; 236 365 237 366 cfg = match->data; 238 - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx) + cfg->num_chars, 239 - GFP_KERNEL); 367 + ctx = devm_kzalloc(dev, sizeof(*ctx) + cfg->num_chars, GFP_KERNEL); 240 368 if (!ctx) 241 369 return -ENOMEM; 242 370 243 371 if (cfg->external_regmap) { 244 - ctx->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); 372 + ctx->regmap = syscon_node_to_regmap(dev->parent->of_node); 245 373 if (IS_ERR(ctx->regmap)) 246 374 return PTR_ERR(ctx->regmap); 247 375 248 - if (of_property_read_u32(pdev->dev.of_node, "offset", 249 - &ctx->offset)) 376 + if (of_property_read_u32(dev->of_node, "offset", &ctx->offset)) 250 377 return -EINVAL; 251 378 } else { 252 379 ctx->base = devm_platform_ioremap_resource(pdev, 0); ··· 253 382 return PTR_ERR(ctx->base); 254 383 } 255 384 256 - ctx->pdev = pdev; 257 - ctx->cfg = cfg; 258 - ctx->message = NULL; 259 - ctx->scroll_pos = 0; 260 - ctx->scroll_rate = HZ / 2; 385 + err = linedisp_register(&ctx->linedisp, dev, cfg->num_chars, ctx->curr, 386 + cfg->update); 387 + if (err) 388 + return err; 261 389 262 - /* initialise a timer for scrolling the message */ 263 - timer_setup(&ctx->timer, img_ascii_lcd_scroll, 0); 390 + /* for backwards compatibility */ 391 + err = compat_only_sysfs_link_entry_to_kobj(&dev->kobj, 392 + &ctx->linedisp.dev.kobj, 393 + "message", NULL); 394 + if (err) 395 + goto err_unregister; 264 396 265 397 platform_set_drvdata(pdev, ctx); 266 - 267 - /* display a default message */ 268 - err = img_ascii_lcd_display(ctx, "Linux " UTS_RELEASE " ", -1); 269 - if (err) 270 - goto out_del_timer; 271 - 272 - err = device_create_file(&pdev->dev, &dev_attr_message); 273 - if (err) 274 - goto out_del_timer; 275 - 276 398 return 0; 277 - out_del_timer: 278 - del_timer_sync(&ctx->timer); 399 + 400 + err_unregister: 401 + linedisp_unregister(&ctx->linedisp); 279 402 return err; 280 403 } 281 404 ··· 286 421 { 287 422 struct img_ascii_lcd_ctx *ctx = platform_get_drvdata(pdev); 288 423 289 - device_remove_file(&pdev->dev, &dev_attr_message); 290 - del_timer_sync(&ctx->timer); 424 + sysfs_remove_link(&pdev->dev.kobj, "message"); 425 + linedisp_unregister(&ctx->linedisp); 291 426 return 0; 292 427 } 293 428
-3
drivers/auxdisplay/ks0108.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/kernel.h> 17 17 #include <linux/delay.h> 18 - #include <linux/fs.h> 19 - #include <linux/io.h> 20 18 #include <linux/parport.h> 21 - #include <linux/uaccess.h> 22 19 #include <linux/ks0108.h> 23 20 24 21 #define KS0108_NAME "ks0108"
+261
drivers/auxdisplay/line-display.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Character line display core support 4 + * 5 + * Copyright (C) 2016 Imagination Technologies 6 + * Author: Paul Burton <paul.burton@mips.com> 7 + * 8 + * Copyright (C) 2021 Glider bv 9 + */ 10 + 11 + #include <generated/utsrelease.h> 12 + 13 + #include <linux/device.h> 14 + #include <linux/module.h> 15 + #include <linux/slab.h> 16 + #include <linux/string.h> 17 + #include <linux/sysfs.h> 18 + #include <linux/timer.h> 19 + 20 + #include "line-display.h" 21 + 22 + #define DEFAULT_SCROLL_RATE (HZ / 2) 23 + 24 + /** 25 + * linedisp_scroll() - scroll the display by a character 26 + * @t: really a pointer to the private data structure 27 + * 28 + * Scroll the current message along the display by one character, rearming the 29 + * timer if required. 30 + */ 31 + static void linedisp_scroll(struct timer_list *t) 32 + { 33 + struct linedisp *linedisp = from_timer(linedisp, t, timer); 34 + unsigned int i, ch = linedisp->scroll_pos; 35 + unsigned int num_chars = linedisp->num_chars; 36 + 37 + /* update the current message string */ 38 + for (i = 0; i < num_chars;) { 39 + /* copy as many characters from the string as possible */ 40 + for (; i < num_chars && ch < linedisp->message_len; i++, ch++) 41 + linedisp->buf[i] = linedisp->message[ch]; 42 + 43 + /* wrap around to the start of the string */ 44 + ch = 0; 45 + } 46 + 47 + /* update the display */ 48 + linedisp->update(linedisp); 49 + 50 + /* move on to the next character */ 51 + linedisp->scroll_pos++; 52 + linedisp->scroll_pos %= linedisp->message_len; 53 + 54 + /* rearm the timer */ 55 + if (linedisp->message_len > num_chars && linedisp->scroll_rate) 56 + mod_timer(&linedisp->timer, jiffies + linedisp->scroll_rate); 57 + } 58 + 59 + /** 60 + * linedisp_display() - set the message to be displayed 61 + * @linedisp: pointer to the private data structure 62 + * @msg: the message to display 63 + * @count: length of msg, or -1 64 + * 65 + * Display a new message @msg on the display. @msg can be longer than the 66 + * number of characters the display can display, in which case it will begin 67 + * scrolling across the display. 68 + * 69 + * Return: 0 on success, -ENOMEM on memory allocation failure 70 + */ 71 + static int linedisp_display(struct linedisp *linedisp, const char *msg, 72 + ssize_t count) 73 + { 74 + char *new_msg; 75 + 76 + /* stop the scroll timer */ 77 + del_timer_sync(&linedisp->timer); 78 + 79 + if (count == -1) 80 + count = strlen(msg); 81 + 82 + /* if the string ends with a newline, trim it */ 83 + if (msg[count - 1] == '\n') 84 + count--; 85 + 86 + if (!count) { 87 + /* Clear the display */ 88 + kfree(linedisp->message); 89 + linedisp->message = NULL; 90 + linedisp->message_len = 0; 91 + memset(linedisp->buf, ' ', linedisp->num_chars); 92 + linedisp->update(linedisp); 93 + return 0; 94 + } 95 + 96 + new_msg = kmemdup_nul(msg, count, GFP_KERNEL); 97 + if (!new_msg) 98 + return -ENOMEM; 99 + 100 + kfree(linedisp->message); 101 + 102 + linedisp->message = new_msg; 103 + linedisp->message_len = count; 104 + linedisp->scroll_pos = 0; 105 + 106 + /* update the display */ 107 + linedisp_scroll(&linedisp->timer); 108 + 109 + return 0; 110 + } 111 + 112 + /** 113 + * message_show() - read message via sysfs 114 + * @dev: the display device 115 + * @attr: the display message attribute 116 + * @buf: the buffer to read the message into 117 + * 118 + * Read the current message being displayed or scrolled across the display into 119 + * @buf, for reads from sysfs. 120 + * 121 + * Return: the number of characters written to @buf 122 + */ 123 + static ssize_t message_show(struct device *dev, struct device_attribute *attr, 124 + char *buf) 125 + { 126 + struct linedisp *linedisp = container_of(dev, struct linedisp, dev); 127 + 128 + return sysfs_emit(buf, "%s\n", linedisp->message); 129 + } 130 + 131 + /** 132 + * message_store() - write a new message via sysfs 133 + * @dev: the display device 134 + * @attr: the display message attribute 135 + * @buf: the buffer containing the new message 136 + * @count: the size of the message in @buf 137 + * 138 + * Write a new message to display or scroll across the display from sysfs. 139 + * 140 + * Return: the size of the message on success, else -ERRNO 141 + */ 142 + static ssize_t message_store(struct device *dev, struct device_attribute *attr, 143 + const char *buf, size_t count) 144 + { 145 + struct linedisp *linedisp = container_of(dev, struct linedisp, dev); 146 + int err; 147 + 148 + err = linedisp_display(linedisp, buf, count); 149 + return err ?: count; 150 + } 151 + 152 + static DEVICE_ATTR_RW(message); 153 + 154 + static ssize_t scroll_step_ms_show(struct device *dev, 155 + struct device_attribute *attr, char *buf) 156 + { 157 + struct linedisp *linedisp = container_of(dev, struct linedisp, dev); 158 + 159 + return sysfs_emit(buf, "%u\n", jiffies_to_msecs(linedisp->scroll_rate)); 160 + } 161 + 162 + static ssize_t scroll_step_ms_store(struct device *dev, 163 + struct device_attribute *attr, 164 + const char *buf, size_t count) 165 + { 166 + struct linedisp *linedisp = container_of(dev, struct linedisp, dev); 167 + unsigned int ms; 168 + 169 + if (kstrtouint(buf, 10, &ms) != 0) 170 + return -EINVAL; 171 + 172 + linedisp->scroll_rate = msecs_to_jiffies(ms); 173 + if (linedisp->message && linedisp->message_len > linedisp->num_chars) { 174 + del_timer_sync(&linedisp->timer); 175 + if (linedisp->scroll_rate) 176 + linedisp_scroll(&linedisp->timer); 177 + } 178 + 179 + return count; 180 + } 181 + 182 + static DEVICE_ATTR_RW(scroll_step_ms); 183 + 184 + static struct attribute *linedisp_attrs[] = { 185 + &dev_attr_message.attr, 186 + &dev_attr_scroll_step_ms.attr, 187 + NULL, 188 + }; 189 + ATTRIBUTE_GROUPS(linedisp); 190 + 191 + static const struct device_type linedisp_type = { 192 + .groups = linedisp_groups, 193 + }; 194 + 195 + /** 196 + * linedisp_register - register a character line display 197 + * @linedisp: pointer to character line display structure 198 + * @parent: parent device 199 + * @num_chars: the number of characters that can be displayed 200 + * @buf: pointer to a buffer that can hold @num_chars characters 201 + * @update: Function called to update the display. This must not sleep! 202 + * 203 + * Return: zero on success, else a negative error code. 204 + */ 205 + int linedisp_register(struct linedisp *linedisp, struct device *parent, 206 + unsigned int num_chars, char *buf, 207 + void (*update)(struct linedisp *linedisp)) 208 + { 209 + static atomic_t linedisp_id = ATOMIC_INIT(-1); 210 + int err; 211 + 212 + memset(linedisp, 0, sizeof(*linedisp)); 213 + linedisp->dev.parent = parent; 214 + linedisp->dev.type = &linedisp_type; 215 + linedisp->update = update; 216 + linedisp->buf = buf; 217 + linedisp->num_chars = num_chars; 218 + linedisp->scroll_rate = DEFAULT_SCROLL_RATE; 219 + 220 + device_initialize(&linedisp->dev); 221 + dev_set_name(&linedisp->dev, "linedisp.%lu", 222 + (unsigned long)atomic_inc_return(&linedisp_id)); 223 + 224 + /* initialise a timer for scrolling the message */ 225 + timer_setup(&linedisp->timer, linedisp_scroll, 0); 226 + 227 + err = device_add(&linedisp->dev); 228 + if (err) 229 + goto out_del_timer; 230 + 231 + /* display a default message */ 232 + err = linedisp_display(linedisp, "Linux " UTS_RELEASE " ", -1); 233 + if (err) 234 + goto out_del_dev; 235 + 236 + return 0; 237 + 238 + out_del_dev: 239 + device_del(&linedisp->dev); 240 + out_del_timer: 241 + del_timer_sync(&linedisp->timer); 242 + put_device(&linedisp->dev); 243 + return err; 244 + } 245 + EXPORT_SYMBOL_GPL(linedisp_register); 246 + 247 + /** 248 + * linedisp_unregister - unregister a character line display 249 + * @linedisp: pointer to character line display structure registered previously 250 + * with linedisp_register() 251 + */ 252 + void linedisp_unregister(struct linedisp *linedisp) 253 + { 254 + device_del(&linedisp->dev); 255 + del_timer_sync(&linedisp->timer); 256 + kfree(linedisp->message); 257 + put_device(&linedisp->dev); 258 + } 259 + EXPORT_SYMBOL_GPL(linedisp_unregister); 260 + 261 + MODULE_LICENSE("GPL");
+43
drivers/auxdisplay/line-display.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Character line display core support 4 + * 5 + * Copyright (C) 2016 Imagination Technologies 6 + * Author: Paul Burton <paul.burton@mips.com> 7 + * 8 + * Copyright (C) 2021 Glider bv 9 + */ 10 + 11 + #ifndef _LINEDISP_H 12 + #define _LINEDISP_H 13 + 14 + /** 15 + * struct linedisp - character line display private data structure 16 + * @dev: the line display device 17 + * @timer: timer used to implement scrolling 18 + * @update: function called to update the display 19 + * @buf: pointer to the buffer for the string currently displayed 20 + * @message: the full message to display or scroll on the display 21 + * @num_chars: the number of characters that can be displayed 22 + * @message_len: the length of the @message string 23 + * @scroll_pos: index of the first character of @message currently displayed 24 + * @scroll_rate: scroll interval in jiffies 25 + */ 26 + struct linedisp { 27 + struct device dev; 28 + struct timer_list timer; 29 + void (*update)(struct linedisp *linedisp); 30 + char *buf; 31 + char *message; 32 + unsigned int num_chars; 33 + unsigned int message_len; 34 + unsigned int scroll_pos; 35 + unsigned int scroll_rate; 36 + }; 37 + 38 + int linedisp_register(struct linedisp *linedisp, struct device *parent, 39 + unsigned int num_chars, char *buf, 40 + void (*update)(struct linedisp *linedisp)); 41 + void linedisp_unregister(struct linedisp *linedisp); 42 + 43 + #endif /* LINEDISP_H */
+241
include/uapi/linux/map_to_14segment.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ 2 + /* 3 + * Copyright (C) 2021 Glider bv 4 + * 5 + * Based on include/uapi/linux/map_to_7segment.h: 6 + 7 + * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> 8 + */ 9 + 10 + #ifndef MAP_TO_14SEGMENT_H 11 + #define MAP_TO_14SEGMENT_H 12 + 13 + /* This file provides translation primitives and tables for the conversion 14 + * of (ASCII) characters to a 14-segments notation. 15 + * 16 + * The 14 segment's wikipedia notation below is used as standard. 17 + * See: https://en.wikipedia.org/wiki/Fourteen-segment_display 18 + * 19 + * Notation: +---a---+ 20 + * |\ | /| 21 + * f h i j b 22 + * | \|/ | 23 + * +-g1+-g2+ 24 + * | /|\ | 25 + * e k l m c 26 + * |/ | \| 27 + * +---d---+ 28 + * 29 + * Usage: 30 + * 31 + * Register a map variable, and fill it with a character set: 32 + * static SEG14_DEFAULT_MAP(map_seg14); 33 + * 34 + * 35 + * Then use for conversion: 36 + * seg14 = map_to_seg14(&map_seg14, some_char); 37 + * ... 38 + * 39 + * In device drivers it is recommended, if required, to make the char map 40 + * accessible via the sysfs interface using the following scheme: 41 + * 42 + * static ssize_t map_seg14_show(struct device *dev, 43 + * struct device_attribute *attr, char *buf) 44 + * { 45 + * memcpy(buf, &map_seg14, sizeof(map_seg14)); 46 + * return sizeof(map_seg14); 47 + * } 48 + * static ssize_t map_seg14_store(struct device *dev, 49 + * struct device_attribute *attr, 50 + * const char *buf, size_t cnt) 51 + * { 52 + * if (cnt != sizeof(map_seg14)) 53 + * return -EINVAL; 54 + * memcpy(&map_seg14, buf, cnt); 55 + * return cnt; 56 + * } 57 + * static DEVICE_ATTR_RW(map_seg14); 58 + */ 59 + #include <linux/errno.h> 60 + #include <linux/types.h> 61 + 62 + #include <asm/byteorder.h> 63 + 64 + #define BIT_SEG14_A 0 65 + #define BIT_SEG14_B 1 66 + #define BIT_SEG14_C 2 67 + #define BIT_SEG14_D 3 68 + #define BIT_SEG14_E 4 69 + #define BIT_SEG14_F 5 70 + #define BIT_SEG14_G1 6 71 + #define BIT_SEG14_G2 7 72 + #define BIT_SEG14_H 8 73 + #define BIT_SEG14_I 9 74 + #define BIT_SEG14_J 10 75 + #define BIT_SEG14_K 11 76 + #define BIT_SEG14_L 12 77 + #define BIT_SEG14_M 13 78 + #define BIT_SEG14_RESERVED1 14 79 + #define BIT_SEG14_RESERVED2 15 80 + 81 + struct seg14_conversion_map { 82 + __be16 table[128]; 83 + }; 84 + 85 + static __inline__ int map_to_seg14(struct seg14_conversion_map *map, int c) 86 + { 87 + if (c < 0 || c >= sizeof(map->table) / sizeof(map->table[0])) 88 + return -EINVAL; 89 + 90 + return __be16_to_cpu(map->table[c]); 91 + } 92 + 93 + #define SEG14_CONVERSION_MAP(_name, _map) \ 94 + struct seg14_conversion_map _name = { .table = { _map } } 95 + 96 + /* 97 + * It is recommended to use a facility that allows user space to redefine 98 + * custom character sets for LCD devices. Please use a sysfs interface 99 + * as described above. 100 + */ 101 + #define MAP_TO_SEG14_SYSFS_FILE "map_seg14" 102 + 103 + /******************************************************************************* 104 + * ASCII conversion table 105 + ******************************************************************************/ 106 + 107 + #define _SEG14(sym, a, b, c, d, e, f, g1, g2, h, j, k, l, m, n) \ 108 + __cpu_to_be16( a << BIT_SEG14_A | b << BIT_SEG14_B | \ 109 + c << BIT_SEG14_C | d << BIT_SEG14_D | \ 110 + e << BIT_SEG14_E | f << BIT_SEG14_F | \ 111 + g1 << BIT_SEG14_G1 | g2 << BIT_SEG14_G2 | \ 112 + h << BIT_SEG14_H | j << BIT_SEG14_I | \ 113 + k << BIT_SEG14_J | l << BIT_SEG14_K | \ 114 + m << BIT_SEG14_L | n << BIT_SEG14_M ) 115 + 116 + #define _MAP_0_32_ASCII_SEG14_NON_PRINTABLE \ 117 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 118 + 119 + #define _MAP_33_47_ASCII_SEG14_SYMBOL \ 120 + _SEG14('!', 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), \ 121 + _SEG14('"', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), \ 122 + _SEG14('#', 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0), \ 123 + _SEG14('$', 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0), \ 124 + _SEG14('%', 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0), \ 125 + _SEG14('&', 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1), \ 126 + _SEG14('\'',0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0), \ 127 + _SEG14('(', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1), \ 128 + _SEG14(')', 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0), \ 129 + _SEG14('*', 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1), \ 130 + _SEG14('+', 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0), \ 131 + _SEG14(',', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0), \ 132 + _SEG14('-', 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0), \ 133 + _SEG14('.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), \ 134 + _SEG14('/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0), 135 + 136 + #define _MAP_48_57_ASCII_SEG14_NUMERIC \ 137 + _SEG14('0', 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0), \ 138 + _SEG14('1', 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0), \ 139 + _SEG14('2', 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0), \ 140 + _SEG14('3', 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0), \ 141 + _SEG14('4', 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 142 + _SEG14('5', 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1), \ 143 + _SEG14('6', 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 144 + _SEG14('7', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0), \ 145 + _SEG14('8', 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 146 + _SEG14('9', 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0), 147 + 148 + #define _MAP_58_64_ASCII_SEG14_SYMBOL \ 149 + _SEG14(':', 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0), \ 150 + _SEG14(';', 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0), \ 151 + _SEG14('<', 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1), \ 152 + _SEG14('=', 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0), \ 153 + _SEG14('>', 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0), \ 154 + _SEG14('?', 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0), \ 155 + _SEG14('@', 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0), 156 + 157 + #define _MAP_65_90_ASCII_SEG14_ALPHA_UPPER \ 158 + _SEG14('A', 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 159 + _SEG14('B', 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0), \ 160 + _SEG14('C', 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 161 + _SEG14('D', 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0), \ 162 + _SEG14('E', 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0), \ 163 + _SEG14('F', 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0), \ 164 + _SEG14('G', 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0), \ 165 + _SEG14('H', 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 166 + _SEG14('I', 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0), \ 167 + _SEG14('J', 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), \ 168 + _SEG14('K', 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1), \ 169 + _SEG14('L', 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 170 + _SEG14('M', 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0), \ 171 + _SEG14('N', 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1), \ 172 + _SEG14('O', 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 173 + _SEG14('P', 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 174 + _SEG14('Q', 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1), \ 175 + _SEG14('R', 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1), \ 176 + _SEG14('S', 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0), \ 177 + _SEG14('T', 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0), \ 178 + _SEG14('U', 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 179 + _SEG14('V', 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0), \ 180 + _SEG14('W', 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1), \ 181 + _SEG14('X', 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1), \ 182 + _SEG14('Y', 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0), \ 183 + _SEG14('Z', 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0), 184 + 185 + #define _MAP_91_96_ASCII_SEG14_SYMBOL \ 186 + _SEG14('[', 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 187 + _SEG14('\\',0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), \ 188 + _SEG14(']', 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), \ 189 + _SEG14('^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1), \ 190 + _SEG14('_', 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), \ 191 + _SEG14('`', 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0), 192 + 193 + #define _MAP_97_122_ASCII_SEG14_ALPHA_LOWER \ 194 + _SEG14('a', 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0), \ 195 + _SEG14('b', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1), \ 196 + _SEG14('c', 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0), \ 197 + _SEG14('d', 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0), \ 198 + _SEG14('e', 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0), \ 199 + _SEG14('f', 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0), \ 200 + _SEG14('g', 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0), \ 201 + _SEG14('h', 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0), \ 202 + _SEG14('i', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0), \ 203 + _SEG14('j', 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0), \ 204 + _SEG14('k', 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1), \ 205 + _SEG14('l', 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), \ 206 + _SEG14('m', 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0), \ 207 + _SEG14('n', 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0), \ 208 + _SEG14('o', 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0), \ 209 + _SEG14('p', 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0), \ 210 + _SEG14('q', 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0), \ 211 + _SEG14('r', 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0), \ 212 + _SEG14('s', 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1), \ 213 + _SEG14('t', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0), \ 214 + _SEG14('u', 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), \ 215 + _SEG14('v', 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0), \ 216 + _SEG14('w', 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1), \ 217 + _SEG14('x', 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1), \ 218 + _SEG14('y', 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0), \ 219 + _SEG14('z', 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0), 220 + 221 + #define _MAP_123_126_ASCII_SEG14_SYMBOL \ 222 + _SEG14('{', 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0), \ 223 + _SEG14('|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0), \ 224 + _SEG14('}', 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1), \ 225 + _SEG14('~', 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0), 226 + 227 + /* Maps */ 228 + #define MAP_ASCII14SEG_ALPHANUM \ 229 + _MAP_0_32_ASCII_SEG14_NON_PRINTABLE \ 230 + _MAP_33_47_ASCII_SEG14_SYMBOL \ 231 + _MAP_48_57_ASCII_SEG14_NUMERIC \ 232 + _MAP_58_64_ASCII_SEG14_SYMBOL \ 233 + _MAP_65_90_ASCII_SEG14_ALPHA_UPPER \ 234 + _MAP_91_96_ASCII_SEG14_SYMBOL \ 235 + _MAP_97_122_ASCII_SEG14_ALPHA_LOWER \ 236 + _MAP_123_126_ASCII_SEG14_SYMBOL 237 + 238 + #define SEG14_DEFAULT_MAP(_name) \ 239 + SEG14_CONVERSION_MAP(_name, MAP_ASCII14SEG_ALPHANUM) 240 + 241 + #endif /* MAP_TO_14SEGMENT_H */