ラズベリーパイにMOXA社UPort11xxドライバをインストールする

# はじめに
MOXA社製UPort11xxもRasPiで使用が可能
ただし、HPでDLできるものはSRCのため、ARMアーキテクチャ用（RasPiCPU用）にビルドする必要がある。
Kernel6.x対応
## MOXA社のHP↓
https://www.moxa.com/jp/products/industrial-edge-connectivity/usb-to-serial-converters-usb-hubs/usb-to-serial-converters/uport-1100-series

## ドライバDLサイト
https://www.moxa.com/jp/products/industrial-edge-connectivity/usb-to-serial-converters-usb-hubs/usb-to-serial-converters/uport-1100-series#resources
# 対応するLinuxカーネルの選択
対応するLinuxカーネルを選択するためにRasPi側のOSカーネルバージョンを調べる↓

```
uname -r
uname -a
uname -m
```

## Kernel 6.xにおける不具合
### 不具合 rasPi5 kernel6.6.x時
2024年10月10日時点ではRaspberry Pi(5)のKernel6.6.51+rpt-rpi-2712に合わせて
最新版6.0をセットアップしたところ以下の不具合が確認されている。

```
************************************************************************
 Debian GNU/Linux 12 
 \l 6.6.31+rpt-rpi-2712
 MOXA UPort 11x0 series driver ver 6.0
 Release Date: 2023/03/14
************************************************************************
**********************************WARNING*******************************
 MOXA UPort 11x0 series driver hes been tested under kernel 6.2.0
 That may not be compatible with Linux Kernel version 6.6.31+rpt-rpi-2712 .
 Please download the latest driver at http://www.moxa.com first.
 If you still have issue, you can contact support@moxa.com 
************************************************************************
  *******************************************************************
    MOXA UPort 11x0 series USB to Serial Hub Driver v6.0      
                                                                     
                   release date : 2023/03/14                        
  *******************************************************************
Build unsuccessfully! Please check build.log for further information
make[1]: *** [Makefile:63: module] Error 1
make: *** [Makefile:16: install] Error 2
```

*現時点でのUPortドライバの確認はkernel6.2.0での確認まで
*6.6.31xxxでのコンパチは確認できない
*実際ビルドエラーが発生している

エラーの内容は以下の理由による。
* usb_serial_driver構造体の.break_ctl変数（関数へのポインタ）に割り当てられる関数の戻り値仕様の変更による（build.logの内容より）
* 従来はvoid型
* 最新はint型　おそらく→ <linux/usb/serial.h>に記載（面倒くさいので確認はしていない）

#### 対策
* カーネルを旧バージョンに戻してもよいが、最新カーネルを使いたいので、ソースを変更する。
* 変更ソースはmxu11x0.cのみ
* 修正関数はmxu1_break関数（の戻り値）

修正箇所は以下：
199行目付近
```
- static void mxu1_break(struct tty_struct *tty, int break_state); # ←void型
+ static int mxu1_break(struct tty_struct *tty, int break_state); # ←int型
```

