@@ -3,7 +3,6 @@ use cfg_if::cfg_if;
33cfg_if ! {
44 if #[ cfg( all( target_os = "linux" , not( target_env = "musl" ) , feature = "libudev" ) ) ] {
55 use std:: ffi:: OsStr ;
6- use regex:: Regex ;
76 }
87}
98
@@ -215,41 +214,9 @@ fn port_type(d: &libudev::Device) -> Result<SerialPortType> {
215214 )
216215 }
217216
218- // MODALIAS = usb:v303Ap1001d0101dcEFdsc02dp01ic02isc02ip00in00
219- // v 303A (device vendor)
220- // p 1001 (device product)
221- // d 0101 (bcddevice)
222- // dc EF (device class)
223- // dsc 02 (device subclass)
224- // dp 01 (device protocol)
225- // ic 02 (interface class)
226- // isc 02 (interface subclass)
227- // ip 00 (interface protocol)
228- // in 00 (interface number)
229- fn parse_modalias ( moda : String ) -> Option < UsbPortInfo > {
230- let re = Regex :: new ( concat ! (
231- r"usb:v(?P<vid>[[:xdigit:]]{4})" ,
232- r"p(?P<pid>[[:xdigit:]]{4})" ,
233- r".*" ,
234- r"in(?P<in>[[:xdigit:]]{2})"
235- ) )
236- . unwrap ( ) ;
237-
238- let caps = re. captures ( moda. as_str ( ) ) ?;
239-
240- Some ( UsbPortInfo {
241- vid : u16:: from_str_radix ( & caps[ "vid" ] , 16 ) . ok ( ) ?,
242- pid : u16:: from_str_radix ( & caps[ "pid" ] , 16 ) . ok ( ) ?,
243- serial_number : None ,
244- manufacturer : None ,
245- product : None ,
246- #[ cfg( feature = "usbportinfo-interface" ) ]
247- interface : u8:: from_str_radix ( & caps[ "in" ] , 16 ) . ok ( ) ,
248- } )
249- }
250-
251217 find_usb_interface_from_parents ( d. parent ( ) )
252218 . and_then ( get_modalias_from_device)
219+ . as_deref ( )
253220 . and_then ( parse_modalias)
254221 . map_or ( Ok ( SerialPortType :: Unknown ) , |port_info| {
255222 Ok ( SerialPortType :: UsbPort ( port_info) )
@@ -259,6 +226,51 @@ fn port_type(d: &libudev::Device) -> Result<SerialPortType> {
259226 }
260227}
261228
229+ // MODALIAS = usb:v303Ap1001d0101dcEFdsc02dp01ic02isc02ip00in00
230+ // v 303A (device vendor)
231+ // p 1001 (device product)
232+ // d 0101 (bcddevice)
233+ // dc EF (device class)
234+ // dsc 02 (device subclass)
235+ // dp 01 (device protocol)
236+ // ic 02 (interface class)
237+ // isc 02 (interface subclass)
238+ // ip 00 (interface protocol)
239+ // in 00 (interface number)
240+ #[ cfg( all( target_os = "linux" , not( target_env = "musl" ) , feature = "libudev" ) ) ]
241+ fn parse_modalias ( moda : & str ) -> Option < UsbPortInfo > {
242+ // Find the start of the string, will start with "usb:"
243+ let mod_start = moda. find ( "usb:v" ) ?;
244+
245+ // Tail to update while searching.
246+ let mut mod_tail = moda. get ( mod_start + 5 ..) ?;
247+
248+ // The next four characters should be hex values of the vendor.
249+ let vid = mod_tail. get ( ..4 ) ?;
250+ mod_tail = mod_tail. get ( 4 ..) ?;
251+
252+ // The next portion we care about is the device product ID.
253+ let pid_start = mod_tail. find ( 'p' ) ?;
254+ let pid = mod_tail. get ( pid_start + 1 ..pid_start + 5 ) ?;
255+
256+ Some ( UsbPortInfo {
257+ vid : u16:: from_str_radix ( vid, 16 ) . ok ( ) ?,
258+ pid : u16:: from_str_radix ( pid, 16 ) . ok ( ) ?,
259+ serial_number : None ,
260+ manufacturer : None ,
261+ product : None ,
262+ // Only attempt to find the interface if the feature is enabled.
263+ #[ cfg( feature = "usbportinfo-interface" ) ]
264+ interface : mod_tail. get ( pid_start + 4 ..) . and_then ( |mod_tail| {
265+ mod_tail. find ( "in" ) . and_then ( |i_start| {
266+ mod_tail
267+ . get ( i_start + 2 ..i_start + 4 )
268+ . and_then ( |interface| u8:: from_str_radix ( interface, 16 ) . ok ( ) )
269+ } )
270+ } ) ,
271+ } )
272+ }
273+
262274#[ cfg( any( target_os = "ios" , target_os = "macos" ) ) ]
263275fn get_parent_device_by_type (
264276 device : io_object_t ,
@@ -679,3 +691,17 @@ cfg_if! {
679691 }
680692 }
681693}
694+
695+ #[ cfg( all( target_os = "linux" , not( target_env = "musl" ) , feature = "libudev" ) ) ]
696+ #[ test]
697+ fn parser_modalias ( ) {
698+ const MODALIAS : & str = "usb:v303Ap1001d0101dcEFdsc02dp01ic02isc02ip00in0C" ;
699+
700+ let port_info = parse_modalias ( MODALIAS ) . expect ( "parse failed" ) ;
701+
702+ assert_eq ! ( port_info. vid, 0x303A , "vendor parse invalid" ) ;
703+ assert_eq ! ( port_info. pid, 0x1001 , "product parse invalid" ) ;
704+
705+ #[ cfg( feature = "usbportinfo-interface" ) ]
706+ assert_eq ! ( port_info. interface, Some ( 0x0C ) , "interface parse invalid" ) ;
707+ }
0 commit comments