今天從 CDC serial driver 的 setParameters 部分下手,
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
// UsbConstants.USB_TYPE_CLASS = 0x20
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) {
byte stopBitsByte;
switch (stopBits) {
case STOPBITS_1: stopBitsByte = 0; break;
case STOPBITS_1_5: stopBitsByte = 1; break;
case STOPBITS_2: stopBitsByte = 2; break;
default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits);
}
byte parityBitesByte;
switch (parity) {
case PARITY_NONE: parityBitesByte = 0; break;
case PARITY_ODD: parityBitesByte = 1; break;
case PARITY_EVEN: parityBitesByte = 2; break;
case PARITY_MARK: parityBitesByte = 3; break;
case PARITY_SPACE: parityBitesByte = 4; break;
default: throw new IllegalArgumentException("Bad value for parity: " + parity);
}
byte[] msg = {
(byte) ( baudRate & 0xff),
(byte) ((baudRate >> 8 ) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff),
stopBitsByte,
parityBitesByte,
(byte) dataBits}; // 共計 7 byte 的msg資料
sendAcmControlMessage(SET_LINE_CODING, 0, msg);
}
private int sendAcmControlMessage(int request, int value, byte[] buf) {
return mConnection.controlTransfer(
USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
}
上面是 CDC serial driver 的控制方式
下面是 Linux/drivers/usb/class/cdc-acm.c 針對 CDC 通訊控制中設定 serial port 參數的部分,我們先來看看有什麼不一樣 :
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
struct ktermios *termios = &tty->termios;
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); // 轉換成 little endian binary (32bit)
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) +
(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
switch (termios->c_cflag & CSIZE) {
case CS5:
newline.bDataBits = 5;
break;
case CS6:
newline.bDataBits = 6;
break;
case CS7:
newline.bDataBits = 7;
break;
case CS8:
default:
newline.bDataBits = 8;
break;
}
/* FIXME: Needs to clear unsupported bits in the termios */
acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
//這邊用到的 #define ACM_CTRL_DTR 0x01
if (!newline.dwDTERate) {
newline.dwDTERate = acm->line.dwDTERate;
newctrl &= ~ACM_CTRL_DTR; // ACM_CTRL_DTR 變成 0xFE 跟 newctrl 做 AND 運算
} else
newctrl |= ACM_CTRL_DTR; // 跟 newctrl 做 OR 運算
if (newctrl != acm->ctrlout)
acm_set_control(acm, acm->ctrlout = newctrl);
if (memcmp(&acm->line, &newline, sizeof newline)) {
memcpy(&acm->line, &newline, sizeof newline);
dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n",
__func__,
le32_to_cpu(newline.dwDTERate),
newline.bCharFormat, newline.bParityType,
newline.bDataBits);
acm_set_line(acm, &acm->line);
}
}
由上面可以看到他最後是交由
acm_set_control acm_set_line
送出控制指令,而上述這兩的 method 又全部把資料交到 acm_ctrl_msg( ) 這個 method 做分配。
而上述兩者 跟 acm_ctrl_msg 之間又做了那些動作呢? 我們留著明天在作進一步說明
我們明天見 :P
Ref :
http://lxr.free-electrons.com/source/drivers/usb/class/cdc-acm.c
http://lxr.free-electrons.com/source/drivers/usb/class/cdc-acm.h#L34
http://lxr.free-electrons.com/source/drivers/usb/core/message.c#L80
http://lxr.free-electrons.com/source/include/linux/usb.h#L1791
結語:
有沒有發現
(byte) ( baudRate & 0xff),
(byte) ((baudRate >> 8 ) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff),
跟
newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); // 轉換成 little endian binary (32bit)
兩個好像結果不太一樣? 似乎可以從這邊下手研究兩者異同之處 :P