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

Bluetooth: hci_uart: Add new line discipline enhancements

Added the ability to flow control the UART, improved the UART baud
rate setting, transferred the speeds into line discipline from the
protocol and introduced the tty init function.

Signed-off-by: Ilya Faenson <ifaenson@broadcom.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Ilya Faenson and committed by
Marcel Holtmann
2a973dfa 89e40428

+109 -6
+102 -6
drivers/bluetooth/hci_ldisc.c
··· 266 266 return 0; 267 267 } 268 268 269 + /* Flow control or un-flow control the device */ 270 + void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) 271 + { 272 + struct tty_struct *tty = hu->tty; 273 + struct ktermios ktermios; 274 + int status; 275 + unsigned int set = 0; 276 + unsigned int clear = 0; 277 + 278 + if (enable) { 279 + /* Disable hardware flow control */ 280 + ktermios = tty->termios; 281 + ktermios.c_cflag &= ~CRTSCTS; 282 + status = tty_set_termios(tty, &ktermios); 283 + BT_DBG("Disabling hardware flow control: %s", 284 + status ? "failed" : "success"); 285 + 286 + /* Clear RTS to prevent the device from sending */ 287 + /* Most UARTs need OUT2 to enable interrupts */ 288 + status = tty->driver->ops->tiocmget(tty); 289 + BT_DBG("Current tiocm 0x%x", status); 290 + 291 + set &= ~(TIOCM_OUT2 | TIOCM_RTS); 292 + clear = ~set; 293 + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 294 + TIOCM_OUT2 | TIOCM_LOOP; 295 + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 296 + TIOCM_OUT2 | TIOCM_LOOP; 297 + status = tty->driver->ops->tiocmset(tty, set, clear); 298 + BT_DBG("Clearing RTS: %s", status ? "failed" : "success"); 299 + } else { 300 + /* Set RTS to allow the device to send again */ 301 + status = tty->driver->ops->tiocmget(tty); 302 + BT_DBG("Current tiocm 0x%x", status); 303 + 304 + set |= (TIOCM_OUT2 | TIOCM_RTS); 305 + clear = ~set; 306 + set &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 307 + TIOCM_OUT2 | TIOCM_LOOP; 308 + clear &= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | 309 + TIOCM_OUT2 | TIOCM_LOOP; 310 + status = tty->driver->ops->tiocmset(tty, set, clear); 311 + BT_DBG("Setting RTS: %s", status ? "failed" : "success"); 312 + 313 + /* Re-enable hardware flow control */ 314 + ktermios = tty->termios; 315 + ktermios.c_cflag |= CRTSCTS; 316 + status = tty_set_termios(tty, &ktermios); 317 + BT_DBG("Enabling hardware flow control: %s", 318 + status ? "failed" : "success"); 319 + } 320 + } 321 + 322 + void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, 323 + unsigned int oper_speed) 324 + { 325 + hu->init_speed = init_speed; 326 + hu->oper_speed = oper_speed; 327 + } 328 + 329 + void hci_uart_init_tty(struct hci_uart *hu) 330 + { 331 + struct tty_struct *tty = hu->tty; 332 + struct ktermios ktermios; 333 + 334 + /* Bring the UART into a known 8 bits no parity hw fc state */ 335 + ktermios = tty->termios; 336 + ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 337 + INLCR | IGNCR | ICRNL | IXON); 338 + ktermios.c_oflag &= ~OPOST; 339 + ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 340 + ktermios.c_cflag &= ~(CSIZE | PARENB); 341 + ktermios.c_cflag |= CS8; 342 + ktermios.c_cflag |= CRTSCTS; 343 + 344 + /* tty_set_termios() return not checked as it is always 0 */ 345 + tty_set_termios(tty, &ktermios); 346 + } 347 + 269 348 void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed) 270 349 { 271 350 struct tty_struct *tty = hu->tty; ··· 352 273 353 274 ktermios = tty->termios; 354 275 ktermios.c_cflag &= ~CBAUD; 355 - ktermios.c_cflag |= BOTHER; 356 276 tty_termios_encode_baud_rate(&ktermios, speed, speed); 357 277 358 278 /* tty_set_termios() return not checked as it is always 0 */ 359 279 tty_set_termios(tty, &ktermios); 360 280 361 - BT_DBG("%s: New tty speed: %d", hu->hdev->name, tty->termios.c_ispeed); 281 + BT_DBG("%s: New tty speeds: %d/%d", hu->hdev->name, 282 + tty->termios.c_ispeed, tty->termios.c_ospeed); 362 283 } 363 284 364 285 static int hci_uart_setup(struct hci_dev *hdev) ··· 366 287 struct hci_uart *hu = hci_get_drvdata(hdev); 367 288 struct hci_rp_read_local_version *ver; 368 289 struct sk_buff *skb; 290 + unsigned int speed; 369 291 int err; 370 292 293 + /* Init speed if any */ 371 294 if (hu->proto->init_speed) 372 - hci_uart_set_baudrate(hu, hu->proto->init_speed); 295 + speed = hu->proto->init_speed; 296 + else if (hu->init_speed) 297 + speed = hu->init_speed; 298 + else 299 + speed = 0; 373 300 374 - if (hu->proto->set_baudrate && hu->proto->oper_speed) { 375 - err = hu->proto->set_baudrate(hu, hu->proto->oper_speed); 301 + if (speed) 302 + hci_uart_set_baudrate(hu, speed); 303 + 304 + /* Operational speed if any */ 305 + if (hu->proto->oper_speed) 306 + speed = hu->proto->oper_speed; 307 + else if (hu->oper_speed) 308 + speed = hu->oper_speed; 309 + else 310 + speed = 0; 311 + 312 + if (hu->proto->set_baudrate && speed) { 313 + err = hu->proto->set_baudrate(hu, speed); 376 314 if (!err) 377 - hci_uart_set_baudrate(hu, hu->proto->oper_speed); 315 + hci_uart_set_baudrate(hu, speed); 378 316 } 379 317 380 318 if (hu->proto->setup)
+7
drivers/bluetooth/hci_uart.h
··· 85 85 struct sk_buff *tx_skb; 86 86 unsigned long tx_state; 87 87 spinlock_t rx_lock; 88 + 89 + unsigned int init_speed; 90 + unsigned int oper_speed; 88 91 }; 89 92 90 93 /* HCI_UART proto flag bits */ ··· 102 99 int hci_uart_unregister_proto(const struct hci_uart_proto *p); 103 100 int hci_uart_tx_wakeup(struct hci_uart *hu); 104 101 int hci_uart_init_ready(struct hci_uart *hu); 102 + void hci_uart_init_tty(struct hci_uart *hu); 105 103 void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed); 104 + void hci_uart_set_flow_control(struct hci_uart *hu, bool enable); 105 + void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed, 106 + unsigned int oper_speed); 106 107 107 108 #ifdef CONFIG_BT_HCIUART_H4 108 109 int h4_init(void);