Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Line 6 Linux USB driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #ifndef DRIVER_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #define DRIVER_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/kfifo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include "midi.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) /* USB 1.1 speed configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #define USB_LOW_INTERVALS_PER_SECOND 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #define USB_LOW_ISO_BUFFERS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) /* USB 2.0+ speed configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #define USB_HIGH_INTERVALS_PER_SECOND 8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #define USB_HIGH_ISO_BUFFERS 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) /* Fallback USB interval and max packet size values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define LINE6_FALLBACK_INTERVAL 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #define LINE6_FALLBACK_MAXPACKETSIZE 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define LINE6_TIMEOUT 1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define LINE6_BUFSIZE_LISTEN 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define LINE6_MIDI_MESSAGE_MAXLEN 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define LINE6_RAW_MESSAGES_MAXCOUNT_ORDER 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) /* 4k packets are common, BUFSIZE * MAXCOUNT should be bigger... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #define LINE6_RAW_MESSAGES_MAXCOUNT (1 << LINE6_RAW_MESSAGES_MAXCOUNT_ORDER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #if LINE6_BUFSIZE_LISTEN > 65535
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #error "Use dynamic fifo instead"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	Line 6 MIDI control commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define LINE6_PARAM_CHANGE   0xb0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define LINE6_PROGRAM_CHANGE 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) #define LINE6_SYSEX_BEGIN    0xf0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #define LINE6_SYSEX_END      0xf7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #define LINE6_RESET          0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	MIDI channel for messages initiated by the host
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	(and eventually echoed back by the device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #define LINE6_CHANNEL_HOST   0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	MIDI channel for messages initiated by the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #define LINE6_CHANNEL_DEVICE 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) #define LINE6_CHANNEL_UNKNOWN 5	/* don't know yet what this is good for */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) #define LINE6_CHANNEL_MASK 0x0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) extern const unsigned char line6_midi_id[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) #define SYSEX_DATA_OFS (sizeof(line6_midi_id) + 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) #define SYSEX_EXTRA_SIZE (sizeof(line6_midi_id) + 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	 Common properties of Line 6 devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) struct line6_properties {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	/* Card id string (maximum 16 characters).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	 * This can be used to address the device in ALSA programs as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	 * "default:CARD=<id>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	const char *id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	/* Card short name (maximum 32 characters) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	/* Bit vector defining this device's capabilities in line6usb driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	int capabilities;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	int altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	unsigned int ctrl_if;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	unsigned int ep_ctrl_r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	unsigned int ep_ctrl_w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	unsigned int ep_audio_r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	unsigned int ep_audio_w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) /* Capability bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	/* device supports settings parameter via USB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	LINE6_CAP_CONTROL =	1 << 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	/* device supports PCM input/output via USB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	LINE6_CAP_PCM =		1 << 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	/* device supports hardware monitoring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	LINE6_CAP_HWMON =	1 << 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	/* device requires output data when input is read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	LINE6_CAP_IN_NEEDS_OUT = 1 << 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	/* device uses raw MIDI via USB (data endpoints) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	LINE6_CAP_CONTROL_MIDI = 1 << 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	/* device provides low-level information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	LINE6_CAP_CONTROL_INFO = 1 << 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	/* device provides hardware monitoring volume control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	LINE6_CAP_HWMON_CTL =	1 << 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	 Common data shared by all Line 6 devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	 Corresponds to a pair of USB endpoints.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct usb_line6 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	/* USB device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	struct usb_device *usbdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	/* Properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	const struct line6_properties *properties;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	/* Interval for data USB packets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	int interval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	/* ...for isochronous transfers framing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	int intervals_per_second;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	/* Number of isochronous URBs used for frame transfers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	int iso_buffers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	/* Maximum size of data USB packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	int max_packet_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	/* Device representing the USB interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	struct device *ifcdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	/* Line 6 sound card data structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	 * Each device has at least MIDI or PCM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	/* Line 6 PCM device data structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	struct snd_line6_pcm *line6pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	/* Line 6 MIDI device data structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct snd_line6_midi *line6midi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	/* URB for listening to POD data endpoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	struct urb *urb_listen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	/* Buffer for incoming data from POD data endpoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	unsigned char *buffer_listen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	/* Buffer for message to be processed, generated from MIDI layer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	unsigned char *buffer_message;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	/* Length of message to be processed, generated from MIDI layer  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	int message_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	/* Circular buffer for non-MIDI control messages */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		struct mutex read_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		wait_queue_head_t wait_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		unsigned int active:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		unsigned int nonblock:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		STRUCT_KFIFO_REC_2(LINE6_BUFSIZE_LISTEN * LINE6_RAW_MESSAGES_MAXCOUNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			fifo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	} messages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	/* Work for delayed PCM startup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	struct delayed_work startup_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	/* If MIDI is supported, buffer_message contains the pre-processed data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	 * otherwise the data is only in urb_listen (buffer_incoming).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	void (*process_message)(struct usb_line6 *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	void (*disconnect)(struct usb_line6 *line6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	void (*startup)(struct usb_line6 *line6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 				      int code2, int size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) extern int line6_read_data(struct usb_line6 *line6, unsigned address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 			   void *data, unsigned datalen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) extern int line6_read_serial_number(struct usb_line6 *line6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 				    u32 *serial_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) extern int line6_send_raw_message(struct usb_line6 *line6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 					const char *buffer, int size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) extern int line6_send_raw_message_async(struct usb_line6 *line6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 					const char *buffer, int size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) extern int line6_send_sysex_message(struct usb_line6 *line6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 				    const char *buffer, int size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 			     const char *buf, size_t count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) extern int line6_version_request_async(struct usb_line6 *line6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) extern int line6_write_data(struct usb_line6 *line6, unsigned address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 			    void *data, unsigned datalen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int line6_probe(struct usb_interface *interface,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		const struct usb_device_id *id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		const char *driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		const struct line6_properties *properties,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 		int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		size_t data_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) void line6_disconnect(struct usb_interface *interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int line6_suspend(struct usb_interface *interface, pm_message_t message);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int line6_resume(struct usb_interface *interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) #endif