#!/usr/bin/perl use strict; use warnings; use File::Find; use Data::Dumper; use File::Spec; use Data::Dumper; ######################################################################## ######################################################################## { package usb::dev; our $base='/sys/bus/usb/devices/'; sub new { my $class=shift; my $self={}; $self->{id}=shift(); $self->{path}=shift(); bless($self,$class); } sub id { $_[0]->{id}; } sub path { $base.$_[0]->{path}; } sub childs { my $self=shift; my @l; for my $path (glob($base.$self->{path}.'/*')) { next unless($path=~m#/([\d.-]+)$#); my $id=$1; $path=~s/^\Q$base\E//; push(@l,usb::dev->new($id,$path)); } return @l; } sub product { my $self=shift; open(my $fh, '<', $base.$self->{path}."/product") or return ''; my $n=<$fh>; chomp($n); return $n; } sub id_product { my $self=shift; open(my $fh, '<', $base.$self->{path}."/idProduct") or return ''; my $n=<$fh>; chomp($n); return $n; } sub id_vendor { my $self=shift; open(my $fh, '<', $base.$self->{path}."/idVendor") or return ''; my $n=<$fh>; chomp($n); return $n; } sub version { my $self=shift; open(my $fh, '<', $base.$self->{path}."/version") or return ''; my $n=<$fh>; chomp($n); return $n; } sub uevent { my $self=shift; open(my $fh, '<', $base.$self->{path}."/uevent") or return {}; my $ret={}; while(my $line=<$fh>) { chomp($line); next unless($line=~/^\s*(\w+)=(.*?)$/); $ret->{$1}=$2; } close($fh); return $ret; } sub interfaces { my $self=shift; open(my $fh, '<', $base.$self->{path}."/version") or return ''; my $n=<$fh>; chomp($n); close($fh); return () unless($n); my @ret; for my $id (1..$n) { my $p=$base.$self->{path}.'/'.$self->id().":$id.0"; next unless(-d $p); push(@ret,usb::dev::Interface->new($p)); } return @ret; } sub inputs { my $self=shift; my @ret; my $p=$base.$self->{path}.'/input'; if(-d $p) { for my $inp (glob($p.'/*')) { push(@ret, usb::dev::Input->new($inp)); } } return @ret; } 1; } #----------------------------------------------------------------------- { package usb::dev::Interface; sub new { my $class=shift; my $self={}; $self->{path}=shift; bless($self,$class); } sub path{ $_[0]->{path}; } sub uevent { my $self=shift; open(my $fh, '<', $self->{path}."/uevent") or return {}; my $ret={}; while(my $line=<$fh>) { chomp($line); next unless($line=~/^\s*(\w+)=(.*?)$/); $ret->{$1}=$2; } close($fh); return $ret; } sub driver { my $self=shift; my $name=$self->uevent()->{DRIVER}; return usb::dev::Driver->new($name) if($name); return undef; } sub inputs { my $self=shift; my $p=$self->{path}.'/input'; return () unless(-d $p); my @ret; for my $inp (glob($p.'/*')) { push(@ret, usb::dev::Input->new($inp)); } return @ret; } 1; } #----------------------------------------------------------------------- { package usb::dev::Input; sub new { my $class=shift; my $self={}; $self->{__path}=shift; bless($self,$class); $self->_read(); return $self; } sub path{ $_[0]->{__path}; } sub id { my $self=shift(); my $name=$self->path(); $name=~s#^.+/##; return $name; } sub name { $_[0]->{NAME} // '???'; } sub phys { $_[0]->{PHYS} // '???'; } sub product { $_[0]->{PRODUCT} // '???'; } sub _read { my $self=shift; open(my $fh, '<', $self->path()."/uevent") or return; while(my $line=<$fh>) { chomp($line); next unless($line=~/^\s*(\w+)=(.*?)$/); $self->{$1}=$2; } close($fh); } sub events { my $self=shift; my @ret; for my $p (glob($self->path().'/event*')) { next unless(-d $p); push(@ret,usb::dev::Input::Event->new($p)); } return @ret; } 1; } { package usb::dev::Input::Event; sub new { my $class=shift; my $self={}; $self->{__path}=shift; bless($self,$class); $self->_read(); return $self; } sub path{ $_[0]->{__path}; } sub name { my $self=shift(); my $name=$self->path(); $name=~s#^.+/##; return $name; } sub major { $_[0]->{MAJOR} // '???'; } sub minor { $_[0]->{MINOR} // '???'; } sub device { '/dev/'.($_[0]->{DEVNAME} // '???'); } sub _read { my $self=shift; open(my $fh, '<', $self->path()."/uevent") or return; while(my $line=<$fh>) { chomp($line); next unless($line=~/^\s*(\w+)=(.*?)$/); $self->{$1}=$2; } close($fh); } 1; } #----------------------------------------------------------------------- { package usb::dev::Driver; my $path='/sys/bus/usb/drivers/'; sub new { my $class=shift; my $name=shift; return undef unless(-d $path.$name); my $driver=File::Spec->rel2abs($path.$name,readlink($path.$name.'module')); my $self={}; $self->{name}=$name; $self->{path}=$driver; bless($self,$class); } sub name{ $_[0]->{name}; } sub module_name { my $self=shift; my $name=readlink($self->{path}."/module"); $name=~s#^.+/##; return $name; } sub module { return sys::Module->new($_[0]->module_name()) } 1;} #----------------------------------------------------------------------- { package sys::Module; my $path='/sys/module/'; sub new { my $class=shift; my $name=shift; return undef unless(-d $path.$name); my $self={}; $self->{name}=$name; bless($self,$class); } sub name{ $_[0]->{name}; } sub drivers { my $self=shift; return map{s#^.*/##; $_}grep{!/\./}glob($path.$self->{name}.'/drivers/*'); } sub holders { my $self=shift; return map{s#^.*/##; $_}grep{!/\./}glob($path.$self->{name}.'/holders/*'); } sub state { my $self=shift; my $ret='UNKNOWN'; open(my $fh, '<', $path.$self->{name}.'/initstate') or return $ret; $ret=<$fh>; chomp($ret); return $ret; } sub count { my $self=shift; my $ret=-1; open(my $fh, '<', $path.$self->{name}.'/refcnt') or return $ret; $ret=<$fh>; chomp($ret); return $ret; } 1;} ######################################################################## ######################################################################## package main; my @devices; for my $path (glob("$usb::dev::base/usb*")) { next unless($path=~/(\d+)$/); my $id=$1; push(@devices,usb::dev->new($id,"usb$id")); } print "ALL USB-DEVICES\n"; for(@devices) { list(' ',$_); } ######################################################################## sub list { my $s=shift() // ''; my $dev=shift; print_out($s,$dev); my @childs=$dev->childs(); if(@childs) { print "\n".$s."CHILDS:\n"; for(@childs) { #print_out("$s ",$_); list("$s ",$_); print "$s ####################\n"; } } } sub print_out { my $s=shift; my $dev=shift; print $s."PATH = ".$dev->path()."\n"; print $s."ID = ".$dev->id()."\n"; print $s."TYP = ".$dev->product()."\n"; print $s."PRODUKT = ".$dev->id_vendor().":".$dev->id_product()."(".$dev->version().")"."\n"; print $s."...\n"; print format_hash($s,$dev->uevent()); my @if=$dev->interfaces(); if(@if) { print $s."INTERFACES:\n"; for my $if(@if) { print format_interface("$s ",$if); print "$s ====================\n"; } } my @inp=$dev->inputs(); if(@inp) { print $s."INPUTS:\n"; for($dev->inputs()) { print format_input("$s ",$_); print "$s ====================\n"; } } } sub format_interface { my $s=shift; my $if=shift; my $ret=''; $ret.=format_hash($s,$if->uevent()); my $driver=$if->driver(); if($driver) { $ret.=$s."DRIVER:\n"; $ret.=format_driver("$s ",$driver); $ret.="$s++++++++++++++++++++\n"; } my @inp=$if->inputs(); if(@inp) { $ret.=$s."INPUTS:\n"; for my $inp (@inp) { $ret.=format_input("$s ",$inp); $ret.="$s --------------------\n"; } $ret.="$s++++++++++++++++++++\n"; } return $ret; } sub format_hash { my $s=shift; my $hash=shift; my $ret=''; my $length=0; for(keys(%$hash)) { $length=length($_) if($length{$_}\n"; } return $ret; } sub format_input { my $s=shift; my $inp=shift; my $ret=''; $ret.= $s."ID = ".$inp->id()."\n"; $ret.= $s."NAME = ".$inp->name()."\n"; $ret.= $s."PHYS = ".$inp->phys()."\n"; $ret.= $s."PRODUCT = ".$inp->product()."\n"; $ret.= $s."EVENTS:\n"; for my $ev ($inp->events()) { $ret.="$s NAME = ".$ev->name()."\n"; $ret.="$s MAJOR = ".$ev->major()."\n"; $ret.="$s MINOR = ".$ev->minor()."\n"; $ret.="$s DEVICE = ".$ev->device()."\n"; $ret.="$s ....................\n"; } return $ret; } sub format_driver { my $s=shift; my $drv=shift; my $ret=''; $ret.= $s."NAME = ".$drv->name()."\n"; $ret.= $s."MODUL = ".$drv->module_name()."\n"; my $modul=$drv->module(); if($modul) { $ret.= $s." Drivers = ".join(', ',$modul->drivers())."\n"; $ret.= $s." Holders = ".join(', ',$modul->holders())."\n"; $ret.= $s." RefCount = ".join(', ',$modul->count())."\n"; $ret.= $s." State = ".join(', ',$modul->state())."\n"; } return $ret; } sub __str_format { my $s=shift; my $str=shift; my $len=shift; $str.=" "x$len; return $s.substr($str,0,$len); }