1737行目付近 (-をコメントアウトまたは削除／+を追加）
```
#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
static void mxu1_break(struct usb_serial_port *port, int break_state)
{
#else
- static void mxu1_break(struct tty_struct *tty, int break_state)
+ static int mxu1_break(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
#endif

	struct mxu1_port *mxport = usb_get_serial_port_data(port);

	dbg("%s - state = %d", __FUNCTION__, break_state);

	if (mxport == NULL)
		//return;
+		return 0;

	mxu1_drain(mxport, (mxport->mxp_closing_wait*HZ)/100, 0);

	if(break_state == -1)
		mxport->mxp_send_break = MXU1_LCR_BREAK;
	else
		mxport->mxp_send_break = 0;
#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
	mxu1_set_termios(mxport->mxp_port,NULL);
#else
	mxu1_set_termios(NULL, mxport->mxp_port,NULL);
#endif
+	return 0;	
}
```
* 修正したら再度ビルドする
* 上記ソース変更については過去のカーネルの動作は保証できないので各々で修正方法は工夫すること
### 不具合　kernel6.1時
2023年5月9日時点ではRaspberry Pi(4)のKernel6.1.21に合わせて
最新版6.xがUPされている。
Driver for UPort 1100 Series (Linux kernel 6.x)
本Verにおいては、V5.1xでの不具合とmxu11x0.cのソース修正は対策されており不要である。
ただし、Raspberry Pi側の不具合により以下の対応が必要になる。

#### RasPi OS 32bitをkernelアップデートした場合に64bit表示になってしまう。
当方所有のRasPi OSは32bitでセットアップしているにもかかわらず
2023年5月時点においてupdateしたところカーネルはｖ6.1.21にUpdateされたが
どうやら64bitの設定にセットアップされてしまっているようであった。
（本件はバグかどうか現時点で不明）
現象としては以下のコマンドにより確認できる。
```
uname -r
　-> 6.1.21-v8+
uname -m
　-> aarch64
```


#### 対策方法
/boot/config.txt
に
arm_64bit=0
を追記する

```
sudo nano /boot/config.txt
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973387/6ae441b5-3ecb-95da-1067-91b9047aaed7.png)
これにより以下となり、不具合はなんとか解消される。
```
uname -r
　-> 6.1.21-v7l+
uname -m
　-> armv7l
```
https://zenn.dev/matsujirushi/scraps/53a08cb853ea0e


## Kernel 5.xにおける不具合
2021年9月2日時点での最新版5.1がUPされているが↓
Driver for UPort 1100 Series (Linux kernel 5.x)
本Verは5.10.103-v7lまでは動作確認済
ただし5.15.32-v7lでは動作しないので注意
``` ビルドエラーメッセージ
mxu11x0/driver/mxu11x0.c:341:21: error: initialization of ‘unsigned int (*)(struct tty_struct *)’ from incompatible pointer type ‘int (*)(struct tty_struct *)’ [-Werror=incompatible-pointer-types]
```

### 暫定対策 (kernel v6.1.21では不要）
・mxu11x0\mxu11x0.cを修正する
具体的には以下の２つの関数の戻り値をint⇒unsigned intに修正する。
static int mxu1_write_room(struct tty_struct *tty);
static int mxu1_chars_in_buffer(struct tty_struct *tty);

ソースの修正箇所については以下の通り
``` mxu11x0.c 162-163行
static unsigned int mxu1_write_room(struct tty_struct *tty);
static unsigned int mxu1_chars_in_buffer(struct tty_struct *tty);
```

``` mxu11x0.c 1130-1183行
#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
static int mxu1_write_room(struct usb_serial_port *port)
{
#else
static unsigned int mxu1_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
#endif

	
	struct mxu1_port *mxport = usb_get_serial_port_data(port);
	int room = 0;
	unsigned long flags;

	dbg("%s - port %d", __FUNCTION__, port->port_number);

	if (mxport == NULL)
		return -ENODEV;
	
	spin_lock_irqsave(&mxport->mxp_lock, flags);
	room = mxu1_buf_space_avail(mxport->mxp_write_buf);
	spin_unlock_irqrestore(&mxport->mxp_lock, flags);

	dbg("%s - returns %d", __FUNCTION__, room);

	return room;
}

#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
static int mxu1_chars_in_buffer(struct usb_serial_port *port)
{
#else
static unsigned int mxu1_chars_in_buffer(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
#endif

	struct mxu1_port *mxport = usb_get_serial_port_data(port);
	int chars = 0;
	unsigned long flags;

	dbg("%s - port %d", __FUNCTION__, port->port_number);

	if (mxport == NULL)
		return -ENODEV;

	spin_lock_irqsave(&mxport->mxp_lock, flags);
	chars = mxu1_buf_data_avail(mxport->mxp_write_buf);
	spin_unlock_irqrestore(&mxport->mxp_lock, flags);

	dbg("%s - returns %d", __FUNCTION__, chars);

	return chars;
}
```


# DLと解凍
moxa-uport-1100-series-linux-kernel-6.x-driver-v6.x.tgzを解凍
moxa-uport-1100-series-linux-kernel-6.x-driver-v6.x\readme.txt を参照（手順が記載されている）
2. System Requirements
3. Installation
はななめ読みする。
3.3 Module driver configuration
   3.3.1 Build the MOXA driver
   3.3.2 Load the MOXA driver
を実施する（以下の方法で）　3.4は不要
# インストール
## 事前知識↓
### Raspi上でドライバをインストールする。
インストールの方法は
・クロス環境（ＰＣ等）でビルドし、ターゲットシステムにロードする
・ネイティブ環境（この場合ターゲットシステムで直接）でビルドし、設定の上使用する。
今回はネイティブ環境でビルドする。　すなわち後者で行う。
### ワークフォルダ（例）
RasPiのセットアップ例にて
/home/pi/share/driver
の作成および実行権限、読書権限をしている前提での説明となる。
 
## 準備
### 1.ビルド
ネイティブ環境でビルドする場合でもカーネルの機能にアクセスするためのカーネルヘッダ等が必要になります。下記コマンドでインストールする

```
sudo apt-get install raspberrypi-kernel-headers
```

/usr/srcにファイルが展開される
参考URL
https://qiita.com/iwatake2222/items/1fdd2e0faaaa868a2db2
 
### 2.MOXA UPortドライバDLファイルの配置（例）
以下にドライバを展開する(mxu11x0フォルダ）

```
cd ﻿/home/pi/share/driver
```

/home/pi/share/driver/mxu11x0に移動する

```
cd mxu11x0
```
必要に応じて実行権限をつける

```
chmod -R 0755 .
```

以下のコマンドでインストール

```
sudo make clean
sudo make install
```

カーネルモジュールをロードし、確認する

```
sudo modprobe mxu11x0
lsmod
```

###【参考】
以下ｍの通りlibフォルダへのコピーまで実施してくれる
@cp -f ./$(TARGET).ko /lib/modules/$(KVER)/misc/
 
インストールは以上
 
# SetserialによるConfiguration
## setserialのインストール
インストール後、UPort1150の機能設定を行うためにインストールが必要
マルチポート動作できるのでRS422で動かしたい場合は明示的にRS422で動作させる設定が必要
 
インストールは以下でできる

```
sudo apt install setserial
```

portの設定をすることでRS422に設定できる。
   port     0       RS-232
               1       RS-485 2W
               2       RS-422
               3       RS-485 4W
﻿setserial /dev/ttyUSB0 port 2
どうやら電源断により上記設定は失われる。
保存の方法は別途調査する